27 #include <boost/lexical_cast.hpp>
35 #include <AffordanceKit/primitives/Plane.h>
36 #include <AffordanceKit/primitives/Cylinder.h>
37 #include <AffordanceKit/primitives/Sphere.h>
38 #include <AffordanceKit/primitives/Box.h>
39 #include <AffordanceKit/PrimitiveExtractor.h>
41 #include <pcl/common/colors.h>
52 void PrimitiveExtractor::onInitPointCloudProcessor()
54 lastProcessedTimestamp = 0;
56 providerName = getProperty<std::string>(
"segmenterName").getValue();
59 minSegmentSize = getProperty<double>(
"minimumSegmentSize").getValue();
60 maxSegmentSize = getProperty<double>(
"maximumSegmentSize").getValue();
61 pMaxIter = getProperty<double>(
"planeMaximumIteration").getValue();
62 pDistThres = getProperty<float>(
"planeDistanceThreshold").getValue();
63 pNorDist = getProperty<float>(
"planeNormalDistance").getValue();
64 cMaxIter = getProperty<double>(
"cylinderMaximumIteration").getValue();
65 cDistThres = getProperty<float>(
"cylinderDistanceThreshold").getValue();
66 cRadLim = getProperty<float>(
"cylinderRadiousLimit").getValue();
67 sMaxIter = getProperty<double>(
"sphereMaximumIteration").getValue();
68 sDistThres = getProperty<float>(
"sphereDistanceThreshold").getValue();
69 sNorDist = getProperty<float>(
"sphereNormalDistance").getValue();
70 verbose = getProperty<bool>(
"vebose").getValue();
71 euclideanClusteringTolerance = getProperty<float>(
"euclideanClusteringTolerance").getValue();
72 outlierThreshold = getProperty<float>(
"outlierThreshold").getValue();
73 circleDistThres = getProperty<float>(
"circularDistanceThreshold").getValue();
75 spatialSamplingDistance = getProperty<float>(
"SpatialSamplingDistance").getValue();
76 numOrientationalSamplings = getProperty<int>(
"NumOrientationalSamplings").getValue();
84 primitiveExtractor.reset(
new AffordanceKit::PrimitiveExtractor());
85 primitiveExtractor->updateParameters(verbose, minSegmentSize, maxSegmentSize, pMaxIter, pDistThres, pNorDist, cMaxIter, cDistThres, cRadLim, sMaxIter, sDistThres, sNorDist, euclideanClusteringTolerance, outlierThreshold, circleDistThres);
86 usingPointCloudProvider(providerName);
88 if (getProperty<std::string>(
"RobotStateComponentName").getValue() !=
"")
90 usingProxy(getProperty<std::string>(
"RobotStateComponentName").getValue());
91 sourceFrameName = getProperty<std::string>(
"sourceFrameName").getValue();
93 usingProxy(getProperty<std::string>(
"WorkingMemoryName").getValue());
95 mappingEnabled =
true;
97 enablePrimitiveFusion = getProperty<bool>(
"enablePrimitiveFusion").getValue();
99 offeringTopic(getProperty<std::string>(
"DebugDrawerTopicName").getValue());
100 offeringTopic(getProperty<std::string>(
"SegmentedPointCloudTopicName").getValue());
102 offeringTopic(getProperty<std::string>(
"DebugObserverName").getValue());
106 void PrimitiveExtractor::onConnectPointCloudProcessor()
108 enableResultPointClouds<PointXYZL>(
"GraspPointCloudResult");
109 enableResultPointClouds<PointXYZL>(
"PrimitiveExtractorResult");
110 enableResultPointClouds<PointXYZL>(
"Inliers");
112 workingMemory = getProxy<memoryx::WorkingMemoryInterfacePrx>(getProperty<std::string>(
"WorkingMemoryName").getValue());
115 ARMARX_ERROR <<
"Failed to obtain working memory proxy";
118 environmentalPrimitiveSegment = workingMemory->getEnvironmentalPrimitiveSegment();
119 if (!environmentalPrimitiveSegment)
121 ARMARX_ERROR <<
"Failed to obtain environmental primitive segment pointer";
124 pointCloudSegmentationPrx = getTopic<visionx::PointCloudSegmentationListenerPrx>(getProperty<std::string>(
"SegmentedPointCloudTopicName").getValue());
126 debugDrawerTopicPrx = getTopic<DebugDrawerInterfacePrx>(getProperty<std::string>(
"DebugDrawerTopicName").getValue());
128 if (getProperty<std::string>(
"RobotStateComponentName").getValue() !=
"")
130 robotStateComponent = getProxy<RobotStateComponentInterfacePrx>(getProperty<std::string>(
"RobotStateComponentName").getValue());
131 if (!robotStateComponent->getSynchronizedRobot()->hasRobotNode(sourceFrameName))
134 robotStateComponent =
nullptr;
140 debugDrawerTopicPrx->clearLayer(
"primitiveMapper");
142 debugObserver = getTopic<DebugObserverInterfacePrx>(getProperty<std::string>(
"DebugObserverName").getValue());
147 debugValues[
"processingTime"] =
new Variant(0.0);
148 debugValues[
"oldPrimitives"] =
new Variant(0.0);
149 debugValues[
"visiblePrimitives"] =
new Variant(0.0);
150 debugValues[
"newPrimitives"] =
new Variant(0.0);
151 debugValues[
"modifiedPrimitives"] =
new Variant(0.0);
152 debugValues[
"unmodifiedPrimitives"] =
new Variant(0.0);
153 debugValues[
"removedPrimitives"] =
new Variant(0.0);
154 debugValues[
"numViews"] =
new Variant(0.0);
155 debugObserver->setDebugChannel(getName(), debugValues);
158 void PrimitiveExtractor::onDisconnectPointCloudProcessor()
163 void PrimitiveExtractor::onExitPointCloudProcessor()
167 void PrimitiveExtractor::enablePipelineStep(
const Ice::Current&
c)
169 std::unique_lock lock(enableMutex);
170 mappingEnabled =
true;
173 void PrimitiveExtractor::disablePipelineStep(
const Ice::Current&
c)
175 std::unique_lock lock(enableMutex);
176 mappingEnabled =
false;
179 void PrimitiveExtractor::process()
181 if (!waitForPointClouds(providerName, 10000))
187 std::unique_lock lock(enableMutex);
198 pcl::PointCloud<pcl::PointXYZRGBL>::Ptr temp(
new pcl::PointCloud<pcl::PointXYZRGBL>());
199 if (!getPointClouds(providerName, temp))
205 pcl::copyPointCloud(*temp, *labeledCloudPtr);
206 if (labeledCloudPtr->size() == 0)
210 provideResultPointClouds(labeledCloudPtr,
"GraspPointCloudResult");
211 provideResultPointClouds(labeledCloudPtr,
"PrimitiveExtractorResult");
217 inliersCloudPtr = primitiveExtractor->computeScenePrimitives(labeledCloudPtr);
218 graspCloudPtr = primitiveExtractor->getDetectedGraspPoints();
221 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr >& planeInliers = primitiveExtractor->getPlaneInliers();
222 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr >& cylinderInliers = primitiveExtractor->getCylinderInliers();
223 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr >& sphereInliers = primitiveExtractor->getSphereInliers();
224 const std::vector<float>& circularityProbabilities = primitiveExtractor->getCircularityProbabilities();
226 ARMARX_INFO <<
" ********* Detected Plane number: " << planeInliers.size();
227 ARMARX_INFO <<
" ********* Detected Cylinder number: " << cylinderInliers.size();
228 ARMARX_INFO <<
" ********* Detected Sphere number: " << sphereInliers.size();
229 ARMARX_INFO <<
" ********* Detected Circle Probabilities: " << circularityProbabilities.size();
232 provideResultPointClouds(graspCloudPtr,
"GraspPointCloudResult");
233 provideResultPointClouds(inliersCloudPtr,
"PrimitiveExtractorResult");
235 ARMARX_INFO <<
"Primitive Extraction took " << (IceUtil::Time::now() - startTime).toSecondsDouble() <<
" secs";
238 startTime = IceUtil::Time::now();
242 std::unique_lock lock(enableMutex);
248 if (getProperty<bool>(
"UseAffordanceExtractionLibExport").getValue())
250 pushPrimitivesToMemoryAffordanceKit(temp->header.stamp);
254 pushPrimitivesToMemory(temp->header.stamp);
258 std::unique_lock lock(timestampMutex);
259 lastProcessedTimestamp = temp->header.stamp;
264 pointCloudSegmentationPrx->reportNewPointCloudSegmentation();
267 ARMARX_INFO <<
"Mapping took " << (IceUtil::Time::now() - startTime).toSecondsDouble() <<
" secs";
270 float PrimitiveExtractor::getGraspPointInlierRatio(memoryx::EnvironmentalPrimitiveBasePtr leftPrimitive, memoryx::EnvironmentalPrimitiveBasePtr rightPrimitive)
272 FramedPosePtr pose = FramedPosePtr::dynamicCast(rightPrimitive->getPose());
275 Eigen::Vector3f oBBDimensions = Vector3Ptr::dynamicCast(rightPrimitive->getOBBDimensions())->toEigen();
276 Eigen::Vector3f extent = 0.5 * oBBDimensions + (Eigen::Vector3f::Ones() * 50);
278 float numPoints = 0.0;
279 memoryx::PointList graspPoints = leftPrimitive->getGraspPoints();
281 for (Vector3BasePtr& p : graspPoints)
283 Eigen::Vector4f temp = Eigen::Vector4f(p->x, p->y, p->z, 1.0);
284 Eigen::Vector3f point = (worldToPrimitive * temp).head<3>();
286 if ((point.array().abs() < extent.array()).all())
292 return numPoints / graspPoints.size();
297 void PrimitiveExtractor::fusePrimitives(std::vector<memoryx::EntityBasePtr>& newPrimitives,
long timestamp)
300 std::vector<EnvironmentalPrimitiveBasePtr> primitives = environmentalPrimitiveSegment->getEnvironmentalPrimitives();
303 std::vector<memoryx::EnvironmentalPrimitiveBasePtr> nonVisiblePrimitives;
304 std::vector<memoryx::EnvironmentalPrimitiveBasePtr> visiblePrimitives;
306 std::vector<memoryx::EnvironmentalPrimitiveBasePtr> modifiedPrimitives;
307 std::set<std::string> processedPrimitives;
308 std::set<std::string> primitivesToRemove;
310 if (robotStateComponent)
315 auto snapshot = robotStateComponent->getRobotSnapshotAtTimestamp(timestamp);
317 FramedPoseBasePtr pose = snapshot->getRobotNode(sourceFrameName)->getGlobalPose();
319 cameraToWorld = armarx::FramedPosePtr::dynamicCast(pose)->toEigen();
322 primitiveFilter.updateCameraPosition(cameraToWorld);
325 primitiveFilter.visualizeFrustum(debugDrawerTopicPrx);
327 primitiveFilter.getPrimitivesInFieldOfView(primitives, visiblePrimitives, nonVisiblePrimitives);
332 ARMARX_ERROR <<
"Frustum culling not possible without RobotStateComponent assuming that all primitives are visible";
333 visiblePrimitives = primitives;
337 if (getProperty<bool>(
"EnableBoxPrimitives").
getValue())
341 for (
const EnvironmentalPrimitiveBasePtr& p : primitives)
343 if (p->ice_isA(memoryx::BoxPrimitiveBase::ice_staticId()))
345 primitivesToRemove.insert(p->getId());
350 if (nonVisiblePrimitives.size())
352 ARMARX_INFO <<
"found " << nonVisiblePrimitives.size() <<
" non visible primitives in field of view.";
353 for (memoryx::EnvironmentalPrimitiveBasePtr& p : nonVisiblePrimitives)
355 p->setProbability(
std::max(0.0, p->getProbability() - 0.1));
356 if (p->getProbability() <= 0.4)
358 primitivesToRemove.insert(p->getId());
362 modifiedPrimitives.push_back(p);
368 ARMARX_DEBUG <<
"total primitives " << primitives.size() <<
" visible primitives " << visiblePrimitives.size() <<
"new primitives" << newPrimitives.size();
370 std::vector<memoryx::EntityBasePtr> uniqueEntities;
371 for (
const memoryx::EntityBasePtr& newEntity : newPrimitives)
373 memoryx::EnvironmentalPrimitiveBasePtr newPrimitive = memoryx::EnvironmentalPrimitiveBasePtr::dynamicCast(newEntity);
375 std::vector<EnvironmentalPrimitiveBasePtr> intersectingPrimitives;
376 fusionStrategy.getIntersectingSimilarPrimitives(primitives, newPrimitive, intersectingPrimitives, 50.0);
380 bool addPrimitive =
true;
381 for (EnvironmentalPrimitiveBasePtr& intersectingPrimitive : intersectingPrimitives)
383 if (primitivesToRemove.count(intersectingPrimitive->getId()))
388 int currentLabel = 0;
389 float inlierRatioLeft = getGraspPointInlierRatio(newPrimitive, intersectingPrimitive);
390 float inlierRatioRight = getGraspPointInlierRatio(intersectingPrimitive, newPrimitive);
392 if (inlierRatioLeft <= 0.1 && inlierRatioRight <= 0.1)
394 processedPrimitives.insert(intersectingPrimitive->getId());
397 if (inlierRatioLeft >= 0.9 && inlierRatioRight >= 0.9)
399 intersectingPrimitive->setTime(newPrimitive->getTime());
400 float newProbability = std::fmax(newPrimitive->getProbability(), intersectingPrimitive->getProbability() + 0.15);
401 intersectingPrimitive->setProbability(std::fmin(1.0, newProbability));
402 modifiedPrimitives.push_back(intersectingPrimitive);
404 addPrimitive =
false;
407 else if (inlierRatioLeft <= 0.3 && inlierRatioRight >= 0.7)
410 primitivesToRemove.insert(intersectingPrimitive->getId());
412 else if (inlierRatioLeft >= 0.7 && inlierRatioRight <= 0.3)
415 addPrimitive =
false;
418 else if ((inlierRatioLeft + inlierRatioRight) >= 1.4)
420 if ((newPrimitive->getOBBDimensions()->x * newPrimitive->getOBBDimensions()->y) > (intersectingPrimitive->getOBBDimensions()->x * intersectingPrimitive->getOBBDimensions()->y))
422 primitivesToRemove.insert(intersectingPrimitive->getId());
426 addPrimitive =
false;
434 else if (intersectingPrimitive->getLabel())
436 currentLabel = intersectingPrimitive->getLabel();
439 if (currentLabel == 0 && intersectingPrimitives.size())
441 currentLabel = ++lastUsedLabel;
443 newPrimitive->setLabel(currentLabel);
445 for (EnvironmentalPrimitiveBasePtr& x : intersectingPrimitives)
447 x->setLabel(currentLabel);
448 modifiedPrimitives.push_back(x);
453 uniqueEntities.push_back(newPrimitive);
457 if (robotStateComponent)
460 for (memoryx::EnvironmentalPrimitiveBasePtr& p : visiblePrimitives)
463 if (processedPrimitives.count(p->getId()) || primitivesToRemove.count(p->getId()))
468 float probability = p->getProbability();
469 p->setProbability(
std::max(0.0, p->getProbability() - 0.5));
470 ARMARX_LOG <<
"reducing probability for primitive in field of view: " << p->getId() <<
" from " << probability <<
" to " << p->getProbability();
472 if (p->getProbability() <= 0.4)
474 ARMARX_LOG <<
"scheduling primitive " << p->getId() <<
" for removal";
475 primitivesToRemove.insert(p->getId());
479 modifiedPrimitives.push_back(p);
487 ARMARX_INFO <<
"removing " << primitivesToRemove.size() <<
" primitives";
489 for (
const std::string& x : primitivesToRemove)
491 environmentalPrimitiveSegment->removeEntity(x);
495 processedPrimitives.clear();
496 for (EnvironmentalPrimitiveBasePtr& x : modifiedPrimitives)
498 if (!primitivesToRemove.count(x->getId()) && !processedPrimitives.count(x->getId()))
501 environmentalPrimitiveSegment->updateEntity(x->getId(), x);
502 processedPrimitives.insert(x->getId());
506 float unmodified = primitives.size() - modified - primitivesToRemove.size();
508 ARMARX_INFO <<
"Writing segmentation (" << uniqueEntities.size() <<
" primitives) to memory";
510 environmentalPrimitiveSegment->addEntityList(uniqueEntities);
513 debugValues[
"processingTime"] =
new Variant((TimeUtil::GetTime().toMicroSeconds() - timestamp) / (1000.0 * 1000.0));
514 debugValues[
"oldPrimitives"] =
new Variant((
float) primitives.size());
515 debugValues[
"visiblePrimitives"] =
new Variant((
float) visiblePrimitives.size());
516 debugValues[
"newPrimitives"] =
new Variant((
float) uniqueEntities.size());
517 debugValues[
"modifiedPrimitives"] =
new Variant(modified);
518 debugValues[
"unmodifiedPrimitives"] =
new Variant(unmodified);
519 debugValues[
"removedPrimitives"] =
new Variant((
float) primitivesToRemove.size());
521 debugValues[
"numViews"] =
new Variant((
int) numViews);
522 debugObserver->setDebugChannel(getName(), debugValues);
524 pcl::PointCloud<pcl::PointXYZL>::Ptr inliers(
new pcl::PointCloud<pcl::PointXYZL>());
525 for (
const EnvironmentalPrimitiveBasePtr& x : primitives)
527 if (primitivesToRemove.count(x->getId()))
532 for (
const armarx::Vector3BasePtr&
v : x->getInliers())
535 p.label = x->getLabel();
539 inliers->points.push_back(p);
543 for (
const memoryx::EntityBasePtr& e : uniqueEntities)
547 for (
const armarx::Vector3BasePtr&
v : x->getInliers())
550 p.label = x->getLabel();
554 inliers->points.push_back(p);
560 inliers->width = inliers->points.size();
563 provideResultPointClouds(inliers,
"Inliers");
569 void PrimitiveExtractor::pushPrimitivesToMemory(IceUtil::Int64 originalTimestamp)
571 std::vector<memoryx::EntityBasePtr> newPrimitives;
573 const std::vector<pcl::ModelCoefficients::Ptr>& planeCoefficients = primitiveExtractor->getPlaneCoefficients();
574 const std::vector<pcl::ModelCoefficients::Ptr>& cylinderCoefficients = primitiveExtractor->getCylinderCoefficients();
575 const std::vector<pcl::ModelCoefficients::Ptr>& sphereCoefficients = primitiveExtractor->getSphereCoefficients();
576 const std::vector<float>& circularityProbabilities = primitiveExtractor->getCircularityProbabilities();
578 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr>& planeInliers = primitiveExtractor->getPlaneInliers();
579 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr>& cylinderInliers = primitiveExtractor->getCylinderInliers();
580 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr>& sphereInliers = primitiveExtractor->getSphereInliers();
582 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr>& cylinderGraspPoints = primitiveExtractor->getCylinderGraspPoints();
583 const std::vector<pcl::PointCloud<pcl::PointXYZL>::Ptr>& sphereGraspPoints = primitiveExtractor->getSphereGraspPoints();
588 for (
size_t i = 0 ; i < planeCoefficients.size(); i++)
591 pcl::ModelCoefficients::Ptr coefficients = planeCoefficients[i];
592 pcl::PointCloud<pcl::PointXYZL>::Ptr inliers = planeInliers[i];
594 pcl::PointCloud<pcl::PointXYZL>::Ptr graspPoints(
new pcl::PointCloud<pcl::PointXYZL>());
596 pcl::PointCloud<pcl::PointXYZL>::Ptr temp(
new pcl::PointCloud<pcl::PointXYZL>());
597 pcl::ProjectInliers<PointL> proj;
598 proj.setModelType(pcl::SACMODEL_PLANE);
599 proj.setInputCloud(inliers);
600 proj.setModelCoefficients(coefficients);
605 pcl::ConcaveHull<PointL> concaveHull;
606 concaveHull.setInputCloud(temp);
607 concaveHull.setDimension(2);
608 concaveHull.setAlpha(69.0);
610 concaveHull.reconstruct(*graspPoints);
613 ARMARX_LOG << __LINE__ <<
" done computing hull";
616 pcl::MomentOfInertiaEstimation <pcl::PointXYZL> bb;
617 pcl::PointXYZL min_point_OBB, max_point_OBB, position_OBB;
620 bb.setInputCloud(graspPoints);
622 bb.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
624 Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
625 Vector3Ptr dimension =
new Vector3(max_point_OBB.x * 2, max_point_OBB.y * 2, max_point_OBB.z * 2);
629 pcl::PointXYZL pointMin, pointMax;
630 pcl::getMinMax3D<pcl::PointXYZL>(*inliers, pointMin, pointMax);
631 float length = (pointMax.getVector3fMap() - pointMin.getVector3fMap()).
norm();
634 EnvironmentalPrimitiveBasePtr primitive;
636 primitive->setOBBDimensions(dimension);
637 primitive->setPose(pose);
638 primitive->setProbability(0.75);
639 primitive->setLabel(0);
641 primitive->setLength(length);
642 primitive->setCircularityProbability(circularityProbabilities[i]);
644 primitive->setName(
"environmentalPrimitive_" + boost::lexical_cast<std::string>(label++));
647 PointList graspPointList(graspPoints->points.size());
648 for (
size_t p = 0; p < graspPoints->points.size(); p++)
650 Vector3Ptr currPoint =
new Vector3(graspPoints->points[p].x, graspPoints->points[p].y, graspPoints->points[p].z);
651 graspPointList[p] = currPoint;
653 primitive->setGraspPoints(graspPointList);
655 PointList inlierList(inliers->points.size());
656 for (
size_t p = 0; p < inliers->points.size(); p++)
658 const Eigen::Vector3f& f = inliers->points[p].getVector3fMap();
659 inlierList[p] =
new Vector3(f);
661 primitive->setInliers(inlierList);
667 std::vector<Eigen::Vector3f>
convexHull(graspPointList.size());
668 for (
unsigned int i = 0; i < graspPointList.size(); i++)
670 convexHull[i] = armarx::Vector3Ptr::dynamicCast(graspPointList[i])->toEigen();
672 AffordanceKit::PlanePtr plane(
new AffordanceKit::Plane(
convexHull));
673 plane->sample(spatialSamplingDistance, numOrientationalSamplings);
675 primitive->setSampling(
s);
679 newPrimitives.push_back(primitive);
685 for (
size_t i = 0 ; i < cylinderCoefficients.size(); i++)
688 pcl::ModelCoefficients::Ptr coefficients = cylinderCoefficients[i];
689 pcl::PointCloud<pcl::PointXYZL>::Ptr inliers = cylinderInliers[i];
690 pcl::PointCloud<pcl::PointXYZL>::Ptr graspPoints = cylinderGraspPoints[i];
692 pcl::PointCloud<pcl::PointXYZL>::Ptr temp(
new pcl::PointCloud<pcl::PointXYZL>());
693 pcl::ProjectInliers<PointL> proj;
694 proj.setModelType(pcl::SACMODEL_PLANE);
695 proj.setInputCloud(inliers);
696 proj.setModelCoefficients(coefficients);
699 pcl::ConcaveHull<PointL> concaveHull;
700 concaveHull.setInputCloud(temp);
701 concaveHull.setDimension(2);
702 concaveHull.setAlpha(69.0);
703 concaveHull.setKeepInformation(
true);
704 concaveHull.reconstruct(*graspPoints);
707 pcl::MomentOfInertiaEstimation <pcl::PointXYZL> bb;
708 pcl::PointXYZL min_point_OBB, max_point_OBB, position_OBB;
711 bb.setInputCloud(inliers);
713 bb.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
715 Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
716 Vector3Ptr dimension =
new Vector3(max_point_OBB.x * 2, max_point_OBB.y * 2, max_point_OBB.z * 2);
721 float min_t = std::numeric_limits<float>::infinity();
722 float max_t = -std::numeric_limits<float>::infinity();
724 Eigen::Vector3f b(coefficients->values[0], coefficients->values[1], coefficients->values[2]);
725 Eigen::Vector3f d(coefficients->values[3], coefficients->values[4], coefficients->values[5]);
728 for (
unsigned int i = 0; i < inliers->points.size(); i++)
730 Eigen::Vector3f
v(inliers->points[i].x, inliers->points[i].y, inliers->points[i].z);
732 float t = (
v - b).
dot(d) / d.dot(d);
738 float length = max_t - min_t;
739 Eigen::Vector3f base = b + min_t * d + 0.5 * length * d;
740 Eigen::Vector3f direction = d;
741 float radius = coefficients->values[6];
744 CylinderPrimitiveBasePtr primitive;
746 primitive->setCylinderPoint(
new Vector3(base));
747 primitive->setCylinderAxisDirection(
new Vector3(direction));
748 primitive->setCylinderRadius(radius);
749 primitive->setLength(length);
750 primitive->setOBBDimensions(dimension);
751 primitive->setPose(pose);
752 primitive->setProbability(0.75);
753 primitive->setLabel(0);
755 primitive->setCircularityProbability(0.0);
759 PointList graspPointList(graspPoints->points.size());
761 for (
size_t p = 0; p < graspPoints->points.size(); p++)
763 Vector3Ptr currPoint =
new Vector3(graspPoints->points[p].x, graspPoints->points[p].y, graspPoints->points[p].z);
764 graspPointList[p] = currPoint;
767 primitive->setName(
"environmentalPrimitive_" + boost::lexical_cast<std::string>(planeCoefficients.size() + i));
768 primitive->setGraspPoints(graspPointList);
771 AffordanceKit::CylinderPtr cylinder(
new AffordanceKit::Cylinder(base, direction, length, radius));
772 cylinder->sample(spatialSamplingDistance, numOrientationalSamplings);
774 primitive->setSampling(
s);
778 newPrimitives.push_back(primitive);
784 for (
size_t i = 0 ; i < sphereCoefficients.size(); i++)
787 pcl::ModelCoefficients::Ptr coefficients = sphereCoefficients[i];
788 pcl::PointCloud<pcl::PointXYZL>::Ptr inliers = sphereInliers[i];
789 pcl::PointCloud<pcl::PointXYZL>::Ptr graspPoints = sphereGraspPoints[i];
796 pcl::MomentOfInertiaEstimation <pcl::PointXYZL> bb;
797 pcl::PointXYZL min_point_OBB, max_point_OBB, position_OBB;
800 bb.setInputCloud(inliers);
802 bb.getOBB(min_point_OBB, max_point_OBB, position_OBB, rotational_matrix_OBB);
804 Eigen::Vector3f position(position_OBB.x, position_OBB.y, position_OBB.z);
805 Vector3Ptr dimension =
new Vector3(max_point_OBB.x * 2, max_point_OBB.y * 2, max_point_OBB.z * 2);
810 pcl::PointXYZL pointMin, pointMax;
811 pcl::getMinMax3D<pcl::PointXYZL>(*inliers, pointMin, pointMax);
812 float length = (pointMax.getVector3fMap() - pointMin.getVector3fMap()).
norm();
815 EnvironmentalPrimitiveBasePtr primitive = {};
817 primitive->setOBBDimensions(dimension);
818 primitive->setPose(pose);
819 primitive->setLabel(0);
820 primitive->setProbability(0.75);
822 primitive->setLength(length);
823 primitive->setCircularityProbability(0.0);
827 PointList graspPointList(graspPoints->points.size());
829 for (
size_t p = 0; p < graspPoints->points.size(); p++)
831 Vector3Ptr currPoint =
new Vector3(graspPoints->points[p].x, graspPoints->points[p].y, graspPoints->points[p].z);
832 graspPointList[p] = currPoint;
835 primitive->setName(
"environmentalPrimitive_" + boost::lexical_cast<std::string>(cylinderCoefficients.size() + planeCoefficients.size() + i));
836 primitive->setGraspPoints(graspPointList);
839 Eigen::Vector3f center(coefficients->values[0], coefficients->values[1], coefficients->values[2]);
840 float radius = coefficients->values[3];
841 AffordanceKit::SpherePtr sphere(
new AffordanceKit::Sphere(center, radius));
842 sphere->sample(spatialSamplingDistance, numOrientationalSamplings);
844 primitive->setSampling(
s);
848 newPrimitives.push_back(primitive);
852 ARMARX_LOG << __LINE__ <<
" writing primitives to memory.";
854 if (enablePrimitiveFusion)
856 fusePrimitives(newPrimitives, originalTimestamp);
860 ARMARX_LOG << __LINE__ <<
" removing previous primitives from memory.";
861 environmentalPrimitiveSegment->removeAllEntities();
863 environmentalPrimitiveSegment->addEntityList(newPrimitives);
867 ARMARX_LOG << __LINE__ <<
"done writing primitives to memory.";
869 if (getProperty<bool>(
"EnableBoxPrimitives").
getValue())
871 newPrimitives.clear();
873 std::vector<EnvironmentalPrimitiveBasePtr> primitives = environmentalPrimitiveSegment->getEnvironmentalPrimitives();
876 unsigned int sz = newPrimitives.size();
877 fusionStrategy.findBoxPrimitives(primitives, newPrimitives, environmentalPrimitiveSegment);
880 for (
auto& primitive : newPrimitives)
888 Eigen::Matrix4f pose = PosePtr::dynamicCast(box->getPose())->toEigen();
889 Eigen::Vector3f dimensions = Vector3Ptr::dynamicCast(box->getOBBDimensions())->toEigen();
890 AffordanceKit::BoxPtr b(
new AffordanceKit::Box(pose, dimensions));
891 b->sample(getProperty<float>(
"SpatialSamplingDistance").
getValue(), getProperty<int>(
"NumOrientationalSamplings").
getValue());
896 ARMARX_INFO <<
"Found " << (newPrimitives.size() - sz) <<
" Box primitives";
898 environmentalPrimitiveSegment->addEntityList(newPrimitives);
902 void PrimitiveExtractor::pushPrimitivesToMemoryAffordanceKit(IceUtil::Int64 originalTimestamp)
904 AffordanceKit::PrimitiveSetPtr ps = primitiveExtractor->getPrimitiveSet(getProperty<float>(
"SpatialSamplingDistance").
getValue(), getProperty<int>(
"NumOrientationalSamplings").
getValue(), originalTimestamp);
906 primitiveSet.writeToMemory(environmentalPrimitiveSegment);
916 std::unique_lock lock(enableMutex);
917 return mappingEnabled;
922 std::unique_lock lock(timestampMutex);
929 primitiveExtractor->updateParameters(verbose, parameters.minSegmentSize, parameters.maxSegmentSize,
930 parameters.planeMaxIterations, parameters.planeDistanceThreshold, parameters.planeNormalDistance,
931 parameters.cylinderMaxIterations, parameters.cylinderDistanceThreshold, parameters.cylinderRadiusLimit,
932 parameters.sphereMaxIterations, parameters.sphereDistanceThreshold, parameters.sphereNormalDistance,
933 parameters.euclideanClusteringTolerance, parameters.outlierThreshold, parameters.circularDistanceThreshold);
936 void PrimitiveExtractor::loadParametersFromFile(
const std::string&
filename,
const Ice::Current&
c)
938 std::string absolute_filename;
939 ArmarXDataPath::getAbsolutePath(
filename, absolute_filename);
941 ARMARX_INFO <<
"Loading parameter setup from " << absolute_filename;
942 QSettings config(QString::fromStdString(absolute_filename), QSettings::IniFormat);
944 config.beginGroup(
"PrimitiveExtraction");
946 primitiveExtractor->updateParameters(verbose,
947 config.value(
"MinPrimitiveSize", getProperty<double>(
"minimumSegmentSize").getValue()).toDouble(),
948 config.value(
"MaxPrimitiveSize", getProperty<double>(
"maximumSegmentSize").getValue()).toDouble(),
949 config.value(
"PlaneMaxIterations", getProperty<double>(
"planeMaximumIteration").getValue()).toDouble(),
950 config.value(
"PlaneDistanceThreshold", getProperty<float>(
"planeDistanceThreshold").getValue()).toFloat(),
951 config.value(
"PlaneNormalDistance", getProperty<float>(
"planeNormalDistance").getValue()).toFloat(),
952 config.value(
"CylinderMaxIterations", getProperty<double>(
"cylinderMaximumIteration").getValue()).toDouble(),
953 config.value(
"CylinderDistanceThreshold", getProperty<float>(
"cylinderDistanceThreshold").getValue()).toFloat(),
954 config.value(
"CylinderRadiusLimit", getProperty<float>(
"cylinderRadiousLimit").getValue()).toFloat(),
955 config.value(
"SphereMaxIterations", getProperty<double>(
"sphereMaximumIteration").getValue()).toDouble(),
956 config.value(
"SphereDistanceThreshold", getProperty<float>(
"sphereDistanceThreshold").getValue()).toFloat(),
957 config.value(
"SphereNormalDistance", getProperty<float>(
"sphereNormalDistance").getValue()).toFloat(),
958 config.value(
"EuclideanClusteringTolerance", getProperty<float>(
"euclideanClusteringTolerance").getValue()).toFloat(),
959 config.value(
"OutlierDistanceThreshold", getProperty<float>(
"outlierThreshold").getValue()).toFloat(),
960 config.value(
"PlaneCircularDistanceThreshold", getProperty<float>(
"circularDistanceThreshold").getValue()).toFloat()
968 visionx::PrimitiveExtractorParameters parameters;
969 parameters.minSegmentSize = primitiveExtractor->minSegmentSize;
970 parameters.maxSegmentSize = primitiveExtractor->maxSegmentSize;
971 parameters.planeMaxIterations = primitiveExtractor->planeMaxIteration;
972 parameters.planeDistanceThreshold = primitiveExtractor->planeMaxIteration;
973 parameters.planeNormalDistance = primitiveExtractor->planeNormalDistanceWeight;
974 parameters.cylinderMaxIterations = primitiveExtractor->cylinderMaxIteration;
975 parameters.cylinderDistanceThreshold = primitiveExtractor->cylinderDistanceThreshold;
976 parameters.cylinderRadiusLimit = primitiveExtractor->cylinderRadiusLimit;
978 parameters.sphereMaxIterations = primitiveExtractor->sphereMaxIteration;
979 parameters.sphereDistanceThreshold = primitiveExtractor->sphereDistanceThreshold;
980 parameters.sphereNormalDistance = primitiveExtractor->sphereNormalDistanceWeight;
981 parameters.euclideanClusteringTolerance = primitiveExtractor->euclideanClusteringTolerance;
982 parameters.outlierThreshold = primitiveExtractor->outlierThreshold;
983 parameters.circularDistanceThreshold = primitiveExtractor->circleDistanceThreshold;