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
45using namespace armarx;
46
47namespace
48{
49
50 const char* const GC_COMPONENT_ENABLE = "ComponentEnable";
51 const char* const GC_COMPONENT_SELECTOR = "ComponentSelector";
52
53} // namespace
54
55bool
56visionx::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
108void
110{
111 rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Intensity", true);
112 rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
113}
114
115void
117{
118 rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "IntensityCombined", true);
119 rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
120}
121
122void
124{
125 rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Disparity", true);
126 rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
127}
128
129void
131{
132 rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Confidence", true);
133 rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
134}
135
136void
138{
139 rcg::setString(nodemap, GC_COMPONENT_SELECTOR, "Error", true);
140 rcg::setString(nodemap, GC_COMPONENT_ENABLE, enabled ? "1" : "0", true);
141}
142
143void
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
236void
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
245void
247{
248 ARMARX_INFO << "Stop streaming Roboception Images";
249 stream->stopStreaming();
250 stream->close();
251}
252
253void
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
277void
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
295void
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
358void
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
372void
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}
#define float
Definition 16_Level.h:22
#define VAROUT(x)
constexpr T c
void enableDisparity(bool enabled)
visionx::StereoCalibration stereoCalibration
void enableError(bool enabled)
void enableIntensityCombined(bool enabled)
std::shared_ptr< GenApi::CNodeMapRef > nodemap
bool initDevice(const std::string &dname)
void enableConfidence(bool enabled)
void enableIntensity(bool enabled)
void setupStreamAndCalibration(float scalefactor, const std::string &calibSavePath)
visionx::ImageDimension dimensions
static void fillCameraImageDepth(unsigned char *outputPixels, double f, double t, double scale, const rcg::Image &disparity, size_t upscale=1)
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)
#define ARMARX_CHECK(expression)
Shortcut for ARMARX_CHECK_EXPRESSION.
#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...
#define ARMARX_INFO
The normal logging level.
Definition Logging.h:181
#define ARMARX_FATAL
The logging level for unexpected behaviour, that will lead to a seriously malfunctioning program and ...
Definition Logging.h:199
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
Definition Logging.h:196
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
Definition Logging.h:193
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::shared_ptr< rcg::Stream > StreamPtr
std::shared_ptr< rcg::Device > DevicePtr
const char *const GC_COMPONENT_SELECTOR
const char *const GC_COMPONENT_ENABLE
void depthValueToRGB(unsigned int depthInMM, unsigned char &r, unsigned char &g, unsigned char &b, bool noiseResistant=false)
Definition ImageUtil.h:183
CByteImage::ImageType convert(const ImageType visionxImageType)
Converts a VisionX image type into an image type of IVT's ByteImage.