00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
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
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
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);
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 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