gc_pointcloud.cc
Go to the documentation of this file.
1 /*
2  * This file is part of the rc_genicam_api package.
3  *
4  * Copyright (c) 2017 Roboception GmbH
5  * All rights reserved
6  *
7  * Author: Heiko Hirschmueller
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include <rc_genicam_api/system.h>
38 #include <rc_genicam_api/device.h>
39 #include <rc_genicam_api/stream.h>
40 #include <rc_genicam_api/buffer.h>
41 #include <rc_genicam_api/image.h>
44 #include <rc_genicam_api/config.h>
45 
47 
48 #include <Base/GCException.h>
49 
50 namespace
51 {
52 
53 /*
54  Print help text on standard output.
55 */
56 
57 void printHelp(const char *prgname)
58 {
59  // show help
60 
61  std::cout << prgname << " -h | [-o <output-filename>] [<interface-id>:]<device-id> [<key>=<value>] ..." << std::endl;
62  std::cout << std::endl;
63  std::cout << "Gets the first synchronized image set of the Roboception rc_visard, consisting of left, disparity, confidence and error image, creates a point cloud and stores it in ply ascii format." << std::endl;
64  std::cout << std::endl;
65  std::cout << "Options:" << std::endl;
66  std::cout << "-h Prints help information and exits" << std::endl;
67  std::cout << "-o <file> Set name of output file (default is 'rc_visard_<timestamp>.ply')" << std::endl;
68  std::cout << std::endl;
69  std::cout << "Parameters:" << std::endl;
70  std::cout << "<interface-id> Optional GenICam ID of interface for connecting to the device" << std::endl;
71  std::cout << "<device-id> GenICam device ID, serial number or user defined name of device" << std::endl;
72  std::cout << "<key>=<value> Optional GenICam parameters to be changed in the given order" << std::endl;
73 }
74 
75 }
76 
77 int main(int argc, char *argv[])
78 {
79  int ret=0;
80 
81  try
82  {
83  // optional parameters
84 
85  std::string name="";
86 
87  int i=1;
88 
89  while (i < argc && argv[i][0] == '-')
90  {
91  if (std::string(argv[i]) == "-o")
92  {
93  i++;
94  name=argv[i++];
95  }
96  else
97  {
98  std::cout << "Unknown parameter: " << argv[i] << std::endl;
99  std::cout << std::endl;
100 
101  printHelp(argv[0]);
102 
103  return 1;
104  }
105  }
106 
107  if (i >= argc || std::string(argv[i]) == "-h")
108  {
109  printHelp(argv[0]);
110  return 1;
111  }
112 
113  // find specific device accross all systems and interfaces and open it
114 
115  std::shared_ptr<rcg::Device> dev=rcg::getDevice(argv[i++]);
116 
117  if (dev)
118  {
119  dev->open(rcg::Device::CONTROL);
120  std::shared_ptr<GenApi::CNodeMapRef> nodemap=dev->getRemoteNodeMap();
121 
122  // get focal length, baseline and disparity scale factor
123 
124  double f=rcg::getFloat(nodemap, "FocalLengthFactor", 0, 0, false);
125  double t=rcg::getFloat(nodemap, "Baseline", 0, 0, true);
126  double scale=rcg::getFloat(nodemap, "Scan3dCoordinateScale", 0, 0, true);
127 
128  // check for special exposure alternate mode of rc_visard and
129  // corresponding filter and set tolerance accordingly
130 
131  // (The exposure alternate mode is typically used with a random dot
132  // projector connected to Out1. Alternate means that Out1 is high for
133  // every second image. The rc_visard calculates disparities from images
134  // with Out1=High. However, if the alternate filter is set to OnlyLow,
135  // then it is gueranteed that Out1=Low (i.e. projector off) for all
136  // rectified images. Thus, rectified images and disparity images are
137  // always around 40 ms appart, which must be taken into account for
138  // synchronization.)
139 
140  uint64_t tol=0;
141 
142  try
143  {
144  rcg::setEnum(nodemap, "LineSelector", "Out1", true);
145  std::string linesource=rcg::getEnum(nodemap, "LineSource", true);
146  std::string filter=rcg::getEnum(nodemap, "AcquisitionAlternateFilter", true);
147 
148  if (linesource == "ExposureAlternateActive" && filter == "OnlyLow")
149  {
150  tol=50*1000*1000; // set tolerance to 50 ms
151  }
152  }
153  catch (const std::exception &)
154  {
155  // ignore possible errors
156  }
157 
158  // sanity check of some parameters
159 
160  rcg::checkFeature(nodemap, "Scan3dOutputMode", "DisparityC");
161  rcg::checkFeature(nodemap, "Scan3dCoordinateOffset", "0");
162  rcg::checkFeature(nodemap, "Scan3dInvalidDataFlag", "1");
163  rcg::checkFeature(nodemap, "Scan3dInvalidDataValue", "0");
164 
165  // set to color format if available
166 
167  rcg::setEnum(nodemap, "PixelFormat", "YCbCr411_8", false);
168 
169  // enable left image, disparity, confidence and error image and disable
170  // all others
171 
172  {
173  std::vector<std::string> component;
174 
175  rcg::getEnum(nodemap, "ComponentSelector", component, true);
176 
177  for (size_t k=0; k<component.size(); k++)
178  {
179  rcg::setEnum(nodemap, "ComponentSelector", component[k].c_str(), true);
180 
181  bool enable=(component[k] == "Intensity" || component[k] == "Disparity" ||
182  component[k] == "Confidence" || component[k] == "Error");
183  rcg::setBoolean(nodemap, "ComponentEnable", enable, true);
184  }
185  }
186 
187  // try getting synchronized data (which only has an effect if the device
188  // and GenTL producer support multipart)
189 
190  rcg::setString(nodemap, "AcquisitionMultiPartMode", "SynchronizedComponents");
191 
192  // set values as given on the command line
193 
194  while (i < argc)
195  {
196  // split argument in key and value
197 
198  std::string key=argv[i++];
199  std::string value;
200 
201  size_t k=key.find('=');
202  if (k != std::string::npos)
203  {
204  value=key.substr(k+1);
205  key=key.substr(0, k);
206  }
207 
208  if (value.size() > 0)
209  {
210  rcg::setString(nodemap, key.c_str(), value.c_str(), true);
211  }
212  else
213  {
214  rcg::callCommand(nodemap, key.c_str(), true);
215  }
216  }
217 
218  // open image stream
219 
220  std::vector<std::shared_ptr<rcg::Stream> > stream=dev->getStreams();
221 
222  if (stream.size() > 0)
223  {
224  // opening first stream
225 
226  stream[0]->open();
227  stream[0]->startStreaming();
228 
229  // prepare buffers for time synchronization of images (buffer at most
230  // 25 images in each list)
231 
232  rcg::ImageList left_list(50);
233  rcg::ImageList disp_list(25);
234  rcg::ImageList conf_list(25);
235  rcg::ImageList error_list(25);
236 
237  bool run=true;
238  int async=0, maxasync=50; // maximum number of asynchroneous images before giving up
239 
240  while (run && async < maxasync)
241  {
242  async++;
243 
244  // grab next image with timeout
245 
246  const rcg::Buffer *buffer=stream[0]->grab(5000);
247  if (buffer != 0)
248  {
249  // check for a complete image in the buffer
250 
251  if (!buffer->getIsIncomplete())
252  {
253  // go through all parts in case of multi-part buffer
254 
255  size_t partn=buffer->getNumberOfParts();
256  for (uint32_t part=0; part<partn; part++)
257  {
258  if (buffer->getImagePresent(part))
259  {
260  // store image in the corresponding list
261 
262  uint64_t left_tol=0;
263  uint64_t disp_tol=0;
264 
265  std::string component=rcg::getComponetOfPart(nodemap, buffer, part);
266 
267  if (component == "Intensity")
268  {
269  left_list.add(buffer, part);
270  disp_tol=tol;
271  }
272  else if (component == "Disparity")
273  {
274  disp_list.add(buffer, part);
275  left_tol=tol;
276  }
277  else if (component == "Confidence")
278  {
279  conf_list.add(buffer, part);
280  left_tol=tol;
281  }
282  else if (component == "Error")
283  {
284  error_list.add(buffer, part);
285  left_tol=tol;
286  }
287 
288  // get corresponding left and disparity images
289 
290  uint64_t timestamp=buffer->getTimestampNS();
291  std::shared_ptr<const rcg::Image> left=left_list.find(timestamp, left_tol);
292  std::shared_ptr<const rcg::Image> disp=disp_list.find(timestamp, disp_tol);
293 
294  // get confidence and error images that correspond to the
295  // disparity image
296 
297  std::shared_ptr<const rcg::Image> conf;
298  std::shared_ptr<const rcg::Image> error;
299 
300  if (disp)
301  {
302  conf=conf_list.find(disp->getTimestampNS());
303  error=error_list.find(disp->getTimestampNS());
304  }
305 
306  if (left && disp && conf && error)
307  {
308  // compute and store point cloud from synchronized image pair
309 
310  rcg::storePointCloud(name, f, t, scale, left, disp, conf, error);
311 
312  // remove all images from the buffer with the current or an
313  // older time stamp
314 
315  async=0;
316  left_list.removeOld(timestamp);
317  disp_list.removeOld(timestamp);
318  conf_list.removeOld(timestamp);
319  error_list.removeOld(timestamp);
320 
321  // in this example, we exit the grabbing loop after receiving
322  // the first synchronized image pair
323 
324  run=false;
325  }
326  }
327  }
328  }
329  }
330  else
331  {
332  std::cerr << "Cannot grab images" << std::endl;
333  break;
334  }
335  }
336 
337  // report if synchronization failed
338 
339  if (async >= maxasync && run)
340  {
341  std::cerr << "Cannot grab synchronized left and disparity image" << std::endl;
342  ret=1;
343  }
344 
345  // stopping and closing image stream
346 
347  stream[0]->stopStreaming();
348  stream[0]->close();
349  }
350  else
351  {
352  std::cerr << "No streams available" << std::endl;
353  ret=1;
354  }
355 
356  // closing the communication to the device
357 
358  dev->close();
359  }
360  else
361  {
362  std::cerr << "Device '" << argv[1] << "' not found!" << std::endl;
363  ret=1;
364  }
365  }
366  catch (const std::exception &ex)
367  {
368  std::cerr << ex.what() << std::endl;
369  ret=2;
370  }
371  catch (const GENICAM_NAMESPACE::GenericException &ex)
372  {
373  std::cerr << "Exception: " << ex.what() << std::endl;
374  ret=2;
375  }
376  catch (...)
377  {
378  std::cerr << "Unknown exception!" << std::endl;
379  ret=2;
380  }
381 
383 
384  return ret;
385 }
std::shared_ptr< Device > getDevice(const char *id)
Searches across all transport layers and interfaces for a device.
Definition: device.cc:480
void storePointCloud(std::string name, double f, double t, double scale, std::shared_ptr< const Image > left, std::shared_ptr< const Image > disp, std::shared_ptr< const Image > conf, std::shared_ptr< const Image > error)
Definition: pointcloud.cc:86
An object of this class manages a limited number of images.
Definition: imagelist.h:53
bool setEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool exception)
Set the value of an enumeration of the given nodemap.
Definition: config.cc:301
static void clearSystems()
Clears the internal list of systems.
Definition: system.cc:282
void removeOld(uint64_t timestamp)
Removes all images that have a timestamp that is older or equal than the given timestamp.
Definition: imagelist.cc:73
bool getImagePresent(std::uint32_t part) const
Returns if a 2D, 3D or confidence image is present in the specified part.
Definition: buffer.cc:472
The buffer class encapsulates a Genicam buffer that is provided by a stream.
Definition: buffer.h:118
void checkFeature(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool igncache)
Checks the value of given feature and throws an exception in case of a mismatch.
Definition: config.cc:899
LOG4CPP_EXPORT CategoryStream & left(CategoryStream &os)
left manipulator
std::string getEnum(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception)
Get the value of an enumeration of the given nodemap.
Definition: config.cc:676
uint64_t getTimestampNS() const
Returns the acquisition timestamp of the data in this buffer in ns.
Definition: buffer.cc:670
void add(const std::shared_ptr< const Image > &image)
Adds the given image to the internal list.
Definition: imagelist.cc:53
std::string getComponetOfPart(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const Buffer *buffer, uint32_t ipart)
Definition: config.cc:936
bool setString(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, const char *value, bool exception)
Set the value of a feature of the given nodemap.
Definition: config.cc:365
bool setBoolean(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool value, bool exception)
Set the value of a boolean feature of the given nodemap.
Definition: config.cc:106
double getFloat(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, double *vmin, double *vmax, bool exception, bool igncache)
Get the value of a double feature of the given nodemap.
Definition: config.cc:625
std::shared_ptr< const Image > find(uint64_t timestamp) const
Returns the image that has the given timestamp.
Definition: imagelist.cc:102
bool callCommand(const std::shared_ptr< GenApi::CNodeMapRef > &nodemap, const char *name, bool exception)
Calls the given command.
Definition: config.cc:60
bool getIsIncomplete() const
Signals if the buffer is incomplete due to an error.
Definition: buffer.cc:315
GenICam&#39;s exception class.
Definition: GCException.h:63
int main(int argc, char *argv[])
std::uint32_t getNumberOfParts() const
Returns the number of parts, excluding chunk data.
Definition: buffer.cc:203
virtual const char * what() const
Get error description (overwrite from std:exception)


rc_genicam_api
Author(s): Heiko Hirschmueller
autogenerated on Sun Jun 18 2023 02:43:55