25 #include <pcl/filters/approximate_voxel_grid.h>
28 #include <pangolin/pangolin.h>
30 #include <Image/IplImageAdaptor.h>
34 #include <VisionX/interface/components/PointCloudAndImageAndCalibrationProviderInterface.h>
35 #include <VisionX/interface/components/RGBDImageProvider.h>
37 #include <Eigen/Geometry>
39 #include <Core/Model/Model.h>
47 imageProviderName = getProperty<std::string>(
"ImageProviderName").getValue();
57 imageProvider = getProxy<visionx::ImageProviderInterfacePrx>(imageProviderName);
63 <<
") does not match the expected number of images (" << numImages <<
")";
67 std::lock_guard<std::mutex> lock(imagesMutex);
71 images[0] = imageRgb.get();
72 images[1] = imageDepth.get();
78 std::lock_guard<std::mutex> lock(imagesMutex);
82 imageRgb.reset(
nullptr);
83 imageDepth.reset(
nullptr);
85 imageProvider =
nullptr;
107 ImageProcessor::onInitComponent();
108 CapturingPointCloudProvider::onInitComponent();
110 framesBetweenUpdates = getProperty<int>(
"FramesBetweenUpdates").getValue();
111 downsamplingLeafSize = getProperty<float>(
"DownsamplingLeafSize").getValue();
113 framesSinceLastUpdate = framesBetweenUpdates;
115 resultPointCloud.reset(
new pcl::PointCloud<OutPointT>());
120 cofusionParams.
timeDelta = getProperty<int>(
"cofusion.TimeDelta").getValue();
121 cofusionParams.
countThresh = getProperty<int>(
"cofusion.CountThresh").getValue();
122 cofusionParams.
errThresh = getProperty<float>(
"cofusion.ErrThresh").getValue();
123 cofusionParams.
covThresh = getProperty<float>(
"cofusion.CovThresh").getValue();
124 cofusionParams.
closeLoops = getProperty<bool>(
"cofusion.CloseLoops").getValue();
125 cofusionParams.
iclnuim = getProperty<bool>(
"cofusion.Iclnuim").getValue();
126 cofusionParams.
reloc = getProperty<bool>(
"cofusion.Reloc").getValue();
127 cofusionParams.
photoThresh = getProperty<float>(
"cofusion.PhotoThresh").getValue();
128 cofusionParams.
initConfidenceGlobal = getProperty<float>(
"cofusion.InitConfidenceGlobal").getValue();
129 cofusionParams.
initConfidenceObject = getProperty<float>(
"cofusion.InitConfidenceObject").getValue();
130 cofusionParams.
depthCut = getProperty<float>(
"cofusion.DepthCut").getValue();
131 cofusionParams.
icpThresh = getProperty<float>(
"cofusion.IcpThresh").getValue();
132 cofusionParams.
fastOdom = getProperty<bool>(
"cofusion.FastOdom").getValue();
133 cofusionParams.
fernThresh = getProperty<float>(
"cofusion.FernThresh").getValue();
134 cofusionParams.
so3 = getProperty<bool>(
"cofusion.So3").getValue();
135 cofusionParams.
frameToFrameRGB = getProperty<bool>(
"cofusion.FrameToFrameRGB").getValue();
136 cofusionParams.
modelSpawnOffset = getProperty<unsigned>(
"cofusion.ModelSpawnOffset").getValue();
137 cofusionParams.
matchingType = getProperty<Model::MatchingType>(
"cofusion.MatchingType").getValue();
138 cofusionParams.
exportDirectory = getProperty<std::string>(
"cofusion.ExportDirectory").getValue();
141 #if USE_MASKFUSION == 1
142 cofusionParams.usePrecomputedMasksOnly = getProperty<bool>(
"cofusion.UsePrecomputedMasksOnly").getValue();
143 cofusionParams.frameQueueSize = getProperty<int>(
"cofusion.FrameQueueSize").getValue();
151 ImageProcessor::onConnectComponent();
152 CapturingPointCloudProvider::onConnectComponent();
157 visionx::StereoCalibrationProviderInterfacePrx calibrationProvider = visionx::StereoCalibrationProviderInterfacePrx::checkedCast(imageProvider);
159 if (calibrationProvider)
161 ARMARX_LOG <<
"reading intrinsics from calibration provider";
162 visionx::StereoCalibration calibration = calibrationProvider->getStereoCalibration();
164 cofusionParams.
fx = calibration.calibrationRight.cameraParam.focalLength[0];
165 cofusionParams.
fy = calibration.calibrationRight.cameraParam.focalLength[1];
166 cofusionParams.
cx = calibration.calibrationRight.cameraParam.principalPoint[0];
167 cofusionParams.
cy = calibration.calibrationRight.cameraParam.principalPoint[1];
169 referenceFrameName = calibrationProvider->getReferenceFrame();
173 cofusionParams.
fx = 525.0;
174 cofusionParams.
fy = 525.0;
175 cofusionParams.
cx = 320;
176 cofusionParams.
cy = 240;
177 referenceFrameName =
"unkown";
178 ARMARX_WARNING <<
"unable to get camera intrinsics. using dummy values";
182 visionx::ImageFormatInfo imageFormat = imageProvider->getImageFormat();
184 cofusionParams.
width = imageFormat.dimension.width;
185 cofusionParams.
height = imageFormat.dimension.height;
188 if (getProperty<bool>(
"ShowTimeStats").getValue())
190 if (stopwatchReportTask)
192 stopwatchReportTask->stop();
196 stopwatchReportTask->start();
199 providePointCloud<OutPointT>(resultPointCloud);
205 ImageProcessor::onDisconnectComponent();
206 CapturingPointCloudProvider::onDisconnectComponent();
211 ImageProcessor::onExitComponent();
212 CapturingPointCloudProvider::onExitComponent();
232 ARMARX_WARNING <<
"Timeout or error in waitForImages(" << imageProviderName <<
")";
238 std::lock_guard<std::mutex> lock(imagesMutex);
240 armarx::MetaInfoSizeBasePtr metaInfo;
242 int numImages =
getImages(imageProviderName, images, metaInfo);
245 ARMARX_WARNING <<
"Did not receive correct number of images! (Expected 2, but was "
246 << numImages <<
".) Aborting!";
252 initializeCoFusion();
265 stopwatch.start(
"CoFusion::ProcessFrame");
267 #if USE_MASKFUSION == 1
268 std::shared_ptr<FrameData> framePtr = std::make_shared<FrameData>(frame);
270 cofusion->processFrame(framePtr);
272 cofusion->processFrame(frame);
275 stopwatch.stop(
"CoFusion::ProcessFrame");
278 framesSinceLastUpdate++;
279 if (framesSinceLastUpdate >= framesBetweenUpdates)
282 framesSinceLastUpdate = 0;
291 void CoFusionProcessor::initializeCoFusion()
293 ARMARX_INFO <<
"Initializing CoFusion (resolution: " << cofusionParams.
width <<
"x" << cofusionParams.
height <<
")";
295 pangolin::Params windowParams;
296 windowParams.Set(
"SAMPLE_BUFFERS", 0);
297 windowParams.Set(
"SAMPLES", 0);
299 pangolin::CreateWindowAndBind(
"Main", cofusionParams.
width, cofusionParams.
height, windowParams);
302 GLenum glewInitError = glewInit();
305 ARMARX_ERROR <<
"glewInit() failed with error: " << glewInitError;
308 int prog = glCreateProgram();
309 ARMARX_INFO <<
"Created gl program (" << prog <<
")";
316 cofusion->addNewModelListener([
this](std::shared_ptr<Model> m)
320 cofusion->addInactiveModelListener([
this](std::shared_ptr<Model> m)
325 #if USE_MASKFUSION == 1
326 cofusion->preallocateModels(getProperty<int>(
"cofusion.PreallocatedModelsCount").getValue());
331 FrameData CoFusionProcessor::constructFrameData()
333 bool copyData =
false;
334 cv::Mat matRgb = cv::cvarrToMat(IplImageAdaptor::Adapt(imageRgb.get()), copyData);
335 cv::Mat matDepth = cv::cvarrToMat(IplImageAdaptor::Adapt(imageDepth.get()), copyData);
344 int rows = matDepth.rows;
345 int cols = matDepth.cols;
349 cv::Mat matDepthCofusion(rows, cols, CV_32FC1);
351 for (
int x = 0; x < rows; ++x)
353 for (
int y = 0; y < cols; ++y)
375 cv::Vec3b depthPixel = matDepth.at<cv::Vec3b>(x, y);
378 value += depthPixel[0];
379 value += depthPixel[1] << 8;
380 value += depthPixel[2] << 16;
395 matDepthCofusion.at<
float>(x, y) = depth;
399 frame.depth = matDepthCofusion;
406 void CoFusionProcessor::updateSurfelMaps()
408 std::list<std::shared_ptr<Model>>& models = cofusion->getModels();
416 std::lock_guard<std::mutex> lock(surfelMapMutex);
418 ARMARX_INFO <<
"Downloading surfel maps of " << models.size() <<
" models ...";
420 for (std::shared_ptr<Model>
const& model : models)
422 unsigned int id = model->getID();
429 surfelMaps[id] = model->downloadMap();
433 Model::SurfelMap& surfelMap = surfelMaps[id];
434 ARMARX_VERBOSE <<
"SurfelMap contains " << surfelMap.numPoints <<
" points "
435 <<
"(container size: " << surfelMap.data->size() <<
")";
441 newFrameAvailable =
true;
452 ARMARX_WARNING <<
"CoFusionProcessor does currently not support startCaptureForNumFrames(numFrames)";
461 if (newFrameAvailable)
463 newFrameAvailable =
false;
464 resultPointCloud.reset();
465 reconstructResultPointCloud();
466 providePointCloud<OutPointT>(resultPointCloud);
475 void CoFusionProcessor::reconstructResultPointCloud()
477 std::lock_guard<std::mutex> lock(surfelMapMutex);
479 resultPointCloud.reset(
new pcl::PointCloud<OutPointT>());
482 ARMARX_INFO <<
"Reconstructing point cloud from " << surfelMaps.size() <<
" SurfelMaps.";
483 stopwatch.start(
"PointCloud construction");
485 for (
auto& it : surfelMaps)
487 unsigned int id = it.first;
488 Model::SurfelMap& surfelMap = it.second;
492 <<
" contains " << surfelMap.numPoints <<
" points "
493 <<
"(container size: " << surfelMap.data->size() <<
")";
504 resultPointCloud->reserve(resultPointCloud->size() + surfelMap.numPoints);
506 for (
unsigned int i = 0; i < surfelMap.numPoints; ++i)
508 Eigen::Vector4f& position4f = (*surfelMap.data)[i * 3 + 0];
509 position4f.head<3>() *= 1000;
511 Eigen::Vector4f& color4f = (*surfelMap.data)[i * 3 + 1];
514 uint32_t color24b =
static_cast<uint32_t
>(color4f(0));
515 uchar r = (color24b >> 16) & 0xFF;
516 uchar g = (color24b >> 8) & 0xFF;
517 uchar b = (color24b >> 0) & 0xFF;
524 pcl::PointXYZRGBL point;
525 point.x = position4f(0);
526 point.y = position4f(1);
527 point.z = position4f(2);
532 resultPointCloud->push_back(point);
539 if (downsamplingLeafSize > 0.f)
541 pcl::PointCloud<OutPointT>::Ptr filtered(
new pcl::PointCloud<OutPointT>());
542 std::size_t sizeBefore = resultPointCloud->size();
544 pcl::ApproximateVoxelGrid<OutPointT> grid;
545 grid.setLeafSize(downsamplingLeafSize, downsamplingLeafSize, downsamplingLeafSize);
546 grid.setInputCloud(resultPointCloud);
547 grid.filter(*filtered);
548 resultPointCloud.swap(filtered);
550 std::size_t sizeAfter = resultPointCloud->size();
552 ARMARX_INFO <<
"Downsampled to " << sizeAfter <<
" points (before: " << sizeBefore <<
")";
555 stopwatch.stop(
"PointCloud construction");
560 visionx::MetaPointCloudFormatPtr info =
new visionx::MetaPointCloudFormat();
561 info->capacity = 50 * 640 * 480 *
sizeof(visionx::ColoredLabeledPoint3D);
562 info->size = info->capacity;
563 info->type = visionx::eColoredLabeledPoints;
567 void CoFusionProcessor::reportStopwatchStats()