ThreeB 1.1
|
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