31 #include <Calibration/StereoCalibration.h>
41 void chromaCallback(
const crl::multisense::image::Header& header,
void* userDataP)
47 void lumaCallback(
const crl::multisense::image::Header& header,
void* userDataP)
52 void lidarCallback(
const crl::multisense::lidar::Header& header,
void* userDataP)
59 crl::multisense::image::Calibration
c;
60 crl::multisense::lidar::Calibration l;
61 crl::multisense::Status
status;
65 driver = crl::multisense::Channel::Create(getProperty<std::string>(
"ipAddress").getValue());
69 throw std::runtime_error(
"Unable to connect to multisense device");
72 crl::multisense::Status
status = driver->getImageCalibration(
c);
73 if (
status != crl::multisense::Status_Ok)
75 throw std::runtime_error(
"Unable to retrieve image calibration.");
79 if (getProperty<bool>(
"useLidar").getValue())
81 driver->getLidarCalibration(l);
82 if (
status != crl::multisense::Status_Ok)
84 throw std::runtime_error(
"Unable to retrieve liadr calibration.");
91 catch (std::exception& e)
93 ARMARX_FATAL <<
"Multisense error: " << e.what() <<
" Try entering ' roslaunch multisense_bringup multisense.launch mtu:=1500 ' in your console";
94 crl::multisense::Channel::Destroy(driver);
100 q_matrix = cv::Mat::zeros(4, 4, cv::DataType<double>::type);
102 const int width = 1024;
103 const int height = 544;
105 rgbImage = cv::Mat::zeros(height, width, CV_8UC3);
106 disparityImage = cv::Mat::zeros(height, width, CV_16SC1);
109 rgbImages =
new CByteImage*[2];
111 rgbImages[0] =
new CByteImage(width, height, CByteImage::eRGB24);
112 rgbImages[1] =
new CByteImage(width, height, CByteImage::eRGB24);
125 double xScale = 2048 / width;
126 double yScale = 1088 / height;
127 double Fx =
c.right.P[0][0] / xScale;
128 double Cx =
c.right.P[0][2] / xScale;
129 double Fy =
c.right.P[1][1] / yScale;
130 double Cy =
c.right.P[1][2] / yScale;
131 double Tx = (
c.right.P[0][3] / xScale) / Fx;
133 q_matrix.at<
double>(0, 0) = Fy * Tx;
134 q_matrix.at<
double>(0, 3) = - Fy * Cx * Tx;
135 q_matrix.at<
double>(1, 1) = Fx * Tx;
136 q_matrix.at<
double>(1, 3) = - Fx * Cy * Tx;
137 q_matrix.at<
double>(2, 3) = Fx * Fy * Tx;
138 q_matrix.at<
double>(3, 2) = -Fy;
141 std::string calibrationFileName = getProperty<std::string>(
"CalibrationFileName").getValue();
144 CStereoCalibration ivtStereoCalibration;
145 if (ivtStereoCalibration.LoadCameraParameters(calibrationFileName.c_str(),
true))
151 ARMARX_WARNING <<
"Failed loading calibration file " << calibrationFileName;
156 ARMARX_WARNING <<
"Calibration file with file name " << calibrationFileName <<
" not found";
158 calibration.calibrationLeft.cameraParam.width = width;
159 calibration.calibrationLeft.cameraParam.height = height;
160 calibration.calibrationLeft.cameraParam.principalPoint.push_back(Cx);
161 calibration.calibrationLeft.cameraParam.principalPoint.push_back(Cy);
162 calibration.calibrationLeft.cameraParam.focalLength.push_back(Fx);
163 calibration.calibrationLeft.cameraParam.focalLength.push_back(Fy);
172 Eigen::Vector4f minPoint = getProperty<Eigen::Vector4f>(
"minPoint").getValue();
173 Eigen::Vector4f maxPoint = getProperty<Eigen::Vector4f>(
"maxPoint").getValue();;
175 cropBoxFilter.setMin(minPoint);
176 cropBoxFilter.setMax(maxPoint);
178 mask = crl::multisense::Source_Unknown;
181 if (getProperty<bool>(
"useLidar").getValue())
184 mask |= crl::multisense::Source_Lidar_Scan;
190 mask |= crl::multisense::Source_Disparity;
193 if (
status != crl::multisense::Status_Ok)
195 throw std::runtime_error(
"Unable to attach isolated callback");
199 status = driver->addIsolatedCallback(
lumaCallback, crl::multisense::Source_Luma_Left | crl::multisense::Source_Luma_Right,
this);
200 mask |= crl::multisense::Source_Luma_Left | crl::multisense::Source_Luma_Right;
202 if (
status != crl::multisense::Status_Ok)
204 throw std::runtime_error(
"Unable to attach isolated callback");
208 status = driver->addIsolatedCallback(
chromaCallback, crl::multisense::Source_Chroma_Left,
this);
209 mask |= crl::multisense::Source_Chroma_Left;
211 if (
status != crl::multisense::Status_Ok)
213 throw std::runtime_error(
"Unable to attach isolated callback");
216 if (getProperty<bool>(
"enableLight").getValue())
218 crl::multisense::lighting::Config lightingConfig;
219 lightingConfig.setDutyCycle(crl::multisense::lighting::MAX_DUTY_CYCLE);
221 if (driver->setLightingConfig(lightingConfig) != crl::multisense::Status_Ok)
235 crl::multisense::Status
status;
237 if (getProperty<bool>(
"useLidar").getValue())
247 if (
status != crl::multisense::Status_Ok)
254 if (
status != crl::multisense::Status_Ok)
261 if (
status != crl::multisense::Status_Ok)
266 crl::multisense::Channel::Destroy(driver);
276 crl::multisense::Status
status;
277 crl::multisense::image::Config config;
281 status = driver->getImageConfig(config);
282 if (
status != crl::multisense::Status_Ok)
284 throw std::runtime_error(
"Unable read image config");
288 status = driver->setImageConfig(config);
289 if (
status != crl::multisense::Status_Ok)
291 throw std::runtime_error(
"Unable to set image config");
294 pointCloudData.reset(
new pcl::PointCloud<pcl::PointXYZRGBA>());
296 pointCloudData->width = config.width();
297 pointCloudData->height = config.height();
298 pointCloudData->resize(config.width() * config.height());
300 status = driver->startStreams(mask);
302 if (
status != crl::multisense::Status_Ok)
304 throw std::runtime_error(
"Unable to start image streams");
309 catch (std::exception& e)
312 crl::multisense::Channel::Destroy(driver);
315 hasNewColorData =
false;
316 hasNewLumaData =
false;
317 hasNewDisparityData =
false;
322 crl::multisense::Status
status = driver->stopStreams(mask);
324 if (
status != crl::multisense::Status_Ok)
326 ARMARX_FATAL <<
"Unable to stop streams. Status was " << crl::multisense::Channel::statusString(
status);
327 crl::multisense::Channel::Destroy(driver);
333 if (hasNewDisparityData && hasNewColorData)
335 pcl::PointCloud<pcl::PointXYZRGBA>::Ptr pointCloudTemp(
new pcl::PointCloud<pcl::PointXYZRGBA>());
337 std::unique_lock lock(dataMutex);
339 cropBoxFilter.setInputCloud(pointCloudData);
340 cropBoxFilter.filter(*pointCloudTemp);
343 hasNewColorData =
false;
344 hasNewDisparityData =
false;
348 std::vector<int>
index;
349 pcl::removeNaNFromPointCloud(*pointCloudTemp, *pointCloudTemp,
index);
354 std::string outputPCDName =
"/home/peter/output_" + boost::lexical_cast<std::string>(x) +
".pcd";
355 pcl::io::savePCDFileASCII(outputPCDName.data(), *pointCloudTemp);
359 ARMARX_INFO <<
"Providing point cloud of size " << pointCloudTemp->points.size();
371 const uint32_t imageSize = header.width * header.height;
373 std::unique_lock lock(dataMutex);
375 if (header.source == crl::multisense::Source_Luma_Right)
377 uint32_t height = header.height;
378 uint32_t width = header.width;
380 const uint8_t* rightLumaData =
reinterpret_cast<const uint8_t*
>(header.imageDataP);
382 for (
size_t j = 0; j < height; j++)
384 for (
size_t i = 0; i < width; i++)
386 const uint32_t
index = (j * width) + i;
387 rgbImages[1]->pixels[3 *
index + 0] = rightLumaData[
index];
388 rgbImages[1]->pixels[3 *
index + 1] = rightLumaData[
index];
389 rgbImages[1]->pixels[3 *
index + 2] = rightLumaData[
index];
396 lumaData.resize(imageSize);
398 memcpy((
void*)&lumaData.data()[0], header.imageDataP, imageSize);
400 hasNewLumaData =
true;
406 std::unique_lock lock(dataMutex);
413 const uint8_t* chromaP =
reinterpret_cast<const uint8_t*
>(header.imageDataP);
415 uint32_t height = header.height * 2;
416 uint32_t width = header.width * 2;
418 for (
size_t j = 0; j < height; j++)
420 for (
size_t i = 0; i < width; i++)
422 const uint32_t lumaOffset = (j * width) + i;
423 const uint32_t chromaOffset = 2 * (((j / 2) * (width / 2)) + (i / 2));
425 const float px_y =
static_cast<float>(lumaData[lumaOffset]);
426 const float px_cb =
static_cast<float>(chromaP[chromaOffset + 0]) - 128.0f;
427 const float px_cr =
static_cast<float>(chromaP[chromaOffset + 1]) - 128.0f;
429 float px_r = px_y + 1.402f * px_cr;
430 float px_g = px_y - 0.34414f * px_cb - 0.71414f * px_cr;
431 float px_b = px_y + 1.772f * px_cb;
437 int index = j * width + i;
440 pcl::PointXYZRGBA& targetPoint = pointCloudData->points[
index];
442 targetPoint.r =
static_cast<uint8_t
>(px_r);
443 targetPoint.g =
static_cast<uint8_t
>(px_g);
444 targetPoint.b =
static_cast<uint8_t
>(px_b);
446 rgbImages[0]->pixels[3 *
index + 0] =
static_cast<uint8_t
>(px_r);
447 rgbImages[0]->pixels[3 *
index + 1] =
static_cast<uint8_t
>(px_g);
448 rgbImages[0]->pixels[3 *
index + 2] =
static_cast<uint8_t
>(px_b);
450 rgbImage.at<cv::Vec3b>(j, i)[0] =
static_cast<uint8_t
>(px_r);
451 rgbImage.at<cv::Vec3b>(j, i)[1] =
static_cast<uint8_t
>(px_g);
452 rgbImage.at<cv::Vec3b>(j, i)[2] =
static_cast<uint8_t
>(px_b);
456 hasNewLumaData =
false;
457 hasNewColorData =
true;
464 std::unique_lock lock(dataMutex);
466 if (!hasNewColorData)
472 for (
size_t i = 0; i < header.pointCount; i++)
474 const uint32_t range = header.rangesP[i];
475 const double percent =
static_cast<double>(i) /
static_cast<double>(header.pointCount - 1);
476 const double mirrorTheta = - header.scanArc / 2000.0 + percent * header.scanArc / 1000.0;
477 const double spindleTheta = header.spindleAngleStart / 1000.0 + percent * (header.spindleAngleEnd - header.spindleAngleStart) / 1000.0;
480 spindleToMotor.block<3, 3>(0, 0) = Eigen::AngleAxisf(spindleTheta, Eigen::Vector3f::UnitZ()).matrix();
483 Eigen::Vector4f point(range * std::sin(mirrorTheta), 0.0, range * std::cos(mirrorTheta), 1.0);
484 Eigen::Vector4f pointCamera = laserToSpindle * point;
485 pointCamera = spindleToMotor * pointCamera;
486 pointCamera = cameraToSpindle * pointCamera;
489 pcl::PointXYZRGBA& targetPoint = pointCloudData->points[i];
494 visionx:: CameraParameters p = calibration.calibrationLeft.cameraParam;
496 int u = (p.focalLength[0] * pointCamera[0] + p.principalPoint[0] * pointCamera[2]) / pointCamera[2];
497 int v = (p.focalLength[1] * pointCamera[1] + p.principalPoint[1] * pointCamera[2]) / pointCamera[2];
499 if (u < p.width && v < p.height && u >= 0 &&
v >= 0)
501 int index =
v * p.width + u;
504 targetPoint.getArray4fMap() = pointCamera;
506 targetPoint.r =
static_cast<uint8_t
>(rgbImages[0]->pixels[3 *
index + 0]);
507 targetPoint.g =
static_cast<uint8_t
>(rgbImages[0]->pixels[3 *
index + 1]);
508 targetPoint.b =
static_cast<uint8_t
>(rgbImages[0]->pixels[3 *
index + 2]);
513 targetPoint.x = std::numeric_limits<float>::quiet_NaN();
514 targetPoint.y = std::numeric_limits<float>::quiet_NaN();
515 targetPoint.z = std::numeric_limits<float>::quiet_NaN();
523 pointCloudData->header.stamp = header.timeStartMicroSeconds + header.timeStartSeconds / (1000 * 1000);
525 hasNewDisparityData =
true;
531 if (header.bitsPerPixel != 16)
537 cv::Mat_<uint16_t> disparityOrigP(header.height, header.width,
const_cast<uint16_t*
>(
reinterpret_cast<const uint16_t*
>(header.imageDataP)));
539 std::unique_lock lock(dataMutex);
541 cv::Mat_<float> disparity(header.height, header.width);
542 disparity = disparityOrigP / 16.0f;
543 disparity.copyTo(disparityImage);
545 cv::Mat_<cv::Vec3f> points(disparityImage.rows, disparityImage.cols);
547 cv::reprojectImageTo3D(disparity, points, q_matrix,
false);
549 for (
size_t j = 0; j < header.height; j++)
551 for (
size_t i = 0; i < header.width; i++)
553 int index = j * header.width + i;
555 pcl::PointXYZRGBA& targetPoint = pointCloudData->points[
index];
564 targetPoint.x = sourcePoint[0] * 1000.0;
565 targetPoint.y = sourcePoint[1] * 1000.0;
566 targetPoint.z = sourcePoint[2] * 1000.0;
570 targetPoint.x = std::numeric_limits<float>::quiet_NaN();
571 targetPoint.y = std::numeric_limits<float>::quiet_NaN();
572 targetPoint.z = std::numeric_limits<float>::quiet_NaN();
580 pointCloudData->header.frame_id = header.frameId;
581 pointCloudData->header.stamp = header.timeMicroSeconds + header.timeSeconds / (1000 * 1000);
584 hasNewDisparityData =
true;
589 setImageFormat(visionx::ImageDimension(1024, 544), visionx::eRgb);
606 return calibration.calibrationLeft;
612 visionx::MetaPointCloudFormatPtr info =
new visionx::MetaPointCloudFormat();
613 info->capacity = 1024 * 544 *
sizeof(visionx::ColoredPoint3D);
614 info->size = info->capacity;
615 info->type = visionx::PointContentType::eColoredPoints;