Fawkes API  Fawkes Development Version
viewer.cpp
1 
2 /***************************************************************************
3  * viewer.cpp - Generic viewer tool
4  *
5  * Created: Tue Nov 06 15:02:51 2007
6  * Copyright 2005-2007 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include <core/exceptions/software.h>
24 #include <fvcams/buffer.h>
25 #include <fvcams/factory.h>
26 #include <utils/system/argparser.h>
27 #ifdef HAVE_SHMEM_CAM
28 # include <fvcams/shmem.h>
29 #endif
30 #ifdef HAVE_NETWORK_CAM
31 # include <fvcams/net.h>
32 #endif
33 #ifdef HAVE_FILELOADER_CAM
34 # include <fvcams/fileloader.h>
35 #endif
36 
37 #include <fvwidgets/image_display.h>
38 #ifdef HAVE_RECTINFO
39 # include <fvfilters/rectify.h>
40 # include <fvutils/rectification/rectfile.h>
41 # include <fvutils/rectification/rectinfo_block.h>
42 #endif
43 #include <fvutils/colormap/cmfile.h>
44 #include <fvutils/colormap/colormap.h>
45 #include <fvutils/system/filetype.h>
46 
47 #include <SDL.h>
48 #include <cstdio>
49 #include <cstring>
50 #include <stdint.h>
51 #ifdef HAVE_GTKMM
52 # include <gtkmm.h>
53 #endif
54 
55 #include <fvutils/color/conversions.h>
56 
57 using namespace fawkes;
58 using namespace firevision;
59 
60 void
61 print_usage(const char *program_name)
62 {
63  printf("Usage: %s [-c] [-s shmem_id] [-n host[:port]/image_id] [-f file] [-o shmem_id] [-v] \\\n"
64  " [-d delay] [cam arg string]\n\n"
65  " -c Start in continuous update mode\n"
66  " -s shmem_id Open shared memory image with given ID\n"
67  " -n net_string Open network camera, the camera string is of the form\n"
68  " host[:port]/image_id. You have to specify at least the host\n"
69  " and the image_id, the port is optional and defaults to 5000\n"
70  " -j Receive JPEG images, only valid with -n\n"
71  " -d delay Delay in ms before a new image is capture.\n"
72  " -f file Open file loader camera with given file (image, colormap)\n"
73  " -o shmem_id Output the image to a shared memory segment with given ID\n"
74  " -v Verbose output on console\n"
75  " cam arg string Can be an arbitrary camera argument string that is understood\n"
76  " by CameraFactory and the desired camera.\n",
77  program_name);
78 }
79 
80 void
81 print_keys()
82 {
83  printf("Keys:\n"
84  " c Toggle continuous mode (automatic image updating as fast as possible)\n"
85  " r rectify image, will query for rectification info file and possibly\n"
86  " for camera if there is more than one block.\n"
87  " + Increase delay by 5 ms\n"
88  " - Decrease delay by 5 ms\n"
89  " Shift-R rectify image, use already loaded lut info file, do not query for\n"
90  " new file\n"
91  " Space Refresh image\n"
92  " q/Esc Quit viewer\n");
93 }
94 
95 /** Process all outstanding Gtk events. */
96 void
97 process_gtk_events()
98 {
99  while (Gtk::Main::events_pending()) {
100  Gtk::Main::iteration();
101  }
102 }
103 
104 int
105 main(int argc, char **argv)
106 {
107  ArgumentParser argp(argc, argv, "hs:f:n:vjcd:o:");
108  std::string title = "";
109 
110 #ifdef HAVE_GTKMM
111  Gtk::Main gtk_main(argc, argv);
112 #endif
113 
114  Camera * cam;
115  SharedMemoryImageBuffer *buf = NULL;
116  bool verbose = argp.has_arg("v");
117  int delay = 0;
118  Colormap * colormap = NULL;
119  unsigned int colormap_y = 0;
120 
121  if (argp.has_arg("d")) {
122  delay = atoi(argp.arg("d"));
123  if (delay < 0)
124  delay = 0;
125  }
126 
127  if (argp.has_arg("h")) {
128  print_usage(argp.program_name());
129  exit(0);
130  } else if (argp.has_arg("s")) {
131 #ifdef HAVE_SHMEM_CAM
132  title = std::string(argp.arg("s"));
133  cam = new SharedMemoryCamera(argp.arg("s"));
134 #else
135  throw Exception("SharedMemoryCamera not available at compile time");
136 #endif
137  } else if (argp.has_arg("f")) {
138 #ifdef HAVE_FILELOADER_CAM
139  std::string filename = argp.arg("f");
140  title = std::string("File: ").append(filename);
141  std::string ft = fv_filetype_file(filename.c_str());
142 
143  if (ft == "FvColormap") {
144  ColormapFile cm_file;
145  cm_file.read(filename.c_str());
146  colormap = cm_file.get_colormap();
147 
148  cam = new BufferCamera(YUV422_PLANAR, 512, 512);
149  colormap->to_image(cam->buffer(), colormap_y);
150  } else {
151  cam = new FileLoader(filename.c_str());
152  }
153 #else
154  throw Exception("FileLoader not available at compile time");
155 #endif
156  } else if (argp.has_arg("n")) {
157 #ifdef HAVE_NETWORK_CAM
158  title = std::string("Net cam: ").append(argp.arg("n"));
159  char *net_string = strdup(argp.arg("n"));
160  char *image_id = NULL, *host = NULL, *port = NULL, *save_ptr = NULL;
161  int port_num = 2208;
162  char *hostport;
163 
164  hostport = strtok_r(net_string, "/", &save_ptr);
165  image_id = strtok_r(NULL, "", &save_ptr);
166 
167  if (strchr(hostport, ':') != NULL) {
168  host = strtok_r(hostport, ":", &save_ptr);
169  port = strtok_r(NULL, "", &save_ptr);
170  } else {
171  host = hostport;
172  }
173 
174  if (port != NULL) {
175  port_num = atoi(port);
176  if ((port_num < 0) || (port_num > 0xFFFF)) {
177  throw OutOfBoundsException("Invalid port", port_num, 0, 0xFFFF);
178  }
179  }
180 
181  if (image_id == NULL) {
182  throw IllegalArgumentException("Image ID must be specified");
183  }
184 
185  cam = new NetworkCamera(host, port_num, image_id, argp.has_arg("j"));
186  free(net_string);
187 #else
188  throw Exception("NetworkCamera not available at compile time");
189 #endif
190  } else {
191  if (argp.num_items() == 0) {
192  print_usage(argp.program_name());
193  printf("\n\nNeither camera option nor camera string given. Aborting.\n\n");
194  exit(-3);
195  }
196  cam = CameraFactory::instance(argp.items()[0]);
197  }
198 
199  if (cam == NULL) {
200  throw Exception("Failed to initialize camera for unknown reason");
201  }
202 
203  try {
204  cam->open();
205  cam->start();
206  } catch (Exception &e) {
207  printf("Failed to open camera\n");
208  e.print_trace();
209  delete cam;
210  exit(-2);
211  }
212 
213  if (argp.has_arg("o")) {
214  buf = new SharedMemoryImageBuffer(argp.arg("o"),
215  cam->colorspace(),
216  cam->pixel_width(),
217  cam->pixel_height());
218  }
219 
220  print_keys();
221 
222  if (verbose) {
223  printf("Camera opened, settings:\n"
224  " Colorspace: %u (%s)\n"
225  " Dimensions: %u x %u\n"
226  " Buffer size: %zu\n"
227  " Delay: %i ms\n",
228  cam->colorspace(),
229  colorspace_to_string(cam->colorspace()),
230  cam->pixel_width(),
231  cam->pixel_height(),
232  colorspace_buffer_size(cam->colorspace(), cam->pixel_width(), cam->pixel_height()),
233  delay);
234  }
235 
236  ImageDisplay *display = new ImageDisplay(cam->pixel_width(), cam->pixel_height(), title.c_str());
237 
238 #ifdef HAVE_RECTINFO
240  FilterRectify * rectify_filter = NULL;
241  unsigned char * filtered_buffer =
242  malloc_buffer(YUV422_PLANAR, cam->pixel_width(), cam->pixel_height());
243  unsigned char *unfiltered_buffer =
244  malloc_buffer(YUV422_PLANAR, cam->pixel_width(), cam->pixel_height());
245  bool rectifying = false;
246 #endif
247  bool continuous = argp.has_arg("c");
248 
249  SDL_Event redraw_event;
250  redraw_event.type = SDL_KEYUP;
251  redraw_event.key.keysym.sym = SDLK_SPACE;
252 
253  SDL_PushEvent(&redraw_event);
254 
255  bool quit = false;
256  while (!quit) {
257  SDL_Event event;
258  if (SDL_WaitEvent(&event)) {
259  switch (event.type) {
260  case SDL_QUIT: quit = true; break;
261  case SDL_KEYUP:
262  if (event.key.keysym.sym == SDLK_SPACE) {
263  cam->capture();
264  if (cam->buffer() != NULL) {
265  if (buf)
266  memcpy(buf->buffer(), cam->buffer(), cam->buffer_size());
267 #ifdef HAVE_RECTINFO
268  if (rectifying) {
269  convert(cam->colorspace(),
270  YUV422_PLANAR,
271  cam->buffer(),
272  unfiltered_buffer,
273  cam->pixel_width(),
274  cam->pixel_height());
275  ROI *fir = ROI::full_image(cam->pixel_width(), cam->pixel_height());
276  rectify_filter->set_src_buffer(unfiltered_buffer, fir);
277  rectify_filter->set_dst_buffer(filtered_buffer, fir);
278  rectify_filter->apply();
279  display->show(YUV422_PLANAR, filtered_buffer);
280  } else {
281 #endif
282  display->show(cam->colorspace(), cam->buffer());
283 #ifdef HAVE_RECTINFO
284  }
285 #endif
286 
287  cam->dispose_buffer();
288  } else {
289  printf("No valid frame received\n");
290  }
291  if (continuous) {
292  usleep(delay * 1000);
293  SDL_PushEvent(&redraw_event);
294  }
295  } else if (event.key.keysym.sym == SDLK_ESCAPE) {
296  quit = true;
297  } else if (event.key.keysym.sym == SDLK_q) {
298  quit = true;
299  } else if (event.key.keysym.sym == SDLK_c) {
300  continuous = !continuous;
301  SDL_PushEvent(&redraw_event);
302  } else if (event.key.keysym.sym == SDLK_PLUS) {
303  delay += 5;
304  printf("New delay: %i ms\n", delay);
305  } else if (event.key.keysym.sym == SDLK_MINUS) {
306  if (delay > 5) {
307  delay -= 5;
308  } else {
309  delay = 0;
310  }
311  printf("New delay: %i ms\n", delay);
312  } else if (event.key.keysym.sym == SDLK_UP) {
313  colormap_y = std::min(255u, colormap_y + 5);
314  printf("Colormap new Y (+): %u\n", colormap_y);
315  colormap->to_image(cam->buffer(), colormap_y);
316  SDL_PushEvent(&redraw_event);
317  } else if (event.key.keysym.sym == SDLK_DOWN) {
318  colormap_y = std::max(0, (int)colormap_y - 5);
319  printf("Colormap new Y (-): %u\n", colormap_y);
320  colormap->to_image(cam->buffer(), colormap_y);
321  SDL_PushEvent(&redraw_event);
322  } else if (event.key.keysym.sym == SDLK_r) {
323 #ifdef HAVE_GTKMM
324 # ifdef HAVE_RECTINFO
325  if (rectifying) {
326  rectifying = false;
327  } else {
328  if ((!(SDL_GetModState() & KMOD_LSHIFT) && !(SDL_GetModState() & KMOD_RSHIFT))
329  || !rectify_filter) {
330  Gtk::FileChooserDialog fcd("Open Rectification Info File");
331 
332  // Add response buttons the the dialog
333  fcd.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
334  fcd.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
335 
336 # if GTK_VERSION_GE(3, 0)
337  Glib::RefPtr<Gtk::FileFilter> filter_rectinfo = Gtk::FileFilter::create();
338  filter_rectinfo->set_name("Rectification Info");
339  filter_rectinfo->add_pattern("*.rectinfo");
340 # else
341  Gtk::FileFilter filter_rectinfo;
342  filter_rectinfo.set_name("Rectification Info");
343  filter_rectinfo.add_pattern("*.rectinfo");
344 # endif
345  fcd.add_filter(filter_rectinfo);
346 
347 # if GTK_VERSION_GE(3, 0)
348  Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
349  filter_any->set_name("Any File");
350  filter_any->add_pattern("*");
351 # else
352  Gtk::FileFilter filter_any;
353  filter_any.set_name("Any File");
354  filter_any.add_pattern("*");
355 # endif
356  fcd.add_filter(filter_any);
357 
358  int result = fcd.run();
359 
360  fcd.hide();
361  process_gtk_events();
362 
363  if (result == Gtk::RESPONSE_OK) {
364  // Nice, we got a file
365  try {
366  rectfile->read(fcd.get_filename().c_str());
367  if (rectfile->num_blocks() == 0) {
368  throw Exception("Rectification info file does not contain any info blocks");
369  }
370  Gtk::HBox hbox;
371  Gtk::Label label("Camera: ");
372  Gtk::ComboBoxText cboxt;
373  hbox.add(label);
374  hbox.add(cboxt);
375  label.show();
376  cboxt.show();
377 
378  RectificationInfoFile::RectInfoBlockVector *blocks = rectfile->rectinfo_blocks();
379  for (RectificationInfoFile::RectInfoBlockVector::iterator b = blocks->begin();
380  b != blocks->end();
381  ++b) {
382  Glib::ustring us = rectinfo_camera_strings[(*b)->camera()];
383  us += Glib::ustring(" (") + rectinfo_type_strings[(*b)->type()] + ")";
384 # if GTK_VERSION_GE(3, 0)
385  cboxt.append(us);
386 # else
387  cboxt.append_text(us);
388 # endif
389  }
390  cboxt.set_active(0);
391 
392  Gtk::Dialog dialog("Choose Camera", true);
393  dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
394  dialog.get_vbox()->add(hbox);
395  hbox.show();
396  dialog.run();
397  dialog.hide();
398  process_gtk_events();
399 
400  RectificationInfoBlock *chosen_block = (*blocks)[cboxt.get_active_row_number()];
401  RectificationInfoFile::RectInfoBlockVector::iterator bi = blocks->begin();
402  for (int i = 1; i < cboxt.get_active_row_number(); ++i) {
403  ++bi;
404  }
405  blocks->erase(
406  bi); // needs to be erased because otherwise it would be deleted by following delete
407  delete blocks;
408 
409  delete rectify_filter;
410  rectify_filter = new FilterRectify(chosen_block);
411  } catch (Exception &e) {
412  Gtk::MessageDialog md(e.what(),
413  /* use markup */ false,
414  Gtk::MESSAGE_ERROR);
415  md.set_title("Reading Rectification Info failed");
416  md.run();
417  md.hide();
418 
419  process_gtk_events();
420  }
421  }
422  }
423  rectifying = (rectify_filter != NULL);
424  }
425  SDL_PushEvent(&redraw_event);
426 # else
427  printf("Rectification support not available at compile time\n");
428 # endif
429  }
430 #else
431  printf("Rectification support requires gtkmm(-devel) to be installed "
432  " at compile time.\n");
433 #endif
434  break;
435  default: break;
436  }
437  }
438  }
439 
440 #ifdef HAVE_RECTINFO
441  delete rectfile;
442  delete rectify_filter;
443  free(filtered_buffer);
444  free(unfiltered_buffer);
445 #endif
446 
447  cam->close();
448  delete cam;
449  delete display;
450  delete colormap;
451 
452  return 0;
453 }
fawkes::IllegalArgumentException
Definition: software.h:83
firevision::Camera::start
virtual void start()=0
firevision::FilterRectify::apply
virtual void apply()
Definition: rectify.cpp:75
firevision::Filter::set_src_buffer
virtual void set_src_buffer(unsigned char *buf, ROI *roi, orientation_t ori=ORI_HORIZONTAL, unsigned int buffer_num=0)
Set source buffer with orientation.
Definition: filter.cpp:88
firevision::ImageDisplay
Definition: image_display.h:34
firevision::NetworkCamera
Definition: net.h:44
firevision::FileLoader
Definition: fileloader.h:43
firevision::Camera::colorspace
virtual colorspace_t colorspace()=0
firevision::Camera::buffer_size
virtual unsigned int buffer_size()=0
firevision::RectificationInfoFile
Definition: rectfile.h:40
firevision::SharedMemoryCamera
Definition: shmem.h:39
firevision::FireVisionDataFile::read
virtual void read(const char *file_name)
Read file.
Definition: fvfile.cpp:289
firevision::ROI
Definition: roi.h:58
firevision::ColormapFile::get_colormap
Colormap * get_colormap()
Get a freshly generated colormap based on current file content.
Definition: cmfile.cpp:168
firevision::Camera::open
virtual void open()=0
firevision::Camera::dispose_buffer
virtual void dispose_buffer()=0
firevision::SharedMemoryImageBuffer
Definition: shm_image.h:182
firevision::Camera::close
virtual void close()=0
firevision::Filter::set_dst_buffer
virtual void set_dst_buffer(unsigned char *buf, ROI *roi)
Set the destination buffer.
Definition: filter.cpp:122
firevision::RectificationInfoBlock
Definition: rectinfo_block.h:37
fawkes::OutOfBoundsException
Definition: software.h:89
firevision::Colormap::to_image
virtual void to_image(unsigned char *yuv422_planar_buffer, unsigned int level=0)
Create image from LUT.
Definition: colormap.cpp:130
firevision::RectificationInfoFile::RectInfoBlockVector
Vector that is used for maintaining the rectification info blocks.
Definition: rectfile.h:51
firevision::Camera::buffer
virtual unsigned char * buffer()=0
fawkes
firevision::Camera::pixel_height
virtual unsigned int pixel_height()=0
fawkes::ArgumentParser
Definition: argparser.h:67
firevision::FilterRectify
Definition: rectify.h:37
fawkes::Exception::print_trace
void print_trace()
Prints trace to stderr.
Definition: exception.cpp:600
firevision::SharedMemoryImageBuffer::buffer
unsigned char * buffer() const
Get image buffer.
Definition: shm_image.cpp:227
firevision::Camera::pixel_width
virtual unsigned int pixel_width()=0
firevision::Colormap
Definition: colormap.h:40
fawkes::Exception::what
virtual const char * what() const
Get primary string.
Definition: exception.cpp:638
firevision::Camera::capture
virtual void capture()=0
firevision::ColormapFile
Definition: cmfile.h:58
firevision::Camera
Definition: camera.h:36
firevision::BufferCamera
Definition: buffer.h:35
fawkes::Exception
Definition: exception.h:39