Fawkes API Fawkes Development Version
|
00001 00002 /*************************************************************************** 00003 * viewer.cpp - Generic viewer tool 00004 * 00005 * Created: Tue Nov 06 15:02:51 2007 00006 * Copyright 2005-2007 Tim Niemueller [www.niemueller.de] 00007 * 00008 ****************************************************************************/ 00009 00010 /* This program is free software; you can redistribute it and/or modify 00011 * it under the terms of the GNU General Public License as published by 00012 * the Free Software Foundation; either version 2 of the License, or 00013 * (at your option) any later version. 00014 * 00015 * This program is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 * GNU Library General Public License for more details. 00019 * 00020 * Read the full text in the LICENSE.GPL file in the doc directory. 00021 */ 00022 00023 00024 #include <core/exceptions/software.h> 00025 #include <utils/system/argparser.h> 00026 00027 #include <cams/factory.h> 00028 #ifdef HAVE_SHMEM_CAM 00029 #include <cams/shmem.h> 00030 #endif 00031 #ifdef HAVE_NETWORK_CAM 00032 #include <cams/net.h> 00033 #endif 00034 #ifdef HAVE_FILELOADER_CAM 00035 #include <cams/fileloader.h> 00036 #endif 00037 00038 #include <fvwidgets/image_display.h> 00039 #ifdef HAVE_RECTINFO 00040 #include <fvutils/rectification/rectfile.h> 00041 #include <fvutils/rectification/rectinfo_block.h> 00042 #include <filters/rectify.h> 00043 #endif 00044 00045 #include <cstring> 00046 #include <cstdio> 00047 #include <stdint.h> 00048 00049 #include <SDL.h> 00050 #ifdef HAVE_GTKMM 00051 #include <gtkmm.h> 00052 #endif 00053 00054 #include <fvutils/color/conversions.h> 00055 00056 using namespace fawkes; 00057 using namespace firevision; 00058 00059 void 00060 print_usage(const char *program_name) 00061 { 00062 printf("Usage: %s [-c] [-s shmem_id] [-n host[:port]/image_id] [-f file] [-o shmem_id] [-v] \\\n" 00063 " [-d delay] [cam arg string]\n\n" 00064 " -c Start in continuous update mode\n" 00065 " -s shmem_id Open shared memory image with given ID\n" 00066 " -n net_string Open network camera, the camera string is of the form\n" 00067 " host[:port]/image_id. You have to specify at least the host\n" 00068 " and the image_id, the port is optional and defaults to 5000\n" 00069 " -j Receive JPEG images, only valid with -n\n" 00070 " -d delay Delay in ms before a new image is capture.\n" 00071 " -f file Open file loader camera with given file (image, colormap)\n" 00072 " -o shmem_id Output the image to a shared memory segment with given ID\n" 00073 " -v Verbose output on console\n" 00074 " cam arg string Can be an arbitrary camera argument string that is understood\n" 00075 " by CameraFactory and the desired camera.\n", 00076 program_name); 00077 } 00078 00079 void 00080 print_keys() 00081 { 00082 printf("Keys:\n" 00083 " c Toggle continuous mode (automatic image updating as fast as possible)\n" 00084 " r rectify image, will query for rectification info file and possibly\n" 00085 " for camera if there is more than one block.\n" 00086 " + Increase delay by 5 ms\n" 00087 " - Decrease delay by 5 ms\n" 00088 " Shift-R rectify image, use already loaded lut info file, do not query for\n" 00089 " new file\n" 00090 " Space Refresh image\n" 00091 " q/Esc Quit viewer\n"); 00092 } 00093 00094 00095 /** Process all outstanding Gtk events. */ 00096 void 00097 process_gtk_events() 00098 { 00099 while ( Gtk::Main::events_pending() ) { 00100 Gtk::Main::iteration(); 00101 } 00102 } 00103 00104 00105 int 00106 main(int argc, char **argv) 00107 { 00108 ArgumentParser argp(argc, argv, "hs:f:n:vjcd:o:"); 00109 std::string title = ""; 00110 00111 #ifdef HAVE_GTKMM 00112 Gtk::Main gtk_main(argc, argv); 00113 #endif 00114 00115 Camera *cam; 00116 SharedMemoryImageBuffer *buf = NULL; 00117 bool verbose = argp.has_arg("v"); 00118 int delay = 0; 00119 00120 if ( argp.has_arg("d") ) { 00121 delay = atoi(argp.arg("d")); 00122 if ( delay < 0 ) delay = 0; 00123 } 00124 00125 if ( argp.has_arg("h") ) { 00126 print_usage(argp.program_name()); 00127 exit(0); 00128 } else if ( argp.has_arg("s") ) { 00129 #ifdef HAVE_SHMEM_CAM 00130 title = std::string(argp.arg("s")); 00131 cam = new SharedMemoryCamera(argp.arg("s")); 00132 #else 00133 throw Exception("SharedMemoryCamera not available at compile time"); 00134 #endif 00135 } else if ( argp.has_arg("f") ) { 00136 #ifdef HAVE_FILELOADER_CAM 00137 title = std::string("File: ").append(argp.arg("f")); 00138 cam = new FileLoader(argp.arg("f")); 00139 #else 00140 throw Exception("FileLoader not available at compile time"); 00141 #endif 00142 } else if ( argp.has_arg("n") ) { 00143 #ifdef HAVE_NETWORK_CAM 00144 title = std::string("Net cam: ").append(argp.arg("n")); 00145 char *net_string = strdup(argp.arg("n")); 00146 char *image_id = NULL, *host = NULL, *port = NULL, *save_ptr = NULL; 00147 int port_num = 2208; 00148 char *hostport; 00149 00150 hostport = strtok_r(net_string, "/", &save_ptr); 00151 image_id = strtok_r(NULL, "", &save_ptr); 00152 00153 if ( strchr(hostport, ':') != NULL ) { 00154 host = strtok_r(hostport, ":", &save_ptr); 00155 port = strtok_r(NULL, "", &save_ptr); 00156 } else { 00157 host = hostport; 00158 } 00159 00160 if ( port != NULL ) { 00161 port_num = atoi(port); 00162 if ( (port_num < 0) || (port_num > 0xFFFF) ) { 00163 throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF); 00164 } 00165 } 00166 00167 if( image_id == NULL ) { 00168 throw IllegalArgumentException("Image ID must be specified"); 00169 } 00170 00171 cam = new NetworkCamera(host, port_num, image_id, argp.has_arg("j")); 00172 free(net_string); 00173 #else 00174 throw Exception("NetworkCamera not available at compile time"); 00175 #endif 00176 } else { 00177 if ( argp.num_items() == 0 ) { 00178 print_usage(argp.program_name()); 00179 printf("\n\nNeither camera option nor camera string given. Aborting.\n\n"); 00180 exit(-3); 00181 } 00182 cam = CameraFactory::instance(argp.items()[0]); 00183 } 00184 00185 if ( cam == NULL ) { 00186 throw Exception("Failed to initialize camera for unknown reason"); 00187 } 00188 00189 try { 00190 cam->open(); 00191 cam->start(); 00192 } catch (Exception &e) { 00193 printf("Failed to open camera\n"); 00194 e.print_trace(); 00195 delete cam; 00196 exit(-2); 00197 } 00198 00199 if ( argp.has_arg("o") ) 00200 { 00201 buf = new SharedMemoryImageBuffer(argp.arg("o"), cam->colorspace(), cam->pixel_width(), cam->pixel_height()); 00202 } 00203 00204 print_keys(); 00205 00206 if ( verbose ) { 00207 printf("Camera opened, settings:\n" 00208 " Colorspace: %u (%s)\n" 00209 " Dimensions: %u x %u\n" 00210 " Buffer size: %zu\n" 00211 " Delay: %i ms\n", 00212 cam->colorspace(), colorspace_to_string(cam->colorspace()), 00213 cam->pixel_width(), cam->pixel_height(), 00214 colorspace_buffer_size(cam->colorspace(), cam->pixel_width(), cam->pixel_height()), 00215 delay); 00216 } 00217 00218 ImageDisplay *display = new ImageDisplay(cam->pixel_width(), cam->pixel_height(), title.c_str()); 00219 00220 #ifdef HAVE_RECTINFO 00221 RectificationInfoFile *rectfile = new RectificationInfoFile(); 00222 FilterRectify *rectify_filter = NULL; 00223 unsigned char *filtered_buffer = malloc_buffer(YUV422_PLANAR, 00224 cam->pixel_width(), cam->pixel_height()); 00225 unsigned char *unfiltered_buffer = malloc_buffer(YUV422_PLANAR, 00226 cam->pixel_width(), cam->pixel_height()); 00227 bool rectifying = false; 00228 #endif 00229 bool continuous = argp.has_arg("c"); 00230 00231 SDL_Event redraw_event; 00232 redraw_event.type = SDL_KEYUP; 00233 redraw_event.key.keysym.sym = SDLK_SPACE; 00234 00235 SDL_PushEvent(&redraw_event); 00236 00237 bool quit = false; 00238 while (! quit) { 00239 SDL_Event event; 00240 if ( SDL_WaitEvent(&event) ) { 00241 switch (event.type) { 00242 case SDL_QUIT: 00243 quit = true; 00244 break; 00245 case SDL_KEYUP: 00246 if ( event.key.keysym.sym == SDLK_SPACE ) { 00247 cam->capture(); 00248 if (cam->buffer() != NULL ) { 00249 if ( buf ) memcpy(buf->buffer(), cam->buffer(), cam->buffer_size()); 00250 #ifdef HAVE_RECTINFO 00251 if ( rectifying ) { 00252 convert(cam->colorspace(), YUV422_PLANAR, cam->buffer(), unfiltered_buffer, 00253 cam->pixel_width(), cam->pixel_height()); 00254 ROI *fir = ROI::full_image(cam->pixel_width(), cam->pixel_height()); 00255 rectify_filter->set_src_buffer(unfiltered_buffer, fir); 00256 rectify_filter->set_dst_buffer(filtered_buffer, fir); 00257 rectify_filter->apply(); 00258 display->show(YUV422_PLANAR, filtered_buffer); 00259 } else { 00260 #endif 00261 display->show(cam->colorspace(), cam->buffer()); 00262 #ifdef HAVE_RECTINFO 00263 } 00264 #endif 00265 00266 cam->dispose_buffer(); 00267 } else { 00268 printf("No valid frame received\n"); 00269 } 00270 if ( continuous ) { 00271 usleep(delay * 1000); 00272 SDL_PushEvent(&redraw_event); 00273 } 00274 } else if ( event.key.keysym.sym == SDLK_ESCAPE ) { 00275 quit = true; 00276 } else if ( event.key.keysym.sym == SDLK_q ) { 00277 quit = true; 00278 } else if ( event.key.keysym.sym == SDLK_c ) { 00279 continuous = ! continuous; 00280 SDL_PushEvent(&redraw_event); 00281 } else if ( event.key.keysym.sym == SDLK_PLUS ) { 00282 delay += 5; 00283 printf("New delay: %i ms\n", delay); 00284 } else if ( event.key.keysym.sym == SDLK_MINUS ) { 00285 if ( delay > 5 ) { 00286 delay -= 5; 00287 } else { 00288 delay = 0; 00289 } 00290 printf("New delay: %i ms\n", delay); 00291 } else if ( event.key.keysym.sym == SDLK_r ) { 00292 #ifdef HAVE_GTKMM 00293 # ifdef HAVE_RECTINFO 00294 if ( rectifying ) { 00295 rectifying = false; 00296 } else { 00297 if ( (! (SDL_GetModState() & KMOD_LSHIFT) && 00298 ! (SDL_GetModState() & KMOD_RSHIFT)) || 00299 ! rectify_filter ) { 00300 Gtk::FileChooserDialog fcd("Open Rectification Info File"); 00301 00302 // Add response buttons the the dialog 00303 fcd.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); 00304 fcd.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK); 00305 00306 Gtk::FileFilter filter_rectinfo; 00307 filter_rectinfo.set_name("Rectification Info"); 00308 filter_rectinfo.add_pattern("*.rectinfo"); 00309 fcd.add_filter(filter_rectinfo); 00310 00311 Gtk::FileFilter filter_any; 00312 filter_any.set_name("Any File"); 00313 filter_any.add_pattern("*"); 00314 fcd.add_filter(filter_any); 00315 00316 int result = fcd.run(); 00317 00318 fcd.hide(); 00319 process_gtk_events(); 00320 00321 if ( result == Gtk::RESPONSE_OK) { 00322 // Nice, we got a file 00323 try { 00324 rectfile->read(fcd.get_filename().c_str()); 00325 if ( rectfile->num_blocks() == 0 ) { 00326 throw Exception("Rectification info file does not contain any info blocks"); 00327 } 00328 Gtk::HBox hbox; 00329 Gtk::Label label("Camera: "); 00330 Gtk::ComboBoxText cboxt; 00331 hbox.add(label); 00332 hbox.add(cboxt); 00333 label.show(); 00334 cboxt.show(); 00335 00336 RectificationInfoFile::RectInfoBlockVector *blocks = rectfile->rectinfo_blocks(); 00337 for (RectificationInfoFile::RectInfoBlockVector::iterator b = blocks->begin(); b != blocks->end(); ++b) { 00338 Glib::ustring us = rectinfo_camera_strings[(*b)->camera()]; 00339 us += Glib::ustring(" (") + rectinfo_type_strings[(*b)->type()] + ")"; 00340 cboxt.append_text(us); 00341 } 00342 cboxt.set_active(0); 00343 00344 Gtk::Dialog dialog("Choose Camera", false, true); 00345 dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK); 00346 dialog.get_vbox()->add(hbox); 00347 hbox.show(); 00348 dialog.run(); 00349 dialog.hide(); 00350 process_gtk_events(); 00351 00352 RectificationInfoBlock *chosen_block = (*blocks)[cboxt.get_active_row_number()]; 00353 RectificationInfoFile::RectInfoBlockVector::iterator bi = blocks->begin(); 00354 for(int i = 1; i < cboxt.get_active_row_number(); ++i) { 00355 ++bi; 00356 } 00357 blocks->erase(bi); // needs to be erased because otherwise it would be deleted by following delete 00358 delete blocks; 00359 00360 delete rectify_filter; 00361 rectify_filter = new FilterRectify(chosen_block); 00362 } catch (Exception &e) { 00363 Gtk::MessageDialog md(e.what(), 00364 /* use markup */ false, 00365 Gtk::MESSAGE_ERROR); 00366 md.set_title("Reading Rectification Info failed"); 00367 md.run(); 00368 md.hide(); 00369 00370 process_gtk_events(); 00371 } 00372 } 00373 } 00374 rectifying = (rectify_filter != NULL); 00375 } 00376 SDL_PushEvent(&redraw_event); 00377 # else 00378 printf("Rectification support not available at compile time\n"); 00379 # endif 00380 } 00381 #else 00382 printf("Rectification support requires gtkmm(-devel) to be installed " 00383 " at compile time.\n"); 00384 #endif 00385 break; 00386 default: 00387 break; 00388 } 00389 } 00390 } 00391 00392 #ifdef HAVE_RECTINFO 00393 delete rectfile; 00394 delete rectify_filter; 00395 free(filtered_buffer); 00396 free(unfiltered_buffer); 00397 #endif 00398 00399 cam->close(); 00400 delete cam; 00401 delete display; 00402 00403 return 0; 00404 } 00405