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