MRPT  2.0.4
CCameraSensor.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | https://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2020, Individual contributors, see AUTHORS file |
6  | See: https://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See: https://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "hwdrivers-precomp.h" // Precompiled headers
11 //
15 #include <mrpt/gui/WxSubsystem.h>
16 #include <mrpt/gui/WxUtils.h>
20 #include <mrpt/obs/CRawlog.h>
21 #include <mrpt/obs/CSensoryFrame.h>
23 #include <mrpt/system/filesystem.h>
24 #include <mrpt/system/os.h>
27 
28 #include <memory>
29 
30 using namespace mrpt;
31 using namespace mrpt::hwdrivers;
32 using namespace mrpt::gui;
33 using namespace mrpt::obs;
34 using namespace mrpt::config;
35 using namespace mrpt::system;
36 using namespace mrpt::io;
37 using namespace mrpt::serialization;
38 using namespace mrpt::img;
39 using namespace std;
40 using namespace std::literals;
41 
43 
44 /* -----------------------------------------------------
45  Constructor
46  ----------------------------------------------------- */
48  : mrpt::system::COutputLogger("CCameraSensor"),
49  m_sensorPose(),
50  m_grabber_type("opencv"),
51 
52  m_cv_camera_type("CAMERA_CV_AUTODETECT"),
53  m_cv_options(),
54 
55  m_dc1394_options(),
56 
57  m_svs_options(),
58 
59  // ---
60  m_img_dir_url(""),
61  m_img_dir_left_format("imL_%04d.jpg"),
62  m_img_dir_right_format("imR_%04d.jpg"),
63 
64  m_external_image_saver_count(std::thread::hardware_concurrency()),
65 
66  m_hook_pre_save(nullptr)
67 
68 {
69  m_sensorLabel = "CAMERA";
71 }
72 
73 /* -----------------------------------------------------
74  initialize
75  ----------------------------------------------------- */
77 {
78  cout << "[CCameraSensor::initialize] Opening camera..." << endl;
79  close();
80 
81  // Select type of device
82  m_grabber_type = trim(lowerCase(m_grabber_type));
83  m_cv_camera_type = trim(upperCase(m_cv_camera_type));
84 
85  if (m_grabber_type == "opencv")
86  {
87  // OpenCV driver:
88  TCameraType ct;
89  try
90  {
92  m_cv_camera_type);
93  }
94  catch (std::exception&)
95  {
96  m_state = CGenericSensor::ssError;
97  throw;
98  }
99  cout << format(
100  "[CCameraSensor::initialize] opencv camera, index: %i type: "
101  "%i...\n",
102  int(m_cv_camera_index), (int)ct);
103  m_cap_cv = std::make_unique<CImageGrabber_OpenCV>(
104  m_cv_camera_index, ct, m_cv_options);
105 
106  if (!m_cap_cv->isOpen())
107  {
108  m_state = CGenericSensor::ssError;
110  "[CCameraSensor::initialize] ERROR: Couldn't open OpenCV "
111  "camera.");
112  }
113  }
114  else if (m_grabber_type == "dc1394")
115  {
116  // m_cap_dc1394
117  cout << format(
118  "[CCameraSensor::initialize] dc1394 camera, GUID: 0x%lX "
119  "UNIT:%d...\n",
120  long(m_dc1394_camera_guid), m_dc1394_camera_unit);
121  m_cap_dc1394 = std::make_unique<CImageGrabber_dc1394>(
122  m_dc1394_camera_guid, m_dc1394_camera_unit, m_dc1394_options,
123  true /* verbose */);
124 
125  if (!m_cap_dc1394->isOpen())
126  {
127  m_state = CGenericSensor::ssError;
129  "[CCameraSensor::initialize] ERROR: Couldn't open dc1394 "
130  "camera.");
131  }
132  }
133  else if (m_grabber_type == "bumblebee_dc1394")
134  {
135  cout << format(
136  "[CCameraSensor::initialize] bumblebee_libdc1394 camera: "
137  "GUID:0x%08X Index:%i FPS:%f...\n",
138  (unsigned int)(m_bumblebee_dc1394_camera_guid),
139  m_bumblebee_dc1394_camera_unit, m_bumblebee_dc1394_framerate);
140  m_cap_bumblebee_dc1394 =
141  std::make_unique<CStereoGrabber_Bumblebee_libdc1394>(
142  m_bumblebee_dc1394_camera_guid, m_bumblebee_dc1394_camera_unit,
143  m_bumblebee_dc1394_framerate);
144  }
145  else if (m_grabber_type == "svs")
146  {
147  cout << format(
148  "[CCameraSensor::initialize] SVS camera: %u...\n",
149  (unsigned int)(m_svs_camera_index));
150  m_cap_svs = std::make_unique<CStereoGrabber_SVS>(
151  m_svs_camera_index, m_svs_options);
152  }
153  else if (m_grabber_type == "ffmpeg")
154  {
155  // m_cap_ffmpeg
156  cout << format(
157  "[CCameraSensor::initialize] FFmpeg stream: %s...\n",
158  m_ffmpeg_url.c_str());
159  m_cap_ffmpeg = std::make_unique<CFFMPEG_InputStream>();
160 
161  if (!m_cap_ffmpeg->openURL(m_ffmpeg_url, m_capture_grayscale))
162  {
163  m_state = CGenericSensor::ssError;
165  "Error opening FFmpeg stream: %s", m_ffmpeg_url.c_str());
166  }
167  }
168  else if (m_grabber_type == "swissranger")
169  {
170  cout << "[CCameraSensor::initialize] SwissRanger camera...\n";
171  m_cap_swissranger = std::make_unique<CSwissRanger3DCamera>();
172 
173  m_cap_swissranger->setOpenFromUSB(m_sr_open_from_usb);
174  m_cap_swissranger->setOpenIPAddress(m_sr_ip_address);
175 
176  m_cap_swissranger->setSave3D(m_sr_save_3d);
177  m_cap_swissranger->setSaveRangeImage(m_sr_save_range_img);
178  m_cap_swissranger->setSaveIntensityImage(m_sr_save_intensity_img);
179  m_cap_swissranger->setSaveConfidenceImage(m_sr_save_confidence);
180 
181  if (!m_path_for_external_images.empty())
182  m_cap_swissranger->setPathForExternalImages(
183  m_path_for_external_images);
184 
185  // Open it:
186  try
187  {
188  m_cap_swissranger
189  ->initialize(); // This will launch an exception if needed.
190  }
191  catch (std::exception&)
192  {
193  m_state = CGenericSensor::ssError;
194  throw;
195  }
196  }
197  else if (m_grabber_type == "kinect")
198  {
199  cout << "[CCameraSensor::initialize] Kinect camera...\n";
200  m_cap_kinect = std::make_unique<CKinect>();
201  m_cap_kinect->enableGrab3DPoints(m_kinect_save_3d);
202  m_cap_kinect->enableGrabDepth(m_kinect_save_range_img);
203  m_cap_kinect->enableGrabRGB(m_kinect_save_intensity_img);
204  m_cap_kinect->setVideoChannel(
205  m_kinect_video_rgb ? CKinect::VIDEO_CHANNEL_RGB
207 
208  if (!m_path_for_external_images.empty())
209  m_cap_kinect->setPathForExternalImages(m_path_for_external_images);
210 
211  // Open it:
212  try
213  {
214  m_cap_kinect
215  ->initialize(); // This will launch an exception if needed.
216  }
217  catch (std::exception&)
218  {
219  m_state = CGenericSensor::ssError;
220  throw;
221  }
222  }
223  else if (m_grabber_type == "openni2")
224  {
225  cout << "[CCameraSensor::initialize] OpenNI2 sensor...\n";
226  m_cap_openni2 = std::make_unique<COpenNI2Sensor>();
227  m_cap_openni2->enableGrab3DPoints(m_kinect_save_3d); // It uses the
228  // same options as
229  // the Kinect
230  // grabber
231  m_cap_openni2->enableGrabDepth(m_kinect_save_range_img);
232  m_cap_openni2->enableGrabRGB(m_kinect_save_intensity_img);
233 
234  if (!m_path_for_external_images.empty())
235  m_cap_openni2->setPathForExternalImages(m_path_for_external_images);
236 
237  // Open it:
238  try
239  {
240  m_cap_openni2
241  ->initialize(); // This will launch an exception if needed.
242  }
243  catch (const std::exception& e)
244  {
245  m_state = CGenericSensor::ssError;
246  throw e;
247  }
248  }
249  else if (m_grabber_type == "image_dir")
250  {
251  // m_cap_image_dir
252  cout << format(
253  "[CCameraSensor::initialize] Image dir: %s...\n",
254  m_img_dir_url.c_str());
255  m_cap_image_dir = std::make_unique<std::string>();
256  }
257  else if (m_grabber_type == "rawlog")
258  {
259  // m_cap_rawlog
260  cout << format(
261  "[CCameraSensor::initialize] Rawlog stream: %s...\n",
262  m_rawlog_file.c_str());
263  m_cap_rawlog = std::make_unique<CFileGZInputStream>();
264 
265  if (!m_cap_rawlog->open(m_rawlog_file))
266  {
267  m_state = CGenericSensor::ssError;
269  "Error opening rawlog file: %s", m_rawlog_file.c_str());
270  }
271  // File open OK.
272  // Localize the external images directory of this rawlog, if it exists:
273  m_rawlog_detected_images_dir =
274  CRawlog::detectImagesDirectory(m_rawlog_file);
275  }
276  else if (m_grabber_type == "flycap")
277  {
278  cout << "[CCameraSensor::initialize] PGR FlyCapture2 camera...\n";
279  try
280  {
281  // Open camera and start capture:
282  m_cap_flycap =
283  std::make_unique<CImageGrabber_FlyCapture2>(m_flycap_options);
284  }
285  catch (std::exception&)
286  {
287  m_state = CGenericSensor::ssError;
288  throw;
289  }
290  }
291  else if (m_grabber_type == "flycap_stereo")
292  {
293  cout
294  << "[CCameraSensor::initialize] PGR FlyCapture2 stereo camera...\n";
295  try
296  {
297  // Open camera and start capture:
298  m_cap_flycap_stereo_l =
299  std::make_unique<CImageGrabber_FlyCapture2>();
300  m_cap_flycap_stereo_r =
301  std::make_unique<CImageGrabber_FlyCapture2>();
302 
303  cout << "[CCameraSensor::initialize] PGR FlyCapture2 stereo "
304  "camera: Opening LEFT camera...\n";
305  m_cap_flycap_stereo_l->open(
306  m_flycap_stereo_options[0], false /* don't start grabbing */);
307 
308  cout << "[CCameraSensor::initialize] PGR FlyCapture2 stereo "
309  "camera: Opening RIGHT camera...\n";
310  m_cap_flycap_stereo_r->open(
311  m_flycap_stereo_options[1], false /* don't start grabbing */);
312 
313  // Now, start grabbing "simultaneously":
314  if (m_fcs_start_synch_capture)
315  {
316  const CImageGrabber_FlyCapture2* cams[2] = {
317  m_cap_flycap_stereo_l.get(), m_cap_flycap_stereo_r.get()};
319  }
320  else
321  {
322  m_cap_flycap_stereo_l->startCapture();
323  m_cap_flycap_stereo_r->startCapture();
324  }
325  }
326  catch (std::exception&)
327  {
328  m_state = CGenericSensor::ssError;
329  throw;
330  }
331  }
332  else if (m_grabber_type == "duo3d")
333  {
334  // m_cap_duo3D
335  cout << "[CCameraSensor::initialize] DUO3D stereo camera ...\n";
336 
337  // Open it:
338  try
339  {
340  m_cap_duo3d = std::make_unique<CDUO3DCamera>(m_duo3d_options);
341  }
342  catch (const std::exception& e)
343  {
344  m_state = CGenericSensor::ssError;
345  throw e;
346  }
347  }
348  else if (m_grabber_type == "myntd")
349  {
350  cout << "[CCameraSensor::initialize] MYNTEYE-D camera ...\n";
351 
352  // Open it:
353  try
354  {
355  m_myntd = std::make_unique<CMyntEyeCamera>(m_myntd_options);
356  }
357  catch (const std::exception& e)
358  {
359  m_state = CGenericSensor::ssError;
360  throw e;
361  }
362  }
363  else
365  "Unknown 'grabber_type' found: %s", m_grabber_type.c_str());
366 
367  // Change state:
368  cout << "[CCameraSensor::initialize] Done!" << endl;
369  m_state = CGenericSensor::ssWorking;
370 
371  // Launch independent thread?
372  if (m_external_images_own_thread)
373  {
374  m_threadImagesSaverShouldEnd = false;
375 
376  m_threadImagesSaver.clear();
377  m_threadImagesSaver.resize(m_external_image_saver_count);
378 
379  m_toSaveList.clear();
380  m_toSaveList.resize(m_external_image_saver_count);
381 
382  for (unsigned int i = 0; i < m_external_image_saver_count; ++i)
383  {
384  m_threadImagesSaver[i] =
385  std::thread(&CCameraSensor::thread_save_images, this, i);
386 
388  "CameraSaveImages", m_threadImagesSaver[i]);
389  }
390  }
391 }
392 
393 /* -----------------------------------------------------
394  close
395  ----------------------------------------------------- */
397 {
398  m_cap_cv.reset();
399  m_cap_dc1394.reset();
400  m_cap_flycap.reset();
401  m_cap_flycap_stereo_l.reset();
402  m_cap_flycap_stereo_r.reset();
403  m_cap_bumblebee_dc1394.reset();
404  m_cap_ffmpeg.reset();
405  m_cap_rawlog.reset();
406  m_cap_swissranger.reset();
407  m_cap_kinect.reset();
408  m_cap_svs.reset();
409  m_cap_image_dir.reset();
410  m_cap_duo3d.reset();
411 
413 
414  // Wait for threads:
415  if (!m_threadImagesSaver.empty())
416  {
417  m_threadImagesSaverShouldEnd = true;
418  for (auto& i : m_threadImagesSaver) i.join();
419  }
420 }
421 
422 /* -----------------------------------------------------
423  loadConfig_sensorSpecific
424  ----------------------------------------------------- */
426  const mrpt::config::CConfigFileBase& configSource,
427  const std::string& iniSection)
428 {
429  // At this point, my parent class CGenericSensor has already loaded its
430  // params:
431  // Since cameras are special, we'll take control over "m_grab_decimation"
432  // so
433  // external image files are not saved just to be discarded later on...
434  if (m_grab_decimation > 0)
435  {
436  m_camera_grab_decimator = m_grab_decimation;
437  m_camera_grab_decimator_counter = 0;
438  // Reset in parent:
439  m_grab_decimation = 0;
440  }
441  else
442  m_camera_grab_decimator = m_camera_grab_decimator_counter = 0;
443 
444  m_grabber_type = configSource.read_string_first_word(
445  iniSection, "grabber_type", m_grabber_type);
447  preview_decimation, int, m_preview_decimation, configSource, iniSection)
449  preview_reduction, int, m_preview_reduction, configSource, iniSection)
450 
451  // OpenCV options:
452  m_cv_camera_type = configSource.read_string_first_word(
453  iniSection, "cv_camera_type", m_cv_camera_type);
454  m_cv_camera_index =
455  configSource.read_int(iniSection, "cv_camera_index", m_cv_camera_index);
456 
457  m_cv_options.frame_width = configSource.read_int(
458  iniSection, "cv_frame_width", m_cv_options.frame_width);
459  m_cv_options.frame_height = configSource.read_int(
460  iniSection, "cv_frame_height", m_cv_options.frame_height);
461  m_cv_options.gain =
462  configSource.read_double(iniSection, "cv_gain", m_cv_options.gain);
463  m_cv_options.ieee1394_fps = configSource.read_double(
464  iniSection, "cv_fps", m_cv_options.ieee1394_fps);
465 
466  m_capture_grayscale =
467  configSource.read_bool(iniSection, "capture_grayscale", false);
468 
469  m_cv_options.ieee1394_grayscale = m_capture_grayscale;
470 
471  // dc1394 options:
473  dc1394_camera_guid, uint64_t, m_dc1394_camera_guid, configSource,
474  iniSection)
476  dc1394_camera_unit, int, m_dc1394_camera_unit, configSource, iniSection)
477 
479  dc1394_frame_width, int, m_dc1394_options.frame_width, configSource,
480  iniSection)
482  dc1394_frame_height, int, m_dc1394_options.frame_height, configSource,
483  iniSection)
484 
486  dc1394_mode7, int, m_dc1394_options.mode7, configSource, iniSection)
487 
489  dc1394_shutter, int, m_dc1394_options.shutter, configSource, iniSection)
491  dc1394_gain, int, m_dc1394_options.gain, configSource, iniSection)
493  dc1394_gamma, int, m_dc1394_options.gamma, configSource, iniSection)
495  dc1394_brightness, int, m_dc1394_options.brightness, configSource,
496  iniSection)
498  dc1394_exposure, int, m_dc1394_options.exposure, configSource,
499  iniSection)
501  dc1394_sharpness, int, m_dc1394_options.sharpness, configSource,
502  iniSection)
504  dc1394_white_balance, int, m_dc1394_options.white_balance, configSource,
505  iniSection)
506 
508  dc1394_shutter_mode, int, m_dc1394_options.shutter_mode, configSource,
509  iniSection)
511  dc1394_gain_mode, int, m_dc1394_options.gain_mode, configSource,
512  iniSection)
514  dc1394_gamma_mode, int, m_dc1394_options.gamma_mode, configSource,
515  iniSection)
517  dc1394_brightness_mode, int, m_dc1394_options.brightness_mode,
518  configSource, iniSection)
520  dc1394_exposure_mode, int, m_dc1394_options.exposure_mode, configSource,
521  iniSection)
523  dc1394_sharpness_mode, int, m_dc1394_options.sharpness_mode,
524  configSource, iniSection)
526  dc1394_white_balance_mode, int, m_dc1394_options.white_balance_mode,
527  configSource, iniSection)
528 
530  dc1394_trigger_power, int, m_dc1394_options.trigger_power, configSource,
531  iniSection)
533  dc1394_trigger_mode, int, m_dc1394_options.trigger_mode, configSource,
534  iniSection)
536  dc1394_trigger_source, int, m_dc1394_options.trigger_source,
537  configSource, iniSection)
539  dc1394_trigger_polarity, int, m_dc1394_options.trigger_polarity,
540  configSource, iniSection)
542  dc1394_ring_buffer_size, int, m_dc1394_options.ring_buffer_size,
543  configSource, iniSection)
544 
545  // Bumblebee_dc1394 options:
547  bumblebee_dc1394_camera_guid, uint64_t, m_bumblebee_dc1394_camera_guid,
548  configSource, iniSection)
550  bumblebee_dc1394_camera_unit, int, m_bumblebee_dc1394_camera_unit,
551  configSource, iniSection)
553  bumblebee_dc1394_framerate, double, m_bumblebee_dc1394_framerate,
554  configSource, iniSection)
555 
556  // SVS options:
557  m_svs_camera_index = configSource.read_int(
558  iniSection, "svs_camera_index", m_svs_camera_index);
559  m_svs_options.frame_width = configSource.read_int(
560  iniSection, "svs_frame_width", m_svs_options.frame_width);
561  m_svs_options.frame_height = configSource.read_int(
562  iniSection, "svs_frame_height", m_svs_options.frame_height);
563  m_svs_options.framerate = configSource.read_double(
564  iniSection, "svs_framerate", m_svs_options.framerate);
565  m_svs_options.m_NDisp =
566  configSource.read_int(iniSection, "svs_NDisp", m_svs_options.m_NDisp);
567  m_svs_options.m_Corrsize = configSource.read_int(
568  iniSection, "svs_Corrsize", m_svs_options.m_Corrsize);
569  m_svs_options.m_LR =
570  configSource.read_int(iniSection, "svs_LR", m_svs_options.m_LR);
571  m_svs_options.m_Thresh =
572  configSource.read_int(iniSection, "svs_Thresh", m_svs_options.m_Thresh);
573  m_svs_options.m_Unique =
574  configSource.read_int(iniSection, "svs_Unique", m_svs_options.m_Unique);
575  m_svs_options.m_Horopter = configSource.read_int(
576  iniSection, "svs_Horopter", m_svs_options.m_Horopter);
577  m_svs_options.m_SpeckleSize = configSource.read_int(
578  iniSection, "svs_SpeckleSize", m_svs_options.m_SpeckleSize);
579  m_svs_options.m_procesOnChip = configSource.read_bool(
580  iniSection, "svs_procesOnChip", m_svs_options.m_procesOnChip);
581  m_svs_options.m_calDisparity = configSource.read_bool(
582  iniSection, "svs_calDisparity", m_svs_options.m_calDisparity);
583 
584  // FFmpeg options:
585  m_ffmpeg_url = mrpt::system::trim(
586  configSource.read_string(iniSection, "ffmpeg_url", m_ffmpeg_url));
587 
588  // Rawlog options:
589  m_rawlog_file = mrpt::system::trim(
590  configSource.read_string(iniSection, "rawlog_file", m_rawlog_file));
591  m_rawlog_camera_sensor_label = mrpt::system::trim(configSource.read_string(
592  iniSection, "rawlog_camera_sensor_label",
593  m_rawlog_camera_sensor_label));
594 
595  // Image directory options:
596  m_img_dir_url = mrpt::system::trim(
597  configSource.read_string(iniSection, "image_dir_url", m_img_dir_url));
598  m_img_dir_left_format = mrpt::system::trim(configSource.read_string(
599  iniSection, "left_format", m_img_dir_left_format));
600  m_img_dir_right_format = mrpt::system::trim(
601  configSource.read_string(iniSection, "right_format", ""));
602  m_img_dir_start_index =
603  configSource.read_int(iniSection, "start_index", m_img_dir_start_index);
604  ;
605  m_img_dir_end_index =
606  configSource.read_int(iniSection, "end_index", m_img_dir_end_index);
607 
608  m_img_dir_is_stereo = !m_img_dir_right_format.empty();
609  m_img_dir_counter = m_img_dir_start_index;
610 
611  // DUO3D Camera options:
612  m_duo3d_options.loadOptionsFrom(configSource, "DUO3DOptions");
613 
614  // SwissRanger options:
615  m_sr_open_from_usb =
616  configSource.read_bool(iniSection, "sr_use_usb", m_sr_open_from_usb);
617  m_sr_ip_address =
618  configSource.read_string(iniSection, "sr_IP", m_sr_ip_address);
619 
620  m_sr_save_3d =
621  configSource.read_bool(iniSection, "sr_grab_3d", m_sr_save_3d);
622  m_sr_save_intensity_img = configSource.read_bool(
623  iniSection, "sr_grab_grayscale", m_sr_save_intensity_img);
624  m_sr_save_range_img = configSource.read_bool(
625  iniSection, "sr_grab_range", m_sr_save_range_img);
626  m_sr_save_confidence = configSource.read_bool(
627  iniSection, "sr_grab_confidence", m_sr_save_confidence);
628 
629  m_kinect_save_3d =
630  configSource.read_bool(iniSection, "kinect_grab_3d", m_kinect_save_3d);
631  m_kinect_save_intensity_img = configSource.read_bool(
632  iniSection, "kinect_grab_intensity", m_kinect_save_intensity_img);
633  m_kinect_save_range_img = configSource.read_bool(
634  iniSection, "kinect_grab_range", m_kinect_save_range_img);
635  m_kinect_video_rgb = configSource.read_bool(
636  iniSection, "kinect_video_rgb", m_kinect_video_rgb);
637 
638  // FlyCap:
639  m_flycap_options.loadOptionsFrom(configSource, iniSection, "flycap_");
640 
641  // Myntd:
642  {
643  mrpt::config::CConfigFilePrefixer c(configSource, "", "myntd_");
644  m_myntd_options.loadFromConfigFile(c, iniSection);
645  }
646 
647  // FlyCap stereo
648  m_fcs_start_synch_capture = configSource.read_bool(
649  iniSection, "fcs_start_synch_capture", m_fcs_start_synch_capture);
650  m_flycap_stereo_options[0].loadOptionsFrom(
651  configSource, iniSection, "fcs_LEFT_");
652  m_flycap_stereo_options[1].loadOptionsFrom(
653  configSource, iniSection, "fcs_RIGHT_");
654 
655  // Special stuff: FPS
656  map<double, grabber_dc1394_framerate_t> map_fps;
657  map<double, grabber_dc1394_framerate_t>::iterator it_fps;
658  map_fps[1.875] = FRAMERATE_1_875;
659  map_fps[3.75] = FRAMERATE_3_75;
660  map_fps[7.5] = FRAMERATE_7_5;
661  map_fps[15] = FRAMERATE_15;
662  map_fps[30] = FRAMERATE_30;
663  map_fps[60] = FRAMERATE_60;
664  map_fps[120] = FRAMERATE_120;
665  map_fps[240] = FRAMERATE_240;
666 
667  // ... for dc1394
668  double the_fps =
669  configSource.read_double(iniSection, "dc1394_framerate", 15.0);
670  it_fps = map_fps.find(the_fps);
671  if (it_fps == map_fps.end())
673  "ERROR: DC1394 framerate seems to be not a valid number: %f",
674  the_fps);
675 
676  m_dc1394_options.framerate = it_fps->second;
677 
678  // Special stuff: color encoding:
679  map<string, grabber_dc1394_color_coding_t> map_color;
680  map<string, grabber_dc1394_color_coding_t>::iterator it_color;
681 #define ADD_COLOR_MAP(c) map_color[#c] = c;
688 
689  string the_color_coding =
691  iniSection, "dc1394_color_coding", "COLOR_CODING_YUV422"));
692  it_color = map_color.find(the_color_coding);
693  if (it_color == map_color.end())
695  "ERROR: Color coding seems not to be valid : '%s'",
696  the_color_coding.c_str());
697  m_dc1394_options.color_coding = it_color->second;
698 
699  m_external_images_format = mrpt::system::trim(configSource.read_string(
700  iniSection, "external_images_format", m_external_images_format));
701  m_external_images_jpeg_quality = configSource.read_int(
702  iniSection, "external_images_jpeg_quality",
703  m_external_images_jpeg_quality);
704  m_external_images_own_thread = configSource.read_bool(
705  iniSection, "external_images_own_thread", m_external_images_own_thread);
706  m_external_image_saver_count = configSource.read_int(
707  iniSection, "external_images_own_thread_count",
708  m_external_image_saver_count);
709 
710  // Sensor pose:
711  m_sensorPose.setFromValues(
712  configSource.read_float(iniSection, "pose_x", 0),
713  configSource.read_float(iniSection, "pose_y", 0),
714  configSource.read_float(iniSection, "pose_z", 0),
715  DEG2RAD(configSource.read_float(iniSection, "pose_yaw", 0)),
716  DEG2RAD(configSource.read_float(iniSection, "pose_pitch", 0)),
717  DEG2RAD(configSource.read_float(iniSection, "pose_roll", 0)));
718 }
719 
720 /* -----------------------------------------------------
721  Destructor
722  ----------------------------------------------------- */
724 {
725  close();
726 
727  m_preview_win1.reset();
728  m_preview_win2.reset();
729 }
730 /* -----------------------------------------------------
731  getNextFrame
732 ----------------------------------------------------- */
734 {
735  vector<CSerializable::Ptr> out_obs;
736  getNextFrame(out_obs);
737  return std::dynamic_pointer_cast<CObservation>(out_obs[0]);
738 }
739 
740 /* -----------------------------------------------------
741  getNextFrame
742 ----------------------------------------------------- */
743 void CCameraSensor::getNextFrame(vector<CSerializable::Ptr>& out_obs)
744 {
748  obs3D; // 3D range image, also with an intensity channel
749  CObservationIMU::Ptr obsIMU; // IMU observation grabbed by DUO3D cameras
750 
751  bool capture_ok = false;
752 
753  if (m_cap_cv)
754  {
755  obs = std::make_shared<CObservationImage>();
756  if (!m_cap_cv->getObservation(*obs))
757  { // Error
758  m_state = CGenericSensor::ssError;
759  THROW_EXCEPTION("Error grabbing image");
760  }
761  else
762  capture_ok = true;
763  }
764  else if (m_cap_dc1394)
765  {
766  obs = std::make_shared<CObservationImage>();
767  if (!m_cap_dc1394->getObservation(*obs))
768  { // Error
769  m_state = CGenericSensor::ssError;
770  THROW_EXCEPTION("Error grabbing image");
771  }
772  else
773  capture_ok = true;
774  }
775  else if (m_cap_swissranger)
776  {
777  obs3D = std::make_shared<CObservation3DRangeScan>();
778 
779  bool there_is_obs, hardware_error;
780  m_cap_swissranger->getNextObservation(
781  *obs3D, there_is_obs, hardware_error);
782 
783  if (!there_is_obs || hardware_error)
784  { // Error
785  m_state = CGenericSensor::ssError;
786  THROW_EXCEPTION("Error grabbing image from SwissRanger camera.");
787  }
788  else
789  capture_ok = true;
790  }
791  else if (m_cap_kinect)
792  {
793  obs3D = std::make_shared<CObservation3DRangeScan>();
794 
795  // Specially at start-up, there may be a delay grabbing so a few calls
796  // return false: add a timeout.
798  double max_timeout = 3.0; // seconds
799 
800  // If we have an "MRPT_CCAMERA_KINECT_TIMEOUT_MS" environment variable,
801  // use that timeout instead:
802  const char* envVal = getenv("MRPT_CCAMERA_KINECT_TIMEOUT_MS");
803  if (envVal) max_timeout = atoi(envVal) * 0.001;
804 
805  bool there_is_obs, hardware_error;
806  do
807  {
808  m_cap_kinect->getNextObservation(
809  *obs3D, there_is_obs, hardware_error);
810  if (!there_is_obs) std::this_thread::sleep_for(1ms);
811  } while (!there_is_obs && mrpt::system::timeDifference(
812  t0, mrpt::system::now()) < max_timeout);
813 
814  if (!there_is_obs || hardware_error)
815  { // Error
816  m_state = CGenericSensor::ssError;
817  THROW_EXCEPTION("Error grabbing image from Kinect camera.");
818  }
819  else
820  capture_ok = true;
821  }
822  else if (m_cap_openni2)
823  {
824  obs3D = std::make_shared<CObservation3DRangeScan>();
825  // Specially at start-up, there may be a delay grabbing so a few calls
826  // return false: add a timeout.
828  double max_timeout = 3.0; // seconds
829  bool there_is_obs, hardware_error;
830  do
831  {
832  m_cap_openni2->getNextObservation(
833  *obs3D, there_is_obs, hardware_error);
834  if (!there_is_obs) std::this_thread::sleep_for(1ms);
835  } while (!there_is_obs && mrpt::system::timeDifference(
836  t0, mrpt::system::now()) < max_timeout);
837 
838  if (!there_is_obs || hardware_error)
839  { // Error
840  m_state = CGenericSensor::ssError;
841  THROW_EXCEPTION("Error grabbing image from OpenNI2 camera.");
842  }
843  else
844  capture_ok = true;
845  }
846  else if (m_cap_bumblebee_dc1394)
847  {
848  stObs = std::make_shared<CObservationStereoImages>();
849  if (!m_cap_bumblebee_dc1394->getStereoObservation(*stObs))
850  {
851  m_state = CGenericSensor::ssError;
852  THROW_EXCEPTION("Error grabbing stereo images");
853  }
854  else
855  {
856  capture_ok = true;
857  }
858  }
859  else if (m_cap_svs)
860  {
861  stObs = std::make_shared<CObservationStereoImages>();
862 
863  if (!m_cap_svs->getStereoObservation(*stObs))
864  {
865  // Error
866  m_state = CGenericSensor::ssError;
867  THROW_EXCEPTION("Error grabbing disparity images");
868  }
869  else
870  capture_ok = true;
871  }
872  else if (m_cap_ffmpeg)
873  {
874  static bool anyGood = false;
876  if (!m_cap_ffmpeg->retrieveFrame(im))
877  { // Error
878  m_state = CGenericSensor::ssError;
879  if (!anyGood)
880  {
881  THROW_EXCEPTION("Error grabbing image");
882  }
883  else
884  {
886  2.0,
887  "ffmpeg capture driver: Failed to get frame (temporary "
888  "error or EOF?)");
889  capture_ok = true;
890  }
891  }
892  else
893  {
894  obs = std::make_shared<CObservationImage>();
895  obs->image = std::move(im);
896 
897  anyGood = true;
898  capture_ok = true;
899  }
900  }
901  else if (m_cap_image_dir)
902  {
903  if (m_img_dir_counter > m_img_dir_end_index)
904  {
905  m_state = CGenericSensor::ssError;
906  THROW_EXCEPTION("Reached end index.");
907  }
908 
909  std::string auxL = format(
910  "%s/%s", m_img_dir_url.c_str(), m_img_dir_left_format.c_str());
911  if (m_img_dir_is_stereo)
912  {
913  stObs = std::make_shared<CObservationStereoImages>();
914  if (!stObs->imageLeft.loadFromFile(
915  format(auxL.c_str(), m_img_dir_counter)))
916  {
917  m_state = CGenericSensor::ssError;
918  THROW_EXCEPTION("Error reading images from directory");
919  }
920  std::string auxR = format(
921  "%s/%s", m_img_dir_url.c_str(), m_img_dir_right_format.c_str());
922  if (!stObs->imageRight.loadFromFile(
923  format(auxR.c_str(), m_img_dir_counter++)))
924  {
925  m_state = CGenericSensor::ssError;
926  THROW_EXCEPTION("Error reading images from directory");
927  }
928  else
929  capture_ok = true;
930  }
931  else
932  {
933  // use only left image prefix
934  obs = std::make_shared<CObservationImage>();
935  if (!obs->image.loadFromFile(
936  format(auxL.c_str(), m_img_dir_counter++)))
937  {
938  m_state = CGenericSensor::ssError;
939  THROW_EXCEPTION("Error reading images from directory");
940  }
941  else
942  capture_ok = true;
943  }
944  }
945  else if (m_cap_rawlog)
946  {
947  // Read in a loop until we found at least one image:
948  // Assign to: obs && stObs
949  CSerializable::Ptr newObs;
950  while (!obs && !stObs && !obs3D)
951  {
952  archiveFrom(*m_cap_rawlog) >> newObs;
953  if (IS_DERIVED(*newObs, CObservation))
954  {
956  std::dynamic_pointer_cast<CObservation>(newObs);
957  if (!m_rawlog_camera_sensor_label.empty() &&
958  m_rawlog_camera_sensor_label != o->sensorLabel)
959  continue;
960 
961  if (IS_CLASS(*o, CObservationImage))
962  obs = std::dynamic_pointer_cast<CObservationImage>(o);
963  else if (IS_CLASS(*o, CObservationStereoImages))
964  stObs =
965  std::dynamic_pointer_cast<CObservationStereoImages>(o);
966  else if (IS_CLASS(*o, CObservation3DRangeScan))
967  obs3D =
968  std::dynamic_pointer_cast<CObservation3DRangeScan>(o);
969  }
970  else if (IS_CLASS(*newObs, CSensoryFrame))
971  {
972  CSensoryFrame::Ptr sf =
973  std::dynamic_pointer_cast<CSensoryFrame>(newObs);
974 
975  for (auto& o : *sf)
976  {
977  if (!m_rawlog_camera_sensor_label.empty() &&
978  m_rawlog_camera_sensor_label != o->sensorLabel)
979  continue;
980 
981  if (IS_CLASS(*o, CObservationImage))
982  {
983  obs = std::dynamic_pointer_cast<CObservationImage>(o);
984  break;
985  }
986  else if (IS_CLASS(*o, CObservationStereoImages))
987  {
988  stObs =
989  std::dynamic_pointer_cast<CObservationStereoImages>(
990  o);
991  break;
992  }
993  else if (IS_CLASS(*o, CObservation3DRangeScan))
994  {
995  obs3D =
996  std::dynamic_pointer_cast<CObservation3DRangeScan>(
997  o);
998  break;
999  }
1000  }
1001  }
1002  if (obs || stObs || obs3D)
1003  {
1004  // We must convert externally stored images into "normal
1005  // in-memory" images.
1006  const std::string old_dir =
1007  CImage::getImagesPathBase(); // Save current
1008  CImage::setImagesPathBase(m_rawlog_detected_images_dir);
1009 
1010  if (obs && obs->image.isExternallyStored())
1011  obs->image.loadFromFile(
1012  obs->image.getExternalStorageFileAbsolutePath());
1013 
1014  if (obs3D && obs3D->hasIntensityImage &&
1015  obs3D->intensityImage.isExternallyStored())
1016  obs3D->intensityImage.loadFromFile(
1017  obs3D->intensityImage
1018  .getExternalStorageFileAbsolutePath());
1019 
1020  if (stObs && stObs->imageLeft.isExternallyStored())
1021  stObs->imageLeft.loadFromFile(
1022  stObs->imageLeft.getExternalStorageFileAbsolutePath());
1023 
1024  if (stObs && stObs->hasImageRight &&
1025  stObs->imageRight.isExternallyStored())
1026  stObs->imageRight.loadFromFile(
1027  stObs->imageRight.getExternalStorageFileAbsolutePath());
1028 
1029  if (stObs && stObs->hasImageDisparity &&
1030  stObs->imageDisparity.isExternallyStored())
1031  stObs->imageDisparity.loadFromFile(
1032  stObs->imageDisparity
1033  .getExternalStorageFileAbsolutePath());
1034 
1035  CImage::setImagesPathBase(old_dir); // Restore
1036  }
1037  else
1038  continue; // Keep reading
1039  }
1040  capture_ok = true;
1041  }
1042  else if (m_cap_flycap)
1043  {
1044  bool ok;
1045  if (!m_cap_flycap->isStereo()) // Mono image
1046  {
1047  obs = std::make_shared<CObservationImage>();
1048  ok = m_cap_flycap->getObservation(*obs);
1049  }
1050  else // Stereo camera connected
1051  {
1052  stObs = std::make_shared<CObservationStereoImages>();
1053  ok = m_cap_flycap->getObservation(*stObs);
1054  }
1055 
1056  if (!ok)
1057  { // Error
1058  m_state = CGenericSensor::ssError;
1059  THROW_EXCEPTION("Error grabbing image");
1060  }
1061  else
1062  capture_ok = true;
1063  }
1064  else if (m_cap_flycap_stereo_l && m_cap_flycap_stereo_r)
1065  {
1066  stObs = std::make_shared<CObservationStereoImages>();
1067 
1068  CObservationImage obsL, obsR;
1069 
1070  bool ok1, ok2 = false;
1071 
1072  ok1 = m_cap_flycap_stereo_r->getObservation(obsL);
1073  if (ok1) ok2 = m_cap_flycap_stereo_l->getObservation(obsR);
1074 
1075  if (!ok1 || !ok2)
1076  {
1077  // Error
1078  m_state = CGenericSensor::ssError;
1079  THROW_EXCEPTION("Error grabbing disparity images");
1080  }
1081  else
1082  {
1083  // Joint the two images as one stereo:
1084  const double At =
1085  mrpt::system::timeDifference(obsL.timestamp, obsR.timestamp);
1086  if (std::abs(At) > 0.1)
1087  {
1088  cout << "[CCamera, flycap_stereo] Warning: Too large delay "
1089  "between left & right images: "
1090  << At << " sec.\n";
1091  }
1092 
1093  // It seems that the timestamp is not always filled in from FlyCap
1094  // driver?
1095  stObs->timestamp = (obsL.timestamp != INVALID_TIMESTAMP)
1096  ? obsL.timestamp
1097  : mrpt::system::now();
1098  stObs->imageLeft = std::move(obsL.image);
1099  stObs->imageRight = std::move(obsR.image);
1100  capture_ok = true;
1101  }
1102  }
1103  else if (m_cap_duo3d)
1104  {
1105  stObs = std::make_shared<CObservationStereoImages>();
1106  obsIMU = std::make_shared<CObservationIMU>();
1107 
1108  bool thereIsIMG, thereIsIMU;
1109  m_cap_duo3d->getObservations(*stObs, *obsIMU, thereIsIMG, thereIsIMU);
1110  if (!thereIsIMG)
1111  {
1112  m_state = CGenericSensor::ssError;
1113  THROW_EXCEPTION("Error getting observations from DUO3D camera.");
1114  }
1115  else if (m_cap_duo3d->captureIMUIsSet() && !thereIsIMU)
1116  {
1117  cout << "[CCamera, duo3d] Warning: There are no IMU data from the "
1118  "device. Only images are being grabbed.";
1119  }
1120  capture_ok = true;
1121  }
1122  else if (m_myntd)
1123  {
1124  obs3D = std::make_shared<CObservation3DRangeScan>();
1125 
1126  bool thereIsObs = m_myntd->getObservation(*obs3D);
1127  static int noObsCnt = 0;
1128 
1129  if (!thereIsObs)
1130  {
1131  // obs3D.reset();
1132  if (noObsCnt++ > 100)
1133  {
1134  m_state = CGenericSensor::ssError;
1136  "Error getting observations from MYNTEYE-D camera.");
1137  }
1138  }
1139  else
1140  {
1141  noObsCnt = 0;
1142  }
1143  capture_ok = true;
1144  }
1145  else
1146  {
1148  "There is no initialized camera driver: has 'initialize()' been "
1149  "called?");
1150  }
1151 
1152  ASSERT_(capture_ok);
1153 
1154  // Are we supposed to do a decimation??
1155  m_camera_grab_decimator_counter++;
1156  if (m_camera_grab_decimator_counter < m_camera_grab_decimator)
1157  {
1158  // Done here:
1159  out_obs.push_back(CObservation::Ptr());
1160  return;
1161  }
1162  // Continue as normal:
1163  m_camera_grab_decimator_counter = 0;
1164 
1165  // Allow temporary failures to get any frame
1166  // ASSERT_(obs || stObs || obs3D || obsIMU);
1167 
1168  // If we grabbed an image: prepare it and add it to the internal queue:
1169  if (obs)
1170  {
1171  obs->sensorLabel = m_sensorLabel;
1172  obs->setSensorPose(m_sensorPose);
1173  }
1174  else if (stObs)
1175  {
1176  stObs->sensorLabel = (m_cap_duo3d && m_cap_duo3d->captureIMUIsSet())
1177  ? m_sensorLabel + "_IMG"
1178  : m_sensorLabel;
1179  stObs->setSensorPose(m_sensorPose);
1180  }
1181  else if (obs3D)
1182  {
1183  obs3D->sensorLabel = m_sensorLabel;
1184  obs3D->setSensorPose(m_sensorPose);
1185  }
1186  if (obsIMU)
1187  {
1188  obsIMU->sensorLabel = m_sensorLabel + "_IMU";
1189  obsIMU->setSensorPose(m_sensorPose);
1190  }
1191 
1192  // Convert to grayscale if the user wants so and the driver did ignored us:
1193  if (m_capture_grayscale)
1194  {
1195  if (obs)
1196  {
1197  if (obs->image.isColor()) obs->image = obs->image.grayscale();
1198  }
1199  else if (stObs)
1200  {
1201  if (stObs->imageLeft.isColor())
1202  stObs->imageLeft = stObs->imageLeft.grayscale();
1203  if (stObs->hasImageRight && stObs->imageRight.isColor())
1204  stObs->imageRight = stObs->imageRight.grayscale();
1205  if (stObs->hasImageDisparity && stObs->imageDisparity.isColor())
1206  stObs->imageDisparity = stObs->imageDisparity.grayscale();
1207  }
1208  else if (obs3D)
1209  {
1210  if (obs3D->hasIntensityImage && obs3D->intensityImage.isColor())
1211  obs3D->intensityImage = obs3D->intensityImage.grayscale();
1212  }
1213  }
1214 
1215  // Before saving to disk, keep a copy for display, if needed:
1216  CImage img4gui, img4guiR;
1217  if (m_preview_win1 && m_preview_win1->isOpen())
1218  {
1219  if (stObs)
1220  {
1221  img4gui = stObs->imageLeft.makeDeepCopy();
1222  img4guiR = stObs->imageRight.makeDeepCopy();
1223  }
1224  else if (obs)
1225  img4gui = obs->image.makeDeepCopy();
1226  else
1227  img4gui = obs3D->intensityImage.makeDeepCopy();
1228  }
1229 
1230  // External storage?
1231  // If true, we'll return nothing, but the observation will be
1232  // inserted from the thread.
1233  bool delayed_insertion_in_obs_queue = false;
1234  if (!m_path_for_external_images.empty())
1235  {
1236  if (stObs) // If we have grabbed an stereo observation ...
1237  { // Stereo obs -------
1238  if (m_external_images_own_thread)
1239  {
1240  m_csToSaveList.lock();
1241 
1242  // Select the "m_toSaveList" with the shortest pending queue:
1243  size_t idx_min = 0;
1244  for (size_t i = 0; i < m_toSaveList.size(); ++i)
1245  if (m_toSaveList[i].size() < m_toSaveList[idx_min].size())
1246  idx_min = i;
1247  // Insert:
1248  m_toSaveList[idx_min].insert(
1249  TListObsPair(stObs->timestamp, stObs));
1250 
1251  m_csToSaveList.unlock();
1252 
1253  delayed_insertion_in_obs_queue = true;
1254  }
1255  else
1256  {
1257  const string filNameL =
1258  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1259  format(
1260  "_L_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1261  m_external_images_format.c_str());
1262  const string filNameR =
1263  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1264  format(
1265  "_R_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1266  m_external_images_format.c_str());
1267  const string filNameD =
1268  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1269  format(
1270  "_D_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1271  m_external_images_format.c_str());
1272  // cout << "[CCameraSensor] Saving " << filName << endl;
1273  stObs->imageLeft.saveToFile(
1274  m_path_for_external_images + string("/") + filNameL,
1275  m_external_images_jpeg_quality);
1276  stObs->imageLeft.setExternalStorage(filNameL);
1277 
1278  if (stObs->hasImageRight)
1279  {
1280  stObs->imageRight.saveToFile(
1281  m_path_for_external_images + string("/") + filNameR,
1282  m_external_images_jpeg_quality);
1283  stObs->imageRight.setExternalStorage(filNameR);
1284  }
1285  if (stObs->hasImageDisparity)
1286  {
1287  stObs->imageDisparity.saveToFile(
1288  m_path_for_external_images + string("/") + filNameD,
1289  m_external_images_jpeg_quality);
1290  stObs->imageDisparity.setExternalStorage(filNameD);
1291  }
1292  }
1293  }
1294  else if (obs)
1295  { // Monocular image obs -------
1296  if (m_external_images_own_thread)
1297  {
1298  m_csToSaveList.lock();
1299 
1300  // Select the "m_toSaveList" with the shortest pending queue:
1301  size_t idx_min = 0;
1302  for (size_t i = 0; i < m_toSaveList.size(); ++i)
1303  if (m_toSaveList[i].size() < m_toSaveList[idx_min].size())
1304  idx_min = i;
1305 
1306  // Insert:
1307  m_toSaveList[idx_min].insert(TListObsPair(obs->timestamp, obs));
1308 
1309  m_csToSaveList.unlock();
1310  delayed_insertion_in_obs_queue = true;
1311  }
1312  else
1313  {
1314  string filName =
1315  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1316  format(
1317  "_%f.%s", (double)timestampTotime_t(obs->timestamp),
1318  m_external_images_format.c_str());
1319  // cout << "[CCameraSensor] Saving " << filName << endl;
1320  obs->image.saveToFile(
1321  m_path_for_external_images + string("/") + filName,
1322  m_external_images_jpeg_quality);
1323  obs->image.setExternalStorage(filName);
1324  }
1325  } // end else
1326  }
1327 
1328  // Show preview??
1329  if (m_preview_decimation > 0)
1330  { // Yes
1331  if (++m_preview_counter > m_preview_decimation)
1332  {
1333  m_preview_counter = 0;
1334 
1335  // Create window the first time:
1336  if (!m_preview_win1)
1337  {
1338  string caption = string("Preview of ") + m_sensorLabel;
1339  if (stObs) caption += "-LEFT";
1340  if (m_preview_decimation > 1)
1341  caption +=
1342  format(" (decimation: %i)", m_preview_decimation);
1343  m_preview_win1 = mrpt::gui::CDisplayWindow::Create(caption);
1344  }
1345  if (stObs && !m_preview_win2)
1346  {
1347  string caption = string("Preview of ") + m_sensorLabel;
1348  if (stObs) caption += "-RIGHT";
1349  if (m_preview_decimation > 1)
1350  caption +=
1351  format(" (decimation: %i)", m_preview_decimation);
1352  m_preview_win2 = mrpt::gui::CDisplayWindow::Create(caption);
1353  }
1354  // Monocular image or Left from a stereo pair:
1355  if (m_preview_win1->isOpen() && img4gui.getWidth() > 0)
1356  {
1357  // Apply image reduction?
1358  if (m_preview_reduction >= 2)
1359  {
1360  unsigned int w = img4gui.getWidth();
1361  unsigned int h = img4gui.getHeight();
1362  CImage auxImg;
1363  img4gui.scaleImage(
1364  auxImg, w / m_preview_reduction,
1365  h / m_preview_reduction, IMG_INTERP_NN);
1366  m_preview_win1->showImage(auxImg);
1367  }
1368  else
1369  m_preview_win1->showImage(img4gui);
1370  }
1371 
1372  // Right from a stereo pair:
1373  if (m_preview_win2 && m_preview_win2->isOpen() && stObs &&
1374  stObs->hasImageRight && img4gui.getWidth() > 0)
1375  {
1376  // Apply image reduction?
1377  if (m_preview_reduction >= 2)
1378  {
1379  unsigned int w = img4guiR.getWidth();
1380  unsigned int h = img4guiR.getHeight();
1381  CImage auxImg;
1382  img4guiR.scaleImage(
1383  auxImg, w / m_preview_reduction,
1384  h / m_preview_reduction, IMG_INTERP_NN);
1385  m_preview_win2->showImage(auxImg);
1386  }
1387  else
1388  m_preview_win2->showImage(img4guiR);
1389  }
1390 
1391  // Disparity from a stereo pair:
1392  if (m_preview_win2 && m_preview_win2->isOpen() && stObs &&
1393  stObs->hasImageDisparity)
1394  {
1395  // Apply image reduction?
1396  if (m_preview_reduction >= 2)
1397  {
1398  unsigned int w = stObs->imageDisparity.getWidth();
1399  unsigned int h = stObs->imageDisparity.getHeight();
1400  CImage auxImg;
1401  stObs->imageDisparity.scaleImage(
1402  auxImg, w / m_preview_reduction,
1403  h / m_preview_reduction, IMG_INTERP_NN);
1404  m_preview_win2->showImage(auxImg);
1405  }
1406  else
1407  m_preview_win2->showImage(stObs->imageDisparity);
1408  }
1409  }
1410  } // end show preview
1411 
1412  if (delayed_insertion_in_obs_queue)
1413  {
1414  if (m_cap_duo3d && m_cap_duo3d->captureIMUIsSet() && obsIMU)
1415  out_obs.push_back(CObservation::Ptr(obsIMU));
1416  }
1417  else
1418  {
1419  if (stObs) out_obs.push_back(CObservation::Ptr(stObs));
1420  if (obs) out_obs.push_back(CObservation::Ptr(obs));
1421  if (obs3D) out_obs.push_back(CObservation::Ptr(obs3D));
1422  }
1423  return;
1424 }
1425 
1426 /* -----------------------------------------------------
1427  doProcess
1428 ----------------------------------------------------- */
1430 {
1431  vector<CSerializable::Ptr> out_obs;
1432  getNextFrame(out_obs);
1433  appendObservations(out_obs);
1434 }
1435 
1436 /* -----------------------------------------------------
1437  setSoftwareTriggerLevel
1438 ----------------------------------------------------- */
1440 {
1441  if (m_cap_dc1394)
1442  {
1443  if (!m_cap_dc1394->setSoftwareTriggerLevel(level))
1444  { // Error
1445  m_state = CGenericSensor::ssError;
1446  THROW_EXCEPTION("Error setting Trigger level by software");
1447  }
1448  }
1449  else
1450  {
1452  "Software trigger is not implemented for this camera type");
1453  }
1454 }
1455 
1456 /* -----------------------------------------------------
1457  setPathForExternalImages
1458 ----------------------------------------------------- */
1459 void CCameraSensor::setPathForExternalImages(const std::string& directory)
1460 {
1461  if (!mrpt::system::createDirectory(directory))
1462  {
1464  "Cannot create the directory for externally saved images: `%s`",
1465  directory.c_str());
1466  }
1467  m_path_for_external_images = directory;
1468 }
1469 
1470 /* ------------------------------------------------------------------------
1471  prepareVideoSourceFromUserSelection
1472  ------------------------------------------------------------------------ */
1474 {
1475 #if MRPT_HAS_WXWIDGETS
1476  // Create the main wxThread, if it doesn't exist yet:
1478  {
1479  std::cerr << "[mrpt::hwdrivers::prepareVideoSourceFromUserSelection] "
1480  "Error initiating Wx subsystem."
1481  << std::endl;
1482  return CCameraSensor::Ptr(); // Error!
1483  }
1484 
1485  std::promise<void> semDlg;
1486  std::promise<mrpt::gui::detail::TReturnAskUserOpenCamera> dlgSelection;
1487 
1488  // Create window:
1489  auto* REQ = new WxSubsystem::TRequestToWxMainThread[1];
1490  REQ->OPCODE = 700;
1491  REQ->sourceCameraSelectDialog = true;
1492  REQ->voidPtr = reinterpret_cast<void*>(&semDlg);
1493  REQ->voidPtr2 = reinterpret_cast<void*>(&dlgSelection);
1494  WxSubsystem::pushPendingWxRequest(REQ);
1495 
1496  // Wait for the window to realize and signal it's alive:
1497  if (!WxSubsystem::isConsoleApp())
1498  {
1499  std::this_thread::sleep_for(
1500  20ms); // Force at least 1-2 timer ticks for processing the event:
1501  wxApp::GetInstance()->Yield(true);
1502  }
1503 
1504  // wait for window construction:
1505  int maxTimeout =
1506 #ifdef _DEBUG
1507  30000;
1508 #else
1509  6000;
1510 #endif
1511  // If we have an "MRPT_WXSUBSYS_TIMEOUT_MS" environment variable, use that
1512  // timeout instead:
1513  const char* envVal = getenv("MRPT_WXSUBSYS_TIMEOUT_MS");
1514  if (envVal) maxTimeout = atoi(envVal);
1515 
1516  if (semDlg.get_future().wait_for(std::chrono::milliseconds(maxTimeout)) ==
1517  std::future_status::timeout)
1518  {
1519  cerr << "[prepareVideoSourceFromUserSelection] Timeout waiting window "
1520  "creation."
1521  << endl;
1522  return CCameraSensor::Ptr();
1523  }
1524 
1525  // wait for user selection:
1526  auto future = dlgSelection.get_future();
1527  future.wait();
1528  const auto& ret = future.get();
1529 
1530  // If the user didn't accept the dialog, return now:
1531  if (!ret.accepted_by_user) return CCameraSensor::Ptr();
1532 
1533  mrpt::config::CConfigFileMemory selectedConfig(ret.selectedConfig);
1534 
1535  CCameraSensor::Ptr cam = std::make_shared<CCameraSensor>();
1536  cam->loadConfig(selectedConfig, "CONFIG");
1537  cam->initialize(); // This will raise an exception if neccesary
1538 
1539  return cam;
1540 #else
1541  THROW_EXCEPTION("MRPT compiled without wxWidgets");
1542 #endif // MRPT_HAS_WXWIDGETS
1543 }
1544 
1545 /* ------------------------------------------------------------------------
1546  prepareVideoSourceFromPanel
1547  ------------------------------------------------------------------------ */
1549 {
1550 #if MRPT_HAS_WXWIDGETS
1551 
1552  try
1553  {
1554  CConfigFileMemory cfg;
1555  writeConfigFromVideoSourcePanel(_panel, "CONFIG", &cfg);
1556 
1557  // Try to open the camera:
1558  CCameraSensor::Ptr video = std::make_shared<CCameraSensor>();
1559  video->loadConfig(cfg, "CONFIG");
1560 
1561  // This will raise an exception if neccesary
1562  video->initialize();
1563 
1564  return video;
1565  }
1566  catch (const std::exception& e)
1567  {
1568  cerr << endl << e.what() << endl;
1569  wxMessageBox(_("Couldn't open video source"), _("Error"));
1570  return CCameraSensor::Ptr();
1571  }
1572 #else
1573  THROW_EXCEPTION("MRPT compiled without wxWidgets");
1574 #endif // MRPT_HAS_WXWIDGETS
1575 }
1576 
1577 /* ------------------------------------------------------------------------
1578  writeConfigFromVideoSourcePanel
1579  ------------------------------------------------------------------------ */
1581  void* _panel, const std::string& sect, mrpt::config::CConfigFileBase* cfg)
1582 {
1583  MRPT_START
1584 #if MRPT_HAS_WXWIDGETS
1585  ASSERT_(_panel);
1586  auto* panel = reinterpret_cast<mrpt::gui::CPanelCameraSelection*>(_panel);
1587  ASSERTMSG_(
1588  panel, "panel must be of type mrpt::gui::CPanelCameraSelection *");
1589  panel->writeConfigFromVideoSourcePanel(sect, cfg);
1590 
1591 #else
1592  THROW_EXCEPTION("MRPT compiled without wxWidgets");
1593 #endif // MRPT_HAS_WXWIDGETS
1594  MRPT_END
1595 }
1596 
1597 /* ------------------------------------------------------------------------
1598  readConfigIntoVideoSourcePanel
1599  ------------------------------------------------------------------------ */
1601  void* _panel, const std::string& sect,
1602  const mrpt::config::CConfigFileBase* cfg)
1603 {
1604  MRPT_START
1605 #if MRPT_HAS_WXWIDGETS
1606  ASSERT_(_panel);
1607  auto* panel = reinterpret_cast<mrpt::gui::CPanelCameraSelection*>(_panel);
1608  ASSERTMSG_(
1609  panel, "panel must be of type mrpt::gui::CPanelCameraSelection *");
1610 
1611  panel->readConfigIntoVideoSourcePanel(sect, cfg);
1612 
1613 #else
1614  THROW_EXCEPTION("MRPT compiled without wxWidgets");
1615 #endif // MRPT_HAS_WXWIDGETS
1616  MRPT_END
1617 }
1618 
1619 /* -----------------------------------------------------
1620  THREAD: Saver of external images
1621  ----------------------------------------------------- */
1622 void CCameraSensor::thread_save_images(unsigned int my_working_thread_index)
1623 {
1624  while (!m_threadImagesSaverShouldEnd)
1625  {
1626  TListObservations newObs;
1627 
1628  // is there any new image?
1629  m_csToSaveList.lock();
1630  m_toSaveList[my_working_thread_index].swap(newObs);
1631  m_csToSaveList.unlock();
1632 
1633  for (auto i = newObs.begin(); i != newObs.end(); ++i)
1634  {
1635  // Optional user-code hook:
1636  if (m_hook_pre_save)
1637  {
1638  if (IS_DERIVED(*i->second, CObservation))
1639  {
1641  std::dynamic_pointer_cast<mrpt::obs::CObservation>(
1642  i->second);
1643  m_hook_pre_save(obs, m_hook_pre_save_param);
1644  }
1645  }
1646 
1647  if (IS_CLASS(*i->second, CObservationImage))
1648  {
1650  std::dynamic_pointer_cast<CObservationImage>(i->second);
1651 
1652  string filName =
1653  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1654  format(
1655  "_%f.%s", (double)timestampTotime_t(obs->timestamp),
1656  m_external_images_format.c_str());
1657 
1658  obs->image.saveToFile(
1659  m_path_for_external_images + string("/") + filName,
1660  m_external_images_jpeg_quality);
1661  obs->image.setExternalStorage(filName);
1662  }
1663  else if (IS_CLASS(*i->second, CObservationStereoImages))
1664  {
1666  std::dynamic_pointer_cast<CObservationStereoImages>(
1667  i->second);
1668 
1669  const string filNameL =
1670  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1671  format(
1672  "_L_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1673  m_external_images_format.c_str());
1674  const string filNameR =
1675  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1676  format(
1677  "_R_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1678  m_external_images_format.c_str());
1679  const string filNameD =
1680  fileNameStripInvalidChars(trim(m_sensorLabel)) +
1681  format(
1682  "_D_%f.%s", (double)timestampTotime_t(stObs->timestamp),
1683  m_external_images_format.c_str());
1684 
1685  stObs->imageLeft.saveToFile(
1686  m_path_for_external_images + string("/") + filNameL,
1687  m_external_images_jpeg_quality);
1688  stObs->imageLeft.setExternalStorage(filNameL);
1689 
1690  if (stObs->hasImageRight)
1691  {
1692  stObs->imageRight.saveToFile(
1693  m_path_for_external_images + string("/") + filNameR,
1694  m_external_images_jpeg_quality);
1695  stObs->imageRight.setExternalStorage(filNameR);
1696  }
1697  if (stObs->hasImageDisparity)
1698  {
1699  stObs->imageDisparity.saveToFile(
1700  m_path_for_external_images + string("/") + filNameD,
1701  m_external_images_jpeg_quality);
1702  stObs->imageDisparity.setExternalStorage(filNameD);
1703  }
1704  }
1705 
1706  // Append now:
1707  appendObservation(i->second);
1708  }
1709 
1710  std::this_thread::sleep_for(2ms);
1711  }
1712 }
This class implements a config file-like interface over a memory-stored string list.
#define ADD_COLOR_MAP(c)
Declares a class derived from "CObservation" that encapsules an image from a camera, whose relative pose to robot is also stored.
bool createDirectory(const std::string &dirName)
Creates a directory.
Definition: filesystem.cpp:161
#define MRPT_START
Definition: exceptions.h:241
TCameraType
These capture types are like their OpenCV equivalents.
std::string read_string(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
The data structure for each inter-thread request:
Definition: WxSubsystem.h:189
static ENUMTYPE name2value(const std::string &name)
Gives the numerical name for a given enum text name.
Definition: TEnumType.h:100
CCameraSensor::Ptr prepareVideoSourceFromUserSelection()
Show to the user a list of possible camera drivers and creates and open the selected camera...
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:67
std::string std::string format(std::string_view fmt, ARGS &&... args)
Definition: format.h:26
size_t size(const MATRIXLIKE &m, const int dim)
A wrapper for Point Gray Research (PGR) FlyCapture2 API for capturing images from Firewire...
std::pair< mrpt::system::TTimeStamp, mrpt::serialization::CSerializable::Ptr > TListObsPair
void loadConfig_sensorSpecific(const mrpt::config::CConfigFileBase &configSource, const std::string &iniSection) override
See the class documentation at the top for expected parameters.
A range or depth 3D scan measurement, as from a time-of-flight range camera or a structured-light dep...
mrpt::system::TTimeStamp now()
A shortcut for system::getCurrentTime.
Definition: datetime.h:86
Contains classes for various device interfaces.
size_t getHeight() const override
Returns the height of the image in pixels.
Definition: CImage.cpp:855
void readConfigIntoVideoSourcePanel(void *panel, const std::string &in_cfgfile_section_name, const mrpt::config::CConfigFileBase *in_cfgfile)
Parse the given section of the given configuration file and set accordingly the controls of the wxWid...
void scaleImage(CImage &out_img, unsigned int width, unsigned int height, TInterpolationMethod interp=IMG_INTERP_CUBIC) const
Scales this image to a new size, interpolating as needed, saving the new image in a different output ...
Definition: CImage.cpp:1747
void doProcess() override
This method will be invoked at a minimum rate of "process_rate" (Hz)
float read_float(const std::string &section, const std::string &name, float defaultValue, bool failIfNotFound=false) const
STL namespace.
std::string fileNameStripInvalidChars(const std::string &filename, const char replacement_to_invalid_chars='_')
Replace invalid filename chars by underscores (&#39;_&#39;) or any other user-given char. ...
Definition: filesystem.cpp:329
void thread_name(const std::string &name, std::thread &theThread)
Sets the name of the given thread; useful for debuggers.
Definition: thread_name.cpp:63
~CCameraSensor() override
Destructor.
int OPCODE
Valid codes are: For CDisplayWindow:
Definition: WxSubsystem.h:283
void writeConfigFromVideoSourcePanel(void *panel, const std::string &in_cfgfile_section_name, mrpt::config::CConfigFileBase *out_cfgfile)
Parse the user options in the wxWidgets "panel" and write the configuration into the given section of...
int read_int(const std::string &section, const std::string &name, int defaultValue, bool failIfNotFound=false) const
CArchiveStreamBase< STREAM > archiveFrom(STREAM &s)
Helper function to create a templatized wrapper CArchive object for a: MRPT&#39;s CStream, std::istream, std::ostream, std::stringstream.
Definition: CArchive.h:592
void thread_save_images(unsigned int my_working_thread_index)
Thread to save images to files.
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:120
mrpt::Clock::time_point TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:40
This class allows loading and storing values and vectors of different types from a configuration text...
void close()
Close the camera (if open).
size_t getWidth() const override
Returns the width of the image in pixels.
Definition: CImage.cpp:818
The central class for camera grabbers in MRPT, implementing the "generic sensor" interface.
std::string lowerCase(const std::string &str)
Returns an lower-case version of a string.
std::shared_ptr< CCameraSensor > Ptr
constexpr double DEG2RAD(const double x)
Degrees to radians.
Versatile class for consistent logging and management of output messages.
double timestampTotime_t(const mrpt::system::TTimeStamp t) noexcept
Transform from TTimeStamp to standard "time_t" (actually a double number, it can contain fractions of...
Definition: datetime.h:105
#define IS_DERIVED(obj, class_name)
True if the given reference to object (derived from mrpt::rtti::CObject) is an instance of the given ...
Definition: CObject.h:151
Observation class for either a pair of left+right or left+disparity images from a stereo camera...
This namespace contains representation of robot actions and observations.
Declares a class for storing a "sensory frame", a set of "observations" taken by the robot approximat...
Definition: CSensoryFrame.h:51
static std::string & trim(std::string &s)
std::string read_string_first_word(const std::string &section, const std::string &name, const std::string &defaultValue, bool failIfNotFound=false) const
Reads a configuration parameter of type "string", and keeps only the first word (this can be used to ...
#define IS_CLASS(obj, class_name)
True if the given reference to object (derived from mrpt::rtti::CObject) is of the given class...
Definition: CObject.h:146
constexpr auto sect
#define ASSERTMSG_(f, __ERROR_MSG)
Defines an assertion mechanism.
Definition: exceptions.h:108
A wrapper for other CConfigFileBase-based objects that prefixes a given token to every key and/or sec...
double read_double(const std::string &section, const std::string &name, double defaultValue, bool failIfNotFound=false) const
#define IMPLEMENTS_GENERIC_SENSOR(class_name, NameSpace)
This must be inserted in all CGenericSensor classes implementation files:
static void startSyncCapture(int numCameras, const CImageGrabber_FlyCapture2 **cameras_array)
Starts a synchronous capture of several cameras, which must have been already opened.
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
void initialize() override
Tries to open the camera, after setting all the parameters with a call to loadConfig.
std::multimap< mrpt::system::TTimeStamp, mrpt::serialization::CSerializable::Ptr > TListObservations
Declares a class that represents any robot&#39;s observation.
Definition: CObservation.h:43
bool read_bool(const std::string &section, const std::string &name, bool defaultValue, bool failIfNotFound=false) const
std::string upperCase(const std::string &str)
Returns a upper-case version of a string.
#define MRPT_END
Definition: exceptions.h:245
mrpt::obs::CObservation::Ptr getNextFrame()
Retrieves the next frame from the video source, raising an exception on any error.
void setSoftwareTriggerLevel(bool level)
Set Software trigger level value (ON or OFF) for cameras with this function available.
A panel to select the camera input from all the formats supported by MRPT.
Definition: WxUtils.h:154
#define MRPT_LOAD_HERE_CONFIG_VAR( variableName, variableType, targetVariable, configFileObject, sectionNameStr)
std::string trim(const std::string &str)
Removes leading and trailing spaces.
Classes for creating GUI windows for 2D and 3D visualization.
Definition: about_box.h:14
static CDisplayWindow::Ptr Create(const std::string &windowCaption, unsigned int initWidth=400, unsigned int initHeight=400)
Class factory returning a smart pointer.
double timeDifference(const mrpt::system::TTimeStamp t_first, const mrpt::system::TTimeStamp t_later)
Returns the time difference from t1 to t2 (positive if t2 is posterior to t1), in seconds...
Definition: datetime.h:123
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:69
void setPathForExternalImages(const std::string &directory) override
Set the path where to save off-rawlog image files (this class DOES take into account this path)...
#define MRPT_LOG_THROTTLE_WARN(_PERIOD_SECONDS, _STRING)
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Definition: datetime.h:43
static bool createOneInstanceMainThread()
Thread-safe method to create one single instance of the main wxWidgets thread: it will create the thr...
CCameraSensor::Ptr prepareVideoSourceFromPanel(void *panel)
Used only from MRPT apps: Use with caution since "panel" MUST be a "mrpt::gui::CPanelCameraSelection ...
A class for storing images as grayscale or RGB bitmaps.
Definition: img/CImage.h:148



Page generated by Doxygen 1.8.14 for MRPT 2.0.4 Git: 33de1d0ad Sat Jun 20 11:02:42 2020 +0200 at sáb jun 20 17:35:17 CEST 2020