1 // This is oxl/xcv/xcv.cxx
2
3 //:
4 // \file
5 // \author K.Y.McGaul
6 // \brief Main function for xcv.
7 //
8 // This contains the main function for xcv, a program designed to demonstrate
9 // the functionality of vxl.
10 //
11 // \verbatim
12 // Modifications:
13 // K.Y.McGaul 27-JAN-2000 Initial version.
14 // Feb.2002 - Peter Vanroose - brief doxygen comment placed on single line
15 // \endverbatim
16
17 #include <iostream>
18 #include <vector>
19 #ifdef _MSC_VER
20 # include "vcl_msvc_warnings.h"
21 #endif
22 #include <cassert>
23
24 #include "vul/vul_arg.h"
25
26 #include "vil1/vil1_image.h"
27 #include "vil1/vil1_load.h"
28
29 #include "vgui/vgui.h"
30 #include "vgui/vgui_window.h"
31 #include "vgui/vgui_adaptor.h"
32 #include "vgui/vgui_tableau.h"
33 #include "vgui/vgui_menu.h"
34 #include "vgui/vgui_dialog.h"
35 #include "vgui/vgui_macro.h"
36 #include "vgui/vgui_find.h"
37 #include "vgui/vgui_easy2D_tableau.h"
38 #include "vgui/vgui_rubberband_tableau.h"
39 #include "vgui/vgui_viewer2D_tableau.h"
40 #include "vgui/vgui_grid_tableau.h"
41 #include "vgui/vgui_shell_tableau.h"
42
43 #include "xcv_file.h"
44 #include "xcv_display.h"
45 #include "xcv_geometry.h"
46 #include "xcv_processing.h"
47 #include "xcv_segmentation.h"
48 #include "xcv_multiview.h"
49 #include "xcv_image_tableau.h"
50 #include "xcv_picker_tableau.h"
51
52 #define MENUBAR_HEIGHT 70
53
54 //-----------------------------------------------------------------------------
55 class xcv_tableau : public vgui_grid_tableau
56 {
57 public:
58 //xcv_tableau(int nb_images) : vgui_grid_tableau(nb_images, 1) {}
xcv_tableau(int rows,int cols)59 xcv_tableau(int rows, int cols) : vgui_grid_tableau(cols, rows) {}
~xcv_tableau()60 ~xcv_tableau() {}
handle(const vgui_event & e)61 bool handle(const vgui_event& e) { return vgui_grid_tableau::handle(e); }
62 };
63
64 xcv_tableau* xcv_tab;
65
66 //-----------------------------------------------------------------------------
67 //: Get file last used for saving data.
68 //-----------------------------------------------------------------------------
get_savefile()69 std::string* get_savefile()
70 {
71 static std::string savefile = "";
72 return &savefile;
73 }
74
75 //-----------------------------------------------------------------------------
76 //: Get file last used for loading data.
77 //-----------------------------------------------------------------------------
get_loadfile()78 std::string* get_loadfile()
79 {
80 static std::string loadfile = "";
81 return &loadfile;
82 }
83
84 //-----------------------------------------------------------------------------
85 //: Displays given message on the status bar.
86 //-----------------------------------------------------------------------------
post_to_status_bar(const char * msg)87 void post_to_status_bar(const char* msg)
88 {
89 vgui::out << msg << std::endl;
90 }
91
get_top(unsigned col,unsigned row)92 vgui_tableau_sptr get_top(unsigned col,unsigned row)
93 {
94 return xcv_tab->get_tableau_at(col,row);
95 }
96
97 //-----------------------------------------------------------------------------
98 //: Gets the list of all image tableaux in xcv.
99 //-----------------------------------------------------------------------------
get_image_list()100 std::vector<xcv_image_tableau_sptr> get_image_list()
101 {
102 std::vector<xcv_image_tableau_sptr> img_tabs;
103 std::vector<vgui_tableau_sptr> all_tabs = xcv_tab->get_tableau_list();
104 for (unsigned i=0; i<all_tabs.size(); i++)
105 {
106 xcv_image_tableau_sptr img
107 = (xcv_image_tableau*)vgui_find_below_by_type_name(all_tabs[i],
108 std::string("xcv_image_tableau")).operator->();
109 img_tabs.push_back(img);
110 }
111 return img_tabs;
112 }
113
114 //-----------------------------------------------------------------------------
115 //: Gets the list of all easy2D tableaux in xcv.
116 //-----------------------------------------------------------------------------
get_easy2D_list()117 std::vector<vgui_easy2D_tableau_sptr> get_easy2D_list()
118 {
119 std::vector<vgui_easy2D_tableau_sptr> easy_tabs;
120 std::vector<vgui_tableau_sptr> all_tabs = xcv_tab->get_tableau_list();
121 for (unsigned i=0; i<all_tabs.size(); i++)
122 {
123 vgui_easy2D_tableau_sptr easy =
124 (vgui_easy2D_tableau*)vgui_find_below_by_type_name(
125 all_tabs[i], std::string("vgui_easy2D_tableau")).operator->();
126 easy_tabs.push_back(easy);
127 }
128 return easy_tabs;
129 }
130
131 //-----------------------------------------------------------------------------
132 //: Gets the last selected row and column position.
133 //-----------------------------------------------------------------------------
get_current(unsigned * col,unsigned * row)134 void get_current(unsigned* col, unsigned* row)
135 {
136 xcv_tab->get_last_selected_position(col, row);
137 }
138
139 //-----------------------------------------------------------------------------
140 //: Returns true if there are exactly two selected views.
141 //-----------------------------------------------------------------------------
get_twoviews(std::vector<int> * col_pos,std::vector<int> * row_pos)142 bool get_twoviews(std::vector<int>* col_pos, std::vector<int>* row_pos)
143 {
144 std::vector<int> cols, rows, times;
145 int nb_views = xcv_tab->get_selected_positions(&cols, &rows, ×);
146 // if not selected, pick top left pair.
147 if (nb_views != 2) {
148 for (unsigned int i = 0; i < xcv_tab->rows(); ++i)
149 for (unsigned int j = 0; j < xcv_tab->cols(); ++j)
150 xcv_tab->set_selected(i,j, false);
151 cols.clear();
152 rows.clear();
153 times.clear();
154 xcv_tab->set_selected(0,0, true);
155 xcv_tab->set_selected(0,1, true);
156 nb_views = xcv_tab->get_selected_positions(&cols, &rows, ×);
157 }
158
159 // If still not selected, may be a funny layout or summat.
160 if (nb_views != 2)
161 {
162 vgui_dialog two_dl("Error");
163 two_dl.message("");
164 two_dl.message("You must select exactly two views.");
165 two_dl.message("");
166 two_dl.ask();
167 vgui_macro_warning
168 << "You must select exactly two views, not the current "
169 << nb_views << std::endl;
170 return false;
171 }
172
173 // Sort the views into time order:
174 if (times[0] < times[1])
175 {
176 col_pos->push_back(cols[0]); col_pos->push_back(cols[1]);
177 row_pos->push_back(rows[0]); row_pos->push_back(rows[1]);
178 }
179 else
180 {
181 col_pos->push_back(cols[1]); col_pos->push_back(cols[0]);
182 row_pos->push_back(rows[1]); row_pos->push_back(rows[0]);
183 }
184 return true;
185 }
186
187 //-----------------------------------------------------------------------------
188 //: Returns true if there are exactly three selected views.
189 //-----------------------------------------------------------------------------
get_threeviews(std::vector<int> * col_pos,std::vector<int> * row_pos)190 bool get_threeviews(std::vector<int>* col_pos, std::vector<int>* row_pos)
191 {
192 std::vector<int> cols, rows, times;
193 int nb_views = xcv_tab->get_selected_positions(&cols, &rows, ×);
194 if (nb_views != 3)
195 {
196 vgui_dialog dl("Error");
197 dl.message("");
198 dl.message("You need to select exactly three views.");
199 dl.message("");
200 dl.ask();
201 vgui_macro_warning
202 << "You need to selected exactly three views. Number selected = "
203 << nb_views << std::endl;
204 return false;
205 }
206 // Sort the view into time order:
207 int first, second, third;
208 if (times[0] <= times[1] && times[1] <= times[2])
209 { first = 0; second = 1; third = 2; }
210 else if (times[0] <= times[2] && times[2] <= times[1])
211 { first = 0; second = 2; third = 1; }
212 else if (times[1] <= times[0] && times[0] <= times[2])
213 { first = 1; second = 0; third = 2; }
214 else if (times[1] <= times[2] && times[2] <= times[0])
215 { first = 1; second = 2; third = 0; }
216 else if (times[2] <= times[0] && times[0] <= times[1])
217 { first = 2; second = 0; third = 1; }
218 else
219 { first = 2; second = 1; third = 0; }
220
221 col_pos->push_back(cols[first]); row_pos->push_back(rows[first]);
222 col_pos->push_back(cols[second]); row_pos->push_back(rows[second]);
223 col_pos->push_back(cols[third]); row_pos->push_back(rows[third]);
224 return true;
225 }
226
227 //-----------------------------------------------------------------------------
228 //: Return the underlying rubberbander from the tableau at the given position.
229 // This function returns NULL if it fails.
230 //-----------------------------------------------------------------------------
get_rubberbander_at(unsigned col,unsigned row)231 vgui_rubberband_tableau_sptr get_rubberbander_at(unsigned col, unsigned row)
232 {
233 vgui_tableau_sptr top_tab = xcv_tab->get_tableau_at(col, row);
234 if (top_tab)
235 {
236 std::string type_name("vgui_rubberband_tableau");
237 vgui_rubberband_tableau_sptr tab;
238 tab.vertical_cast(vgui_find_below_by_type_name(top_tab, type_name));
239 if (tab)
240 return tab;
241 }
242 vgui_macro_warning << "Unable to get rubberbander tableau at (" << col
243 <<", "<<row<<")\n";
244 return vgui_rubberband_tableau_sptr();
245 }
246
247 //-----------------------------------------------------------------------------
248 //: Return the underlying easy2D from the tableau at the given position.
249 // This function returns NULL if it fails.
250 //-----------------------------------------------------------------------------
get_easy2D_at(unsigned col,unsigned row)251 vgui_easy2D_tableau_sptr get_easy2D_at(unsigned col, unsigned row)
252 {
253 vgui_tableau_sptr top_tab = xcv_tab->get_tableau_at(col, row);
254 if (top_tab)
255 {
256 std::string type_name("vgui_easy2D_tableau");
257 vgui_easy2D_tableau_sptr tab;
258 tab.vertical_cast(vgui_find_below_by_type_name(top_tab, type_name));
259 if (tab)
260 return tab;
261 }
262 vgui_macro_warning << "Unable to get easy2D at ("<< col<< ", "<< row << ")\n";
263 return vgui_easy2D_tableau_sptr();
264 }
265
266 //-----------------------------------------------------------------------------
267 //: Return the underlying easy2D from the tableau at the given position.
268 // This function returns NULL if it fails.
269 //-----------------------------------------------------------------------------
get_composite_at(unsigned col,unsigned row)270 vgui_composite_tableau_sptr get_composite_at(unsigned col, unsigned row)
271 {
272 vgui_tableau_sptr top_tab = xcv_tab->get_tableau_at(col, row);
273 if (top_tab)
274 {
275 std::string type_name("vgui_composite_tableau");
276 vgui_composite_tableau_sptr tab;
277 tab.vertical_cast(vgui_find_below_by_type_name(top_tab, type_name));
278 if (tab)
279 return tab;
280 }
281 vgui_macro_warning << "Unable to get composite at ("<<col<<", "<<row<< ")\n";
282 return vgui_composite_tableau_sptr();
283 }
284
285 //-----------------------------------------------------------------------------
286 //: Return the viewer2D at the given position.
287 // This function returns NULL if it fails.
288 //-----------------------------------------------------------------------------
get_viewer2D_at(unsigned col,unsigned row)289 vgui_viewer2D_tableau_sptr get_viewer2D_at(unsigned col, unsigned row)
290 {
291 vgui_tableau_sptr top_tab = xcv_tab->get_tableau_at(col, row);
292 if (top_tab)
293 {
294 vgui_viewer2D_tableau_sptr view;
295 view.vertical_cast(vgui_find_below_by_type_name(top_tab,
296 std::string("vgui_viewer2D_tableau")));
297 if (view)
298 return view;
299 }
300 vgui_macro_warning << "Unable to get viewer2D tableau at (" << col
301 << ", " << row << ")\n";
302 return vgui_viewer2D_tableau_sptr();
303 }
304
305 //-----------------------------------------------------------------------------
306 //: Return currently active easy2d
307 //-----------------------------------------------------------------------------
get_current_easy2D()308 vgui_easy2D_tableau_sptr get_current_easy2D()
309 {
310 unsigned i,j;
311 get_current(&i,&j);
312 return get_easy2D_at(i,j);
313 }
314
315 //-----------------------------------------------------------------------------
316 //: Gets the image tableau at the given position.
317 // This function returns a new image tableau if it fails.
318 //-----------------------------------------------------------------------------
get_image_tableau_at(unsigned col,unsigned row)319 xcv_image_tableau_sptr get_image_tableau_at(unsigned col, unsigned row)
320 {
321 vgui_easy2D_tableau_sptr tab = get_easy2D_at(col, row);
322 if (tab)
323 {
324 xcv_image_tableau_sptr tt;
325 tt.vertical_cast(vgui_find_below_by_type_name(tab,
326 std::string("xcv_image_tableau")));
327 if (tt)
328 return tt;
329 }
330 vgui_macro_warning << "Unable to get xcv_image_tableau at (" << col << ", "
331 << row << ")\n";
332 return xcv_image_tableau_sptr();
333 }
334
335 //-----------------------------------------------------------------------------
336 //: Gets the picker tableau at the given position.
337 // Returns a new picker_tableau if it fails.
338 //-----------------------------------------------------------------------------
get_picker_tableau_at(unsigned col,unsigned row)339 xcv_picker_tableau_sptr get_picker_tableau_at(unsigned col, unsigned row)
340 {
341 vgui_tableau_sptr top_tab = xcv_tab->get_tableau_at(col, row);
342 if (top_tab)
343 {
344 xcv_picker_tableau_sptr tt;
345 tt.vertical_cast(vgui_find_below_by_type_name(top_tab,
346 std::string("xcv_picker_tableau")));
347 if (tt)
348 return tt;
349 }
350 vgui_macro_warning << "Unable to get xcv_picker_tableau at (" << col << ", "
351 << row << ")\n";
352 return xcv_picker_tableau_sptr();
353 }
354
355 //-----------------------------------------------------------------------------
356 //: Gets the underlying image from the tableau at the given position and returns it in the given image pointer.
357 // Returns true if the image is OK, otherwise returns false.
358 //-----------------------------------------------------------------------------
get_image_at(vil1_image * img,unsigned col,unsigned row)359 bool get_image_at(vil1_image* img, unsigned col, unsigned row)
360 {
361 xcv_image_tableau_sptr img_tab = get_image_tableau_at(col, row);
362 if (img_tab)
363 {
364 *img = img_tab->get_image();
365 return true;
366 }
367 vgui_macro_warning << "Unable to get image at ("<< col <<", "<< row << ")\n";
368 return false;
369 }
370
371 //-----------------------------------------------------------------------------
372 //: Given an image, returns a tableau suitable to display in xcv.
373 //-----------------------------------------------------------------------------
create_tableau(vil1_image img)374 vgui_tableau_sptr create_tableau(vil1_image img)
375 {
376 xcv_image_tableau_new image (img);
377 vgui_easy2D_tableau_new easy (image);
378 vgui_rubberband_tableau_new rubber(new vgui_rubberband_easy2D_client(easy));
379 vgui_composite_tableau_new comp(easy,rubber);
380 xcv_picker_tableau_new picker(comp);
381 vgui_viewer2D_tableau_new view (picker);
382 return view;
383 }
384
385 //-----------------------------------------------------------------------------
386 //: Displays the given image on XCV at the given position.
387 //-----------------------------------------------------------------------------
add_image_at(std::string image_filename,unsigned col,unsigned row)388 void add_image_at(std::string image_filename, unsigned col, unsigned row)
389 {
390 vil1_image img = vil1_load(image_filename.c_str());
391 vgui_tableau_sptr tab = create_tableau(img);
392 xcv_tab->add_at(tab, col, row);
393 }
394
395
396 //-----------------------------------------------------------------------------
397 //: Add image to next available slot
398 //-----------------------------------------------------------------------------
add_image(vil1_image & img)399 void add_image(vil1_image& img)
400 {
401 vgui_tableau_sptr tab = create_tableau(img);
402 xcv_tab->add_next(tab);
403 }
404
405 //-----------------------------------------------------------------------------
406 //: Removes the image at the given position from the display.
407 //-----------------------------------------------------------------------------
remove_image_at(unsigned col,unsigned row)408 void remove_image_at(unsigned col, unsigned row)
409 {
410 xcv_tab->remove_at(col, row);
411 }
412
413 //-----------------------------------------------------------------------------
414 //: Create the menubar.
415 //-----------------------------------------------------------------------------
416 vgui_menu xcv_menubar;
417
create_menubar()418 vgui_menu create_menubar()
419 {
420 xcv_menubar.add("File", xcv_file::create_file_menu());
421 xcv_menubar.add("Display", xcv_display::create_display_menu());
422 xcv_menubar.add("Image-processing", xcv_processing::create_processing_menu());
423 xcv_menubar.add("Geometry", xcv_geometry::create_geometry_menu());
424 xcv_menubar.add("Segmentation", xcv_segmentation::create_segmentation_menu());
425 xcv_menubar.add("Multiview", xcv_multiview::create_multiview_menu());
426
427 return xcv_menubar;
428 }
429
430 //-----------------------------------------------------------------------------
431 //: Choosing a window size
432 // This function chooses a window size by adding up the total image size
433 // along each row (column) and choosing the row (column) sum which is
434 // greatest as the window width (height).
435 //-----------------------------------------------------------------------------
xcv_window_size_traditional(int rows,int cols,std::vector<vil1_image> const & images,unsigned * window_w,unsigned * window_h,double * viewer_scale)436 void xcv_window_size_traditional(int rows, int cols,
437 std::vector<vil1_image> const &images,
438 unsigned *window_w, unsigned *window_h,
439 double *viewer_scale)
440 {
441 assert(rows > 0 && cols > 0);
442
443 assert(window_w && window_h && viewer_scale);
444 *window_w = 0;
445 *window_h = 0;
446 *viewer_scale = 1;
447
448 // set width of window
449 for (int i=0; i<rows; ++i)
450 {
451 unsigned int winnie = 0;
452 for (int j=0; j<cols; ++j)
453 {
454 unsigned int d = i*cols + j;
455 if (d < images.size())
456 winnie += images[d].width();
457 }
458 if (winnie > *window_w)
459 *window_w = winnie;
460 }
461
462 // set height of window
463 for (int j=0; j<cols; ++j)
464 {
465 unsigned int winnie = 0;
466 for (int i=0; i<rows; ++i)
467 {
468 unsigned int d = i*cols + j;
469 if (d < images.size())
470 winnie += images[d].height();
471 }
472 if (winnie > *window_h)
473 *window_h = winnie;
474 }
475 // Add a bit to the height for the menu and status bars:
476 *window_h += MENUBAR_HEIGHT;
477 }
478
479 //-----------------------------------------------------------------------------
480 //: This tries to resize the window to fill some proportion of the screen.
481 // Useful for very small or very large images.
482 //-----------------------------------------------------------------------------
xcv_window_size_adaptive(int rows,int cols,std::vector<vil1_image> const & images,unsigned * window_w,unsigned * window_h,double * viewer_scale)483 void xcv_window_size_adaptive(int rows, int cols,
484 std::vector<vil1_image> const &images,
485 unsigned *window_w, unsigned *window_h,
486 double *viewer_scale)
487 {
488 xcv_window_size_traditional(rows, cols, images, window_w, window_h,
489 viewer_scale);
490
491 // resize the window to occupy roughly 64% of a 1024x1280 display by area.
492 double mw = 0.80 * 1280;
493 double mh = 0.80 * 1024;
494
495 double dw = *window_w;
496 double dh = *window_h;
497 double factor = 1.1;
498 // first make it nice and big
499 while (factor*dw < mw && factor*dh < mh) {
500 dw *= factor;
501 dh *= factor;
502 *viewer_scale *= factor;
503 }
504 // then shrink it to fit onto the screen
505 while (factor*dw > mw || factor*dh > mh) {
506 dw /= factor;
507 dh /= factor;
508 *viewer_scale /= factor;
509 }
510 *window_w = unsigned(dw);
511 *window_h = unsigned(dh);
512 }
513
514 //-----------------------------------------------------------------------------
515 // main.
516 //-----------------------------------------------------------------------------
main(int argc,char ** argv)517 int main(int argc, char** argv)
518 {
519 // Select the toolkit: command line or environment variable
520 // can override, but the default is 'gtk' or 'mfc'.
521 if (! vgui::select(argc, argv))
522 {
523 if (vgui::exists("gtk"))
524 vgui::select("gtk");
525 else if (vgui::exists("mfc"))
526 vgui::select("mfc");
527 else if (vgui::exists("qt"))
528 vgui::select("qt");
529 else
530 {
531 // ??
532 }
533 }
534 // Initialize the chosen toolkit.
535 vgui::init(argc, argv);
536
537 // Let the vbl arg parser loose on those command line
538 // arguments not used by vgui::init();
539 vul_arg<bool> a_adaptive("-adaptive", "resize window adaptively");
540 vul_arg<int> a_rows("-rows", "desired number of rows in array of images", 0);
541 vul_arg<int> a_cols("-cols", "desired number of col(umn)s in array of images", 0);
542 vul_arg_parse(argc, argv);
543
544 int rows, cols;
545 if (a_rows() && a_cols())
546 {
547 rows = a_rows();
548 cols = a_cols();
549 }
550 else
551 {
552 rows = 1;
553 if (argc-1 > 0)
554 cols = argc-1;
555 else
556 cols = 1;
557 }
558 xcv_tab = new xcv_tableau(rows, cols);
559
560 unsigned window_width = 0;
561 unsigned window_height = 0;
562
563 {
564 std::vector<vgui_tableau_sptr> viewers;
565 std::vector<vil1_image> images;
566
567 xcv_tab->set_grid_size_changeable(false);
568 for (int argcount=1; argcount<argc && std::strcmp(argv[argcount], "-d");
569 ++argcount)
570 {
571 vil1_image img = vil1_load(argv[argcount]);
572 vgui_tableau_sptr tab = create_tableau(img);
573 xcv_tab->add_next(tab);
574
575 images.push_back(img);
576 viewers.push_back(tab);
577 }
578 xcv_tab->set_grid_size_changeable(true);
579
580 double viewer_scale;
581 if (a_adaptive())
582 xcv_window_size_adaptive(rows, cols, images, &window_width,
583 &window_height, &viewer_scale);
584 else
585 xcv_window_size_traditional(rows, cols, images, &window_width,
586 &window_height, &viewer_scale);
587
588 for (unsigned int i=0; i<viewers.size(); ++i)
589 {
590 vgui_viewer2D_tableau_sptr v; v.vertical_cast(viewers[i]);
591 v->token.scaleX *= (float)viewer_scale;
592 v->token.scaleY *= (float)viewer_scale;
593 }
594 }
595
596
597 // safety net, in case something silly happened.
598 if (window_width > 1024)
599 window_width = 1024;
600 if (window_height > 1024)
601 window_height = 1024;
602
603 if (window_width <= 0)
604 window_width = 512;
605 if (window_height <= MENUBAR_HEIGHT)
606 window_height = 512;
607
608 std::cerr << "window_width = " << window_width << std::endl
609 << "window_height = " << window_height << std::endl;
610
611 // Create a window, add the tableau and show it on screen:
612 vgui_window *win = vgui::produce_window(window_width, window_height,
613 create_menubar(),
614 "xcv"); // title
615 win->get_adaptor()->set_tableau(vgui_shell_tableau_new(xcv_tab));
616 win->set_statusbar(true);
617 win->enable_vscrollbar(false);
618 win->enable_hscrollbar(false);
619 win->show();
620 return vgui::run();
621 }
622