ThreeB 1.1
multispot5_gui.cc
Go to the documentation of this file.
00001 #include <tag/printf.h>
00002 #undef make_tuple
00003 
00004 #include <tr1/tuple>
00005 #include <algorithm>
00006 #include <climits>
00007 #include <iomanip>
00008 #include <map>
00009 #include <cvd/image_io.h>
00010 #include <cvd/image_convert.h>
00011 #include <cvd/glwindow.h>
00012 #include <cvd/morphology.h>
00013 #include <cvd/connected_components.h>
00014 #include <cvd/draw.h>
00015 #include <cvd/gl_helpers.h>
00016 #include <cvd/vector_image_ref.h>
00017 #include <cvd/videodisplay.h>
00018 
00019 #include <gvars3/instances.h>
00020 #include <gvars3/GStringUtil.h>
00021 #include <gvars3/GUI_readline.h>
00022 
00023 #include "storm_imagery.h"
00024 #include "multispot5.h"
00025 #include "multispot5_place_choice.h"
00026 #include "utility.h"
00027 
00028 using namespace std;
00029 using namespace std::tr1;
00030 using namespace CVD;
00031 using namespace GVars3;
00032 using namespace TooN;
00033 
00034 double lim(double x)
00035 {
00036     return min(max(x, 0.), 1.);
00037 }
00038 
00039 
00040 Image<byte> scale(const SubImage<double>& i, double ctr, double rng)
00041 {
00042     Image<byte> s(i.size());
00043     for(int r=0; r < i.size().y; r++)
00044         for(int c=0; c < i.size().x; c++)
00045             Pixel::DefaultConversion<float, byte>::type::convert(lim((i[r][c] - ctr)/rng), s[r][c]);
00046     return s;
00047 }
00048 
00049 void draw_bbox(const BBox& bbox)
00050 {
00051     glBegin(GL_LINES);
00052     glVertex(bbox.first);
00053     glVertex2i(bbox.first.x, bbox.first.y + bbox.second.y);
00054 
00055     glVertex2i(bbox.first.x, bbox.first.y + bbox.second.y);
00056     glVertex(bbox.first+ bbox.second);
00057 
00058     glVertex(bbox.first+ bbox.second);
00059     glVertex2i(bbox.first.x + bbox.second.x, bbox.first.y);
00060 
00061     glVertex2i(bbox.first.x + bbox.second.x, bbox.first.y);
00062     glVertex(bbox.first);
00063 
00064     glEnd();
00065 }
00066 
00067 map<string, string> watch;
00068 
00069 void watch_var(void*, string comm, string d)
00070 {
00071     vector<string> vs = ChopAndUnquoteString(d);
00072 
00073     if(vs.size() != 1)
00074     {
00075         cerr << "Error: " << comm << " takes 1 argument: " << comm << " gvar\n";
00076         return;
00077     }
00078 
00079     watch[vs[0]] = GV3::get_var(vs[0]);
00080 }
00081 
00082 bool watch_update()
00083 {
00084     bool changes=0;
00085 
00086     for(map<string, string>::iterator i=watch.begin(); i != watch.end(); i++)
00087     {
00088         string s = GV3::get_var(i->first);
00089 
00090         if(s != watch[i->first])
00091         {
00092             changes=1;
00093             watch[i->first] = s;
00094         }
00095     }
00096     
00097     return changes;
00098 }
00099 
00100 void GUI_Pause(int n=0)
00101 {
00102     if(!GV3::get<int>("headless", 0, 1))
00103     {
00104         glFlush();
00105         gvar3<int> pause("pause", 1, 1);
00106 
00107         if(n != 0)
00108             *pause = n;
00109         (*pause)--;
00110         while(*pause == 0)
00111         {
00112             GUI_Widgets.process_in_crnt_thread();
00113             usleep(10000);
00114         }
00115     }
00116 }
00117 
00118 /// Graphics class which draws information to the screen using OpenGL.
00119 class GraphicsGL: public FitSpotsGraphics
00120 {
00121     private:
00122         std::auto_ptr<GLWindow>  win;
00123         GraphicsGL(const GraphicsGL&);
00124         int debug_window_zoom;
00125 
00126         ///Generate circle linesegments as pair of vertices for GL_LINES
00127         ///@param p circle centre
00128         ///@param r circle radius
00129         void glDrawCircle(const Vector<2>& p, float r)
00130         {
00131             float theta=0;
00132             for(;;)
00133             {
00134                 glVertex(p + r * makeVector(cos(theta), sin(theta)));
00135                 theta +=0.01;
00136                 if(theta > M_PI*2)
00137                     break;
00138                 glVertex(p + r * makeVector(cos(theta), sin(theta)));
00139             }
00140             glVertex(p + r * makeVector(1, 0));
00141         }
00142         
00143         ///Set up a GL window so that glDrawPixels and glVertex line up
00144         ///and also so that glDrawPixels is zoomed.
00145         ///@param size Window size
00146         ///@param scale Zoom level
00147         void set_GL_zoom_size(ImageRef size, double scale)
00148         {
00149             double right = size.x;
00150             double bottom = size.y;
00151             //double my_scale = scale;
00152 
00153 
00154             glMatrixMode(GL_MODELVIEW);
00155             glLoadIdentity();
00156 
00157 
00158             glMatrixMode(GL_PROJECTION);
00159 
00160             glLoadIdentity();
00161             glOrtho(0-.5, right-.5, bottom-.5, -.5, -1 , 1);    // If the origin is the top left 
00162 
00163             glRasterPos2f(-.5, -.5);
00164 
00165             // video is now the same way as upside down to graphics!
00166             glPixelZoom(scale, -scale);
00167         }
00168 
00169 
00170     public:
00171         
00172         GraphicsGL()
00173         {
00174             debug_window_zoom = GV3::get<int>("debug.zoom", 3, 1);
00175         }
00176             
00177         virtual void draw_pixels(const vector<ImageRef>& pix, float r, float g, float b, float a)
00178         {
00179             glColor4f(r, g, b, a);
00180             glPointSize(1.5);
00181             glBegin(GL_POINTS);
00182             glVertex(pix);
00183             glEnd();
00184         }
00185 
00186         virtual void draw_bbox(const BBox& bbox)
00187         {
00188 			::draw_bbox(bbox);
00189         }
00190 
00191     
00192         virtual void draw_krap(const vector<Vector<4> >& spots, const Image<byte>& im, const BBox& box, int N, Vector<4> s)
00193         {
00194 
00195             glDrawPixels(im);
00196             glColor3f(1, 0, 0);
00197             draw_bbox(box);
00198 
00199             glLineWidth(0.3);
00200             glBegin(GL_LINES);
00201             for(unsigned int i=0; i < spots.size(); i++)
00202             {
00203                 glColor4f(0, 1, 0, .3);
00204 
00205                 if((int)i == N && s[0] != 1e99) 
00206                     glDrawCircle(s.slice<2, 2>(), s[1]);
00207                 else
00208                     glDrawCircle(spots[i].slice<2, 2>(), spots[i][1]);
00209             }
00210             glEnd();
00211 
00212             glLineWidth(1.0);
00213             glBegin(GL_LINES);
00214             for(unsigned int i=0; i < spots.size(); i++)
00215             {
00216                 glColor3f(1, 0, 0);
00217                 if((int) i == N)
00218                     glColor3f(1, 1, 0);
00219 
00220                 if((int)i == N && s[0] != 1e99) 
00221                     glDrawCross(s.slice<2, 2>(), 1);
00222                 else
00223                     glDrawCross(spots[i].slice<2, 2>(), 1);
00224             }
00225             glEnd();
00226 
00227             glFlush();
00228         }
00229 
00230         virtual void glDrawCross(const Vector<2>& p, int size)
00231         {
00232             glVertex(p + makeVector(0,  size));
00233             glVertex(p + makeVector(0, -size));
00234             glVertex(p + makeVector( size, 0));
00235             glVertex(p + makeVector(-size, 0));
00236         }
00237 
00238 
00239         virtual void swap()
00240         {
00241             win->swap_buffers();
00242         }
00243 
00244 
00245         virtual void init(ImageRef log_ratios_size)
00246         {
00247             win = auto_ptr<GLWindow>(new GLWindow(log_ratios_size*debug_window_zoom));
00248             set_GL_zoom_size(log_ratios_size, debug_window_zoom);
00249             glEnable(GL_BLEND);
00250             glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00251             glEnable(GL_LINE_SMOOTH);
00252         }
00253 
00254         virtual ~GraphicsGL()
00255         {
00256         }
00257 };
00258 
00259 
00260 vector<vector<ImageRef> > get_regions(const SubImage<double>& log_ratios)
00261 {
00262     gvar3<double> radius("radius", 0, 1);
00263 
00264     //Set the liklihood ratio threshold/spot density prior
00265     //same thing.
00266     double threshold = GV3::get<double>("threshold", 0, -1);
00267     int edge = GV3::get<int>("edge", 0, -1);
00268 
00269 
00270     //Threshold image
00271     Image<byte> thresholded(log_ratios.size(), 0);
00272     for(int r=0; r < thresholded.size().y; r++)
00273         for(int c=0; c < min(thresholded.size().x, edge); c++)
00274             thresholded[r][c] = 255 * (log_ratios[r][c] > threshold);
00275     
00276     //Dilate
00277     Image<byte> dilated = morphology(thresholded, getDisc(*radius), Morphology::BinaryDilate<byte>());
00278 
00279     transform(dilated.begin(), dilated.end(), dilated.begin(), bind1st(multiplies<int>(), 255));
00280     
00281     //Connected components of dilated image
00282     vector<ImageRef> fg;
00283     for(int r=0; r < thresholded.size().y; r++)
00284         for(int c=0; c < min(thresholded.size().x, edge); c++)
00285             if(dilated[r][c])
00286                 fg.push_back(ImageRef(c, r));
00287 
00288     vector<vector<ImageRef> > regions;
00289     connected_components(fg, regions);
00290 
00291     return regions;
00292 }
00293 
00294 
00295 void mmain(int argc, char** argv)
00296 {
00297     GUI.RegisterCommand("watch", watch_var);
00298     GUI.LoadFile("multispot5.cfg");
00299     int lastarg = GUI.parseArguments(argc, argv);
00300     if(lastarg >= argc)
00301     {   
00302         cerr << "Specify the images to load\n";
00303         exit(1);
00304     }
00305 
00306     
00307     
00308     //Load the log_ratios image.
00309     //We will use this as a starting point for searching for spots.
00310     Image<double> log_ratios;
00311     try
00312     {
00313         log_ratios = img_load(GV3::get<string>("log_ratios", "", -1));
00314     }
00315     catch(Exceptions::All e)
00316     {
00317         cerr << "Error loading " << GV3::get<string>("log_ratios", "") << ": " << e.what << endl;
00318         exit(1);
00319     }
00320 
00321     Vector<2> log_ratios_zoom = GV3::get<Vector<2> >("log_ratios_zoom", "", -1);
00322 
00323     //Load the raw data, and then load the spot parameters.
00324     vector<string> files(argv + lastarg, argv + argc);
00325     vector<Image<float> > ims = load_and_normalize_images(files);
00326 
00327     //How far away from eash spot to look:
00328     //double spot_sigmas = GV3::get<double>("sigmas", 0., -1);
00329 
00330     
00331     
00332     gvar3<int> cluster_to_show("cluster_to_show", 0, -1);
00333     gvar3<int> use_largest("use_largest", 0, 1);
00334 
00335     vector<vector<ImageRef> > regions;
00336 
00337     GLWindow win(log_ratios.size());
00338     glEnable(GL_BLEND);
00339     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00340     glEnable(GL_LINE_SMOOTH);
00341 
00342     readline_in_current_thread line("> ");
00343 
00344     gvar3<bool> start_processing("process", 0, 1);
00345     gvar3<int> show_thresholded("show_thresholded", 0, 1);
00346 
00347     
00348     Image<Rgb<byte> > reg(log_ratios.size(), Rgb<byte>(0,0,0));
00349     
00350     bool first = true;
00351     BBox cbox = make_pair(ImageRef_zero, ImageRef_zero);
00352     for(;;)
00353     {
00354         double centre = GV3::get<double>("centre", 0, -1);
00355         double range = GV3::get<double>("range", 0, -1);
00356 
00357         line.poll();
00358         win.make_current();
00359         GUI_Widgets.process_in_crnt_thread();
00360         
00361         if(watch_update() || first)
00362         {
00363             first = 0;
00364 
00365             regions = get_regions(log_ratios);
00366             
00367             //Colourize regions
00368             reg.fill(Rgb<byte>(0,0,0));
00369             for(unsigned int i=0; i < regions.size(); i++)
00370             {
00371                 Rgb<byte> c;
00372                 do
00373                 {
00374                     c.red = rand()%255;
00375                     c.green = rand()%255;
00376                     c.blue = rand()%255;
00377                 }
00378                 while(min(c.red, min(c.green, c.blue)) < 128 && min(abs(c.red - c.green), min(abs(c.red - c.blue), abs(c.green - c.blue))) < 64);
00379 
00380                 for(unsigned int j=0; j < regions[i].size(); j++)
00381                     reg[regions[i][j]] = c;
00382             }
00383 
00384                     
00385         }
00386         
00387         
00388         if(*use_largest && !regions.empty())
00389         {
00390             *cluster_to_show=0;
00391             for(unsigned int i=1; i < regions.size(); i++)
00392                 if(regions[i].size() > regions[*cluster_to_show].size())
00393                     *cluster_to_show = i;
00394                     
00395         }
00396         else
00397             *cluster_to_show = max(min(*cluster_to_show, (int)regions.size() - 1), 0);
00398 
00399         if(!regions.empty())
00400             cbox = boundingbox(regions[*cluster_to_show]);
00401 
00402         if(!regions.empty() && *start_processing)
00403         {
00404             GraphicsGL graphics;
00405 
00406             place_and_fit_spots(ims, regions[*cluster_to_show], log_ratios, GV3::get<string>("save_spots"), graphics);
00407             *start_processing=0;
00408         }
00409 
00410         if(*show_thresholded)
00411             glDrawPixels(reg);
00412         else
00413             glDrawPixels(scale(log_ratios, centre, range));
00414 
00415         if(cbox.second != ImageRef_zero)
00416             draw_bbox(cbox);
00417 
00418         if(win.has_events())
00419         {
00420             vector<GLWindow::Event> e;
00421             win.get_events(e);
00422 
00423             for(unsigned int i=0; i < e.size(); i++)
00424             {
00425                 if(e[i].type == GLWindow::Event::RESIZE)
00426                 {
00427                     ImageRef newsize = e[i].size;
00428                     ImageRef imsize = log_ratios.size();
00429                     ImageRef size=imsize;
00430 
00431                     float old_r = (float)imsize.x / imsize.y;
00432                     float new_r = (float)newsize.x / newsize.y;
00433 
00434 
00435                     glViewport(0, 0, newsize.x, newsize.y);
00436                     glMatrixMode(GL_PROJECTION);
00437                     glLoadIdentity();
00438                     double zoom;
00439 
00440                     if(new_r > old_r) //Then use the y axis
00441                         zoom = newsize.y / (float)size.y; 
00442                     else
00443                         zoom = newsize.x / (float)size.x;
00444 
00445                     glOrtho(-.5/zoom, (newsize.x-1.5)/zoom, (newsize.y-1.5)/zoom, -.5/zoom, -1 , 1);
00446 
00447                     glPixelZoom(zoom,-zoom);
00448                     glRasterPos2f(0, 0);
00449                 }
00450             }
00451         }
00452         win.swap_buffers();
00453 
00454         usleep(100000);
00455     }
00456 }
00457 
00458     
00459 int main(int argc, char** argv)
00460 {
00461     try{
00462         mmain(argc, argv);
00463     }
00464     catch(Exceptions::All e)
00465     {
00466         cerr << "Fatal error: " << e.what << endl;
00467     }
00468 }
00469