28 #include <Image/ByteImage.h>
29 #include <Image/ImageProcessor.h>
30 #include <Calibration/Calibration.h>
32 #include <opencv2/opencv.hpp>
49 #include <SimoxUtility/algorithm/string/string_tools.h>
57 FakePointCloudProviderPropertyDefinitions::FakePointCloudProviderPropertyDefinitions(std::string prefix) :
60 defineOptionalProperty<std::string>(
"pointCloudFileName",
"VisionX/examples/point_clouds/",
61 "The point cloud to read. If directory, all *.pcd files of this and all subdirectories are read. \n"
62 "All point clouds are read in before the pointcloud providing starts.");
64 defineOptionalProperty<bool>(
"rewind",
true,
"loop through the point clouds");
65 defineOptionalProperty<float>(
"scaleFactor", -1.0f,
"scale point cloud. only applied if value is larger than zero");
66 defineOptionalProperty<Eigen::Vector2i>(
"dimensions", Eigen::Vector2i(640, 480),
"")
67 .map(
"320x240", Eigen::Vector2i(320, 240))
68 .map(
"640x480", Eigen::Vector2i(640, 480))
69 .map(
"320x240", Eigen::Vector2i(320, 240))
70 .map(
"640x480", Eigen::Vector2i(640, 480))
71 .map(
"800x600", Eigen::Vector2i(800, 600))
72 .map(
"768x576", Eigen::Vector2i(768, 576))
73 .map(
"1024x768", Eigen::Vector2i(1024, 768))
74 .map(
"1024x1024", Eigen::Vector2i(1024, 1024))
75 .map(
"1280x960", Eigen::Vector2i(1280, 960))
76 .map(
"1600x1200", Eigen::Vector2i(1600, 1200));
78 defineOptionalProperty<std::string>(
"depthCameraCalibrationFile",
"",
"Camera depth calibration file (YAML)");
79 defineOptionalProperty<std::string>(
"RGBCameraCalibrationFile",
"",
"Camera RGB calibration file (YAML)");
81 defineOptionalProperty<std::string>(
"sourceFrameName",
"",
82 "Assume point cloud was stored in this frame.");
84 "Coordinate frame in which point cloud will be transformed and provided.\n"
85 "If left empty, no transformation will be applied and source frame name\n"
86 "will be returned as reference frame.");
88 defineOptionalProperty<std::string>(
"RobotStateComponentName",
"RobotStateComponent",
89 "Name of the robot state component to use.");
90 defineOptionalProperty<bool>(
"RemoveNAN",
true,
"Remove NAN from point cloud");
91 defineOptionalProperty<std::string>(
"ProvidedPointCloudFormat",
"XYZRGBA",
"Format of the provided point cloud (XYZRGBA, XYZL, XYZRGBL)");
96 return "FakePointCloudProvider";
132 getProperty(pointCloudFileName,
"pointCloudFileName");
138 getProperty(providedPointCloudFormat,
"ProvidedPointCloudFormat");
139 ARMARX_INFO <<
"Providing point clouds in format " << providedPointCloudFormat <<
".";
141 getProperty(robotStateComponentName,
"RobotStateComponentName");
142 if (!robotStateComponentName.empty())
148 if (!(sourceFrameName.empty() && targetFrameName.empty()))
150 if (!sourceFrameName.empty() && !targetFrameName.empty() && robotStateComponentName.empty())
152 ARMARX_ERROR <<
"Source and target frames specified, but no RobotStateComponent is specified.\n"
153 "No transformation will be applied.";
155 else if (sourceFrameName.empty() && !targetFrameName.empty())
157 ARMARX_WARNING <<
"Target frame was specified (" << targetFrameName <<
"), but no source frame is specified.\n"
158 <<
"Did you set the property `sourceFrameName`? (No transformation will be applied.)";
160 else if (!sourceFrameName.empty() && targetFrameName.empty())
162 ARMARX_INFO <<
"Source frame was specified (" << sourceFrameName <<
"), but no target frame is specified.\n"
163 <<
"No transformation will be applied and source frame is returned as reference frame.";
168 if (!ArmarXDataPath::getAbsolutePath(pointCloudFileName, pointCloudFileName))
170 ARMARX_ERROR <<
"Could not find point cloud file in ArmarXDataPath: " << pointCloudFileName;
174 if (std::filesystem::is_directory(pointCloudFileName))
176 loadPointCloudDirectory(pointCloudFileName);
180 loadPointCloud(pointCloudFileName);
183 if (pointClouds.empty())
185 ARMARX_FATAL <<
"Unable to load point cloud: " << pointCloudFileName;
186 throw LocalException(
"Unable to load point cloud");
189 ARMARX_INFO <<
"Loaded " << pointClouds.size() <<
" point clouds.";
192 visionx::CameraParameters RGBCameraIntrinsics;
193 RGBCameraIntrinsics.focalLength.resize(2);
194 RGBCameraIntrinsics.principalPoint.resize(2);
196 if (!getProperty<std::string>(
"RGBCameraCalibrationFile").getValue().
empty() && !loadCalibrationFile(getProperty<std::string>(
"RGBCameraCalibrationFile").getValue(), RGBCameraIntrinsics))
198 ARMARX_WARNING <<
"Could not load rgb camera parameter file " << getProperty<std::string>(
"RGBCameraCalibrationFile").getValue() <<
" - using camera uncalibrated";
201 visionx::CameraParameters depthCameraIntrinsics;
202 depthCameraIntrinsics.focalLength.resize(2);
203 depthCameraIntrinsics.principalPoint.resize(2);
205 if (!getProperty<std::string>(
"depthCameraCalibrationFile").getValue().
empty() && !loadCalibrationFile(getProperty<std::string>(
"depthCameraCalibrationFile").getValue(), depthCameraIntrinsics))
207 ARMARX_WARNING <<
"Could not load depth camera parameter file " << getProperty<std::string>(
"depthCameraCalibrationFile").getValue() <<
" - using camera uncalibrated";
212 calibration.calibrationLeft.cameraParam = RGBCameraIntrinsics;
213 calibration.calibrationRight.cameraParam = depthCameraIntrinsics;
216 bool FakePointCloudProvider::loadPointCloud(
const std::string& fileName)
220 pcl::PCLPointCloud2Ptr cloudptr(
new pcl::PCLPointCloud2());
223 if (io::loadPCDFile(fileName.c_str(), *cloudptr) == -1)
225 ARMARX_WARNING <<
"Unable to load point cloud from file " << fileName;
230 pointClouds.push_back(cloudptr);
238 bool FakePointCloudProvider::loadPointCloudDirectory(
const std::string& directoryName)
241 std::vector<std::string> fileNames;
243 for (std::filesystem::recursive_directory_iterator dir(directoryName), end;
244 dir != end &&
getState() < eManagedIceObjectExiting; ++dir)
247 if (dir->path().extension() ==
".pcd")
249 fileNames.push_back(dir->path().string());
253 ARMARX_INFO <<
"In total " << fileNames.size() <<
" point clouds found.";
256 std::sort(fileNames.begin(), fileNames.end());
258 for (std::size_t f = 0; f < fileNames.size(); f++)
260 ARMARX_INFO <<
" File " << f <<
" / " << fileNames.size() <<
" is being loaded... " << fileNames[f];
263 loadPointCloud(fileNames[f]);
281 MetaPointCloudFormatPtr format =
new MetaPointCloudFormat();
283 if (providedPointCloudFormat ==
"XYZL")
285 format->type = PointContentType::eLabeledPoints;
287 else if (providedPointCloudFormat ==
"XYZRGBL")
289 format->type = PointContentType::eColoredLabeledPoints;
293 format->type = PointContentType::eColoredPoints;
296 format->capacity =
static_cast<Ice::Int>(
298 format->size = format->capacity;
304 Eigen::Vector2i dimensions = getProperty<Eigen::Vector2i>(
"dimensions");
305 setImageFormat(visionx::ImageDimension(dimensions(0), dimensions(1)), visionx::eRgb);
307 rgbImages =
new CByteImage*[1];
308 rgbImages[0] =
new CByteImage(dimensions(0), dimensions(1), CByteImage::eRGB24);
309 ::ImageProcessor::Zero(rgbImages[0]);
317 if (!robotStateComponentName.empty())
319 getProxy(robotStateComponent, robotStateComponentName);
320 if (!robotStateComponent)
322 ARMARX_ERROR <<
"Failed to obtain robot state component.";
336 pcl::PCLPointCloud2Ptr cloudptr;
339 std::scoped_lock lock(pointCloudMutex);
341 if (rewind &&
static_cast<size_t>(counter.load()) >= pointClouds.size())
346 cloudptr = pointClouds.at(counter);
350 if (providedPointCloudFormat ==
"XYZRGBA")
352 return processAndProvide<pcl::PointXYZRGBA>(cloudptr);
354 else if (providedPointCloudFormat ==
"XYZL")
356 return processAndProvide<pcl::PointXYZL>(cloudptr);
358 else if (providedPointCloudFormat ==
"XYZRGBL")
360 return processAndProvide<pcl::PointXYZRGBL>(cloudptr);
364 ARMARX_ERROR <<
"Could not provide point cloud, because format '" << providedPointCloudFormat <<
"' is unknown";
369 bool FakePointCloudProvider::loadCalibrationFile(std::string fileName, visionx::CameraParameters& calibration)
371 ArmarXDataPath::getAbsolutePath(fileName, fileName, {},
false);
372 cv::FileStorage fs(fileName, cv::FileStorage::READ);
379 std::string cameraName = fs[
"camera_name"];
380 ARMARX_LOG <<
"loading calibration file for " << cameraName;
383 Eigen::Vector2i dimensions = getProperty<Eigen::Vector2i>(
"dimensions").getValue();
384 int imageWidth = fs[
"image_width"];
385 int imageHeight = fs[
"image_height"];
387 if (imageWidth != dimensions(0) || imageHeight != dimensions(1))
393 cv::Mat cameraMatrix, distCoeffs;
395 fs[
"camera_matrix"] >> cameraMatrix;
396 fs[
"distortion_coefficients:"] >> distCoeffs;
398 for (
int i = 0; i < 5; i++)
400 calibration.distortion[
static_cast<std::size_t
>(i)] = distCoeffs.at<
float>(0, i);
403 calibration.focalLength[0] = cameraMatrix.at<
float>(0, 0);
404 calibration.focalLength[1] = cameraMatrix.at<
float>(1, 1);
406 calibration.principalPoint[0] = cameraMatrix.at<
float>(2, 1);
407 calibration.principalPoint[1] = cameraMatrix.at<
float>(2, 2);
419 std::scoped_lock lock(pointCloudMutex);
432 template<
typename Po
intT>
433 bool FakePointCloudProvider::processAndProvide(
const PCLPointCloud2Ptr& pointCloud)
435 using PointCloudPtrT =
typename pcl::PointCloud<PointT>::Ptr;
437 PointCloudPtrT cloudptr(
new pcl::PointCloud<PointT>());
438 pcl::fromPCLPointCloud2(*pointCloud, *cloudptr);
440 if (cloudptr->isOrganized())
442 processRGBImage(pointCloud);
445 PointCloudPtrT resultCloudPtr(
new pcl::PointCloud<PointT>());
449 Eigen::Affine3f
transform(Eigen::Scaling(scaleFactor));
450 pcl::transformPointCloud(*cloudptr, *resultCloudPtr,
transform);
455 pcl::copyPointCloud(*cloudptr, *resultCloudPtr);
459 resultCloudPtr->header.stamp =
static_cast<uint64_t
>(time.toMicroSeconds());
461 if (!sourceFrameName.empty() || !targetFrameName.empty())
463 if (!sourceFrameName.empty() && !targetFrameName.empty())
469 localRobot, robotStateComponent, time.toMicroSeconds());
471 framedPointCloud.
changeFrame(targetFrameName, localRobot);
480 else if (sourceFrameName.empty())
486 else if (targetFrameName.empty())
498 pcl::removeNaNFromPointCloud(*resultCloudPtr, *resultCloudPtr,
indices);
507 counter = freezeImageIdx.load();
516 bool FakePointCloudProvider::processRGBImage(
const PCLPointCloud2Ptr& pointCloud)
518 pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudptr(
new pcl::PointCloud<pcl::PointXYZRGB>());
519 pcl::fromPCLPointCloud2(*pointCloud, *cloudptr);
521 if (!cloudptr->isOrganized())
527 if (
static_cast<int>(cloudptr->width) != rgbImages[0]->width
528 ||
static_cast<int>(cloudptr->height) != rgbImages[0]->height)
530 ARMARX_WARNING <<
"Dimensions of point cloud and image do not match, so no RGB image is generated";
534 ::ImageProcessor::Zero(rgbImages[0]);
535 const int width =
static_cast<int>(cloudptr->width);
536 const int height =
static_cast<int>(cloudptr->height);
538 for (
int i = 0; i < height; i++)
540 for (
int j = 0; j < width; j++)
542 pcl::PointXYZRGB& point = cloudptr->at(
static_cast<std::size_t
>(i * width + j));
543 rgbImages[0]->pixels[3 * (i * width + j) + 0] = point.r;
544 rgbImages[0]->pixels[3 * (i * width + j) + 1] = point.g;
545 rgbImages[0]->pixels[3 * (i * width + j) + 2] = point.b;
554 for (std::size_t i = 0; i < 1; i++)
574 return !targetFrameName.empty() ? targetFrameName : sourceFrameName;
598 prx.
getValue(removeNAN,
"removeNAN");
599 prx.
getValue(scaleFactor,
"scaleFactor");
600 prx.
getValue(freezeImage,
"freezeImage");
603 prx.
getValue(freezeImageIdx,
"freezeImageIdx");
607 prx.
setValue(counter,
"freezeImageIdx");