RoboceptionUser.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * ArmarX is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * ArmarX is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  *
16  * @package VisionX::ArmarXObjects::RoboceptionUser
17  * @author Raphael Grimm ( raphael dot grimm at kit dot edu )
18  * @date 2019
19  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
20  * GNU General Public License
21  */
22 
23 #include "RoboceptionUser.h"
24 
25 #include <stdlib.h>
26 
30 
33 
34 #include <Calibration/Calibration.h>
35 #include <Calibration/StereoCalibration.h>
36 #include <Image/ImageProcessor.h>
37 #include <rc_genicam_api/buffer.h>
38 #include <rc_genicam_api/config.h>
39 #include <rc_genicam_api/image.h>
40 #include <rc_genicam_api/interface.h>
41 #include <rc_genicam_api/pixel_formats.h>
42 #include <rc_genicam_api/system.h>
43 
44 
45 using namespace armarx;
46 
47 namespace
48 {
49 
50  const char* const GC_COMPONENT_ENABLE = "ComponentEnable";
51  const char* const GC_COMPONENT_SELECTOR = "ComponentSelector";
52 
53 } // namespace
54 
55 bool
56 visionx::RoboceptionUser::initDevice(const std::string& dname)
57 {
58  if (!getenv("GENICAM_GENTL64_PATH"))
59  {
60  setenv("GENICAM_GENTL64_PATH", "/usr/lib/rc_genicam_api/", 0);
61  }
62  dev = rcg::getDevice(dname.c_str());
63  if (!dev)
64  {
65  //this randomly gets added by the rc driver
66  const auto dname2 = "devicemodul" + dname;
67  dev = rcg::getDevice(dname2.c_str());
68  }
69 
70  if (dev)
71  {
72  ARMARX_INFO << "Connecting to device: " << dname;
73  dev->open(rcg::Device::EXCLUSIVE);
74  nodemap = dev->getRemoteNodeMap();
75  return true;
76  }
77  ARMARX_WARNING << "Unable to connect to device: " << dname;
78 
79  std::vector<std::shared_ptr<rcg::Device>> devices = rcg::getDevices();
80  ARMARX_INFO << "found " << devices.size() << " devices";
81 
82  for (const rcg::DevicePtr& d : devices)
83  {
84  if (dname == d->getID())
85  {
86  ARMARX_ERROR << "Device: " << d->getID() << " !!!(THIS IS THE DEVICE YOU REQUESTED)!!!";
87  }
88  else
89  {
90  ARMARX_INFO << "Device: " << d->getID();
91  }
92  ARMARX_INFO << "Vendor: " << d->getVendor();
93  ARMARX_INFO << "Model: " << d->getModel();
94  ARMARX_INFO << "TL type: " << d->getTLType();
95  ARMARX_INFO << "Display name: " << d->getDisplayName();
96  ARMARX_INFO << "Access status:" << d->getAccessStatus();
97  ARMARX_INFO << "User name: " << d->getUserDefinedName();
98  ARMARX_INFO << "Serial number: " << d->getSerialNumber();
99  ARMARX_INFO << "Version: " << d->getVersion();
100  ARMARX_INFO << "TS Frequency: " << d->getTimestampFrequency();
101  }
102 
103  ARMARX_ERROR << "Please specify the device id. Aborting";
104 
105  return false;
106 }
107 
108 void
110 {
111  rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Intensity", true);
112  rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
113 }
114 
115 void
117 {
118  rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "IntensityCombined", true);
119  rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
120 }
121 
122 void
124 {
125  rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Disparity", true);
126  rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
127 }
128 
129 void
131 {
132  rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Confidence", true);
133  rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
134 }
135 
136 void
138 {
139  rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Error", true);
140  rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
141 }
142 
143 void
145  const std::string& calibSavePath)
146 {
147  numImages = 2;
148 
149  if (!rcg::setBoolean(nodemap, "GevIEEE1588", true))
150  {
151  ARMARX_WARNING << "Could not activate Precision Time Protocol (PTP) client!";
152  }
153 
154  dimensions.height = Ice::Int(rcg::getInteger(nodemap, "Height") / 2.0);
155  dimensions.width = Ice::Int(rcg::getInteger(nodemap, "Width"));
156  ARMARX_INFO << VAROUT(dimensions.height) << VAROUT(dimensions.width);
157 
158  baseline = rcg::getFloat(nodemap, "Baseline", nullptr, nullptr, true);
159  focalLengthFactor = rcg::getFloat(nodemap, "FocalLengthFactor", nullptr, nullptr, false);
160  float focalLength = float(focalLengthFactor * dimensions.width);
161  ARMARX_INFO << VAROUT(focalLengthFactor) << "\t" << VAROUT(focalLength);
162 
163 
164  ARMARX_INFO << "Get stream";
165  {
166  std::vector<rcg::StreamPtr> availableStreams = dev->getStreams();
167 
168  for (const rcg::StreamPtr& s : availableStreams)
169  {
170  ARMARX_INFO << "Stream: " << s->getID();
171  }
172 
173  if (!availableStreams.size())
174  {
175  ARMARX_FATAL << "Unable to open stream";
176  return;
177  }
178  else
179  {
180  this->stream = availableStreams[0];
181  }
182  }
183 
184 
185  cameraImages = new CByteImage*[numImages];
186  for (size_t i = 0; i < numImages; i++)
187  {
188  cameraImages[i] = new CByteImage(dimensions.width, dimensions.height, CByteImage::eRGB24);
189  }
190 
191  scaleFactor = scalefactor;
192  if (scaleFactor > 1.0)
193  {
194  dimensions.height /= scaleFactor;
195  dimensions.width /= scaleFactor;
196  focalLength /= scaleFactor;
197  }
198 
199  smallImages = new CByteImage*[numImages];
200  for (size_t i = 0; i < numImages; i++)
201  {
202  smallImages[i] = new CByteImage(dimensions.width, dimensions.height, CByteImage::eRGB24);
203  }
204 
205  CCalibration c;
206  c.SetCameraParameters(focalLength,
207  focalLength,
208  dimensions.width / 2.0,
209  dimensions.height / 2.0,
210  0.0,
211  0.0,
212  0.0,
213  0.0,
214  Math3d::unit_mat,
215  Math3d::zero_vec,
216  dimensions.width,
217  dimensions.height);
218 
219  CStereoCalibration ivtStereoCalibration;
220  ivtStereoCalibration.SetSingleCalibrations(c, c);
221  ivtStereoCalibration.rectificationHomographyRight = Math3d::unit_mat;
222  ivtStereoCalibration.rectificationHomographyLeft = Math3d::unit_mat;
223 
224  Vec3d right_translation;
225  right_translation.x = baseline * -1000.0;
226  right_translation.y = 0.0;
227  right_translation.z = 0.0;
228  ivtStereoCalibration.SetExtrinsicParameters(
229  Math3d::unit_mat, Math3d::zero_vec, Math3d::unit_mat, right_translation, false);
230 
231  ARMARX_INFO << "Saving calibration to: " << calibSavePath;
232  ivtStereoCalibration.SaveCameraParameters(calibSavePath.c_str());
233  stereoCalibration = visionx::tools::convert(ivtStereoCalibration);
234 }
235 
236 void
238 {
239  ARMARX_INFO << "Start streaming Roboception Images";
240  // rcg::setString(nodemap, "AcquisitionFrameRate", std::to_string(framesPerSecond), true);
241  stream->open();
242  stream->startStreaming();
243 }
244 
245 void
247 {
248  ARMARX_INFO << "Stop streaming Roboception Images";
249  stream->stopStreaming();
250  stream->close();
251 }
252 
253 void
255 {
256  if (stream)
257  {
258  stream->stopStreaming();
259  stream->close();
260  }
261 
262  if (dev)
263  {
264  dev->close();
265  }
266 
267  for (size_t i = 0; i < numImages; i++)
268  {
269  delete cameraImages[i];
270  delete smallImages[i];
271  }
272 
273  delete[] cameraImages;
274  delete[] smallImages;
275 }
276 
277 void
279 {
280  GenApi::NodeList_t nodeList;
281  nodemap->_GetNodes(nodeList);
282  ARMARX_INFO << "RC config nodes";
283  for (const auto& node : nodeList)
284  {
285  ARMARX_INFO << "---- properties of node '" << node->GetName(true) << '\'';
286  GENICAM_NAMESPACE::gcstring_vector properties;
287  node->GetPropertyNames(properties);
288  for (const auto& string : properties)
289  {
290  ARMARX_INFO << "-------- '" << string << '\'';
291  }
292  }
293 }
294 
295 void
297  size_t nImage,
298  const uint8_t* inputPixels,
299  size_t width,
300  size_t height,
301  uint64_t pixelFormat,
302  size_t xpadding)
303 {
304  const unsigned char* p = inputPixels;
305 
306  switch (pixelFormat)
307  {
308  case PfncFormat::Mono8:
309  case PfncFormat::Confidence8:
310  case Error8:
311  {
312  unsigned char const* row = p + (nImage * height) * (width + xpadding);
313  unsigned char* outRow = outputPixels;
314  for (size_t j = 0; j < height; j++)
315  {
316  for (size_t i = 0; i < width; i++)
317  {
318  const unsigned char c = row[i];
319  outRow[3 * i + 0] = c;
320  outRow[3 * i + 1] = c;
321  outRow[3 * i + 2] = c;
322  }
323 
324  p += xpadding;
325  outRow += width * 3;
326  row += width + xpadding;
327  }
328  }
329  break;
330  case PfncFormat::YCbCr411_8:
331  {
332  // Compression: 4 pixel are encoded in 6 bytes
333  size_t inStride = width * 6 / 4 + xpadding;
334  unsigned char const* row = p + (nImage * height) * inStride;
335  unsigned char* outRow = outputPixels;
336  uint8_t rgb[3];
337  for (size_t j = 0; j < height; j++)
338  {
339  for (size_t i = 0; i < width; i++)
340  {
341  rcg::convYCbCr411toRGB(rgb, row, int(i));
342  outRow[i * 3 + 0] = rgb[0];
343  outRow[i * 3 + 1] = rgb[1];
344  outRow[i * 3 + 2] = rgb[2];
345  }
346 
347  row += inStride;
348  outRow += width * 3;
349  }
350  }
351  break;
352  default:
353  ARMARX_INFO << "Unexpected pixel format: " << int(pixelFormat);
354  break;
355  }
356 }
357 
358 void
360  size_t nImage,
361  const rcg::Image& inputRgb)
362 {
363  fillCameraImageRGB(outputPixels,
364  nImage,
365  inputRgb.getPixels(),
366  inputRgb.getWidth(),
367  inputRgb.getHeight(),
368  inputRgb.getPixelFormat(),
369  inputRgb.getXPadding());
370 }
371 
372 void
374  double f,
375  double t,
376  double scale,
377  const rcg::Image& disparity,
378  size_t upscale)
379 {
380  ARMARX_CHECK(upscale == 1 || upscale == 2)
381  << "Upscaling by factors other than 1 or 2 is not implemented.";
382 
383  // intensityCombined: Top half is the left image, bottom half the right image
384  // Get size and scale factor between left image and disparity image.
385 
386  size_t width = disparity.getWidth();
387  size_t height = disparity.getHeight();
388  bool bigendian = disparity.isBigEndian();
389 
390  // Convert focal length factor into focal length in (disparity) pixels
391 
392  f *= width;
393 
394  // Get pointer to disparity data and size of row in bytes
395 
396  const uint8_t* dps = disparity.getPixels();
397 
398  ARMARX_CHECK_EQUAL(disparity.getPixelFormat(), Coord3D_C16);
399  size_t dstep = disparity.getWidth() * sizeof(uint16_t) + disparity.getXPadding();
400 
401 
402  // Fill depth image.
403 
404  disparity.getXPadding();
405  unsigned char* outRow = outputPixels;
406 
407  for (size_t j = 0; j < height; j++)
408  {
409  for (size_t i = 0; i < width; i++)
410  {
411  // Convert disparity from fixed comma 16 bit integer into float value.
412  double d;
413  if (bigendian)
414  {
415  size_t j = i << 1;
416  d = scale * ((dps[j] << 8) | dps[j + 1]);
417  }
418  else
419  {
420  size_t j = i << 1;
421  d = scale * ((dps[j + 1] << 8) | dps[j]);
422  }
423 
424  unsigned char* pixel = &outRow[3 * i * upscale];
425 
426  // If disparity is valid
427  if (d > 0)
428  {
429  // Reconstruct depth from disparity value
430  double z = f * t / d;
431 
432  // Store depth
433  const double meterToMillimeter = 1000.0;
434  unsigned int depthMM = static_cast<unsigned int>(std::round(z * meterToMillimeter));
435 
436  visionx::tools::depthValueToRGB(depthMM, pixel[0], pixel[1], pixel[2]);
437  }
438  else
439  {
440  pixel[0] = 0;
441  pixel[1] = 0;
442  pixel[2] = 0;
443  }
444 
445  if (upscale == 2)
446  {
447  // Copy the pixel inside this row.
448  unsigned char* nextPixel = pixel + 3;
449  std::memcpy(nextPixel, pixel, 3);
450  }
451  }
452 
453  if (upscale == 2)
454  {
455  // Copy the entire row.
456  unsigned char* nextRow = outRow + width * 3 * upscale;
457  std::memcpy(nextRow, outRow, width * 3 * upscale);
458  outRow = nextRow;
459  }
460 
461  dps += dstep;
462  outRow += width * 3 * upscale;
463  }
464 }
rcg::StreamPtr
std::shared_ptr< rcg::Stream > StreamPtr
Definition: RCImageProvider.h:46
visionx::RoboceptionUser::printNodeMap
void printNodeMap() const
Definition: RoboceptionUser.cpp:278
GfxTL::Vec3d
VectorXD< 3, double > Vec3d
Definition: VectorXD.h:737
visionx::RoboceptionUser::cleanupRC
void cleanupRC()
Definition: RoboceptionUser.cpp:254
visionx::roboception::GC_COMPONENT_ENABLE
const char *const GC_COMPONENT_ENABLE
Definition: roboception_constants.h:8
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
visionx::RoboceptionUser::enableError
void enableError(bool enabled)
Definition: RoboceptionUser.cpp:137
ARMARX_CHECK
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
Definition: ExpressionException.h:82
ARMARX_FATAL
#define ARMARX_FATAL
Definition: Logging.h:199
visionx::tools::convert
CByteImage::ImageType convert(const ImageType visionxImageType)
Converts a VisionX image type into an image type of IVT's ByteImage.
Definition: TypeMapping.cpp:97
visionx::RoboceptionUser::initDevice
bool initDevice(const std::string &dname)
Definition: RoboceptionUser.cpp:56
visionx::RoboceptionUser::fillCameraImageDepth
static void fillCameraImageDepth(unsigned char *outputPixels, double f, double t, double scale, const rcg::Image &disparity, size_t upscale=1)
Definition: RoboceptionUser.cpp:373
visionx::tools::depthValueToRGB
void depthValueToRGB(unsigned int depthInMM, unsigned char &r, unsigned char &g, unsigned char &b, bool noiseResistant=false)
Definition: ImageUtil.h:183
enabled
std::atomic< bool > * enabled
Definition: RemoteGuiWidgetController.cpp:75
visionx::RoboceptionUser::enableDisparity
void enableDisparity(bool enabled)
Definition: RoboceptionUser.cpp:123
rcg::DevicePtr
std::shared_ptr< rcg::Device > DevicePtr
Definition: RCImageProvider.h:45
visionx::roboception::GC_COMPONENT_SELECTOR
const char *const GC_COMPONENT_SELECTOR
Definition: roboception_constants.h:9
ARMARX_ERROR
#define ARMARX_ERROR
Definition: Logging.h:196
visionx::RoboceptionUser::startRC
void startRC()
Definition: RoboceptionUser.cpp:237
ExpressionException.h
float
#define float
Definition: 16_Level.h:22
ARMARX_INFO
#define ARMARX_INFO
Definition: Logging.h:181
VAROUT
#define VAROUT(x)
Definition: StringHelpers.h:198
visionx::RoboceptionUser::enableIntensity
void enableIntensity(bool enabled)
Definition: RoboceptionUser.cpp:109
visionx::RoboceptionUser::enableConfidence
void enableConfidence(bool enabled)
Definition: RoboceptionUser.cpp:130
ImageUtil.h
armarx::VariantType::Int
const VariantTypeId Int
Definition: Variant.h:917
visionx::RoboceptionUser::enableIntensityCombined
void enableIntensityCombined(bool enabled)
Definition: RoboceptionUser.cpp:116
RoboceptionUser.h
visionx::RoboceptionUser::setupStreamAndCalibration
void setupStreamAndCalibration(float scalefactor, const std::string &calibSavePath)
Definition: RoboceptionUser.cpp:144
TypeMapping.h
Logging.h
ARMARX_CHECK_EQUAL
#define ARMARX_CHECK_EQUAL(lhs, rhs)
This macro evaluates whether lhs is equal (==) rhs and if it turns out to be false it will throw an E...
Definition: ExpressionException.h:130
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
ArmarXDataPath.h
visionx::RoboceptionUser::fillCameraImageRGB
static void fillCameraImageRGB(unsigned char *outputPixels, size_t nImage, const uint8_t *inputPixels, size_t width, size_t height, uint64_t pixelFormat, size_t xpadding)
Definition: RoboceptionUser.cpp:296
armarx::ctrlutil::s
double s(double t, double s0, double v0, double a0, double j)
Definition: CtrlUtil.h:33
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27
visionx::RoboceptionUser::stopRC
void stopRC()
Definition: RoboceptionUser.cpp:246