29#include <pcl/common/colors.h>
30#include <pcl/filters/statistical_outlier_removal.h>
31#include <pcl/surface/convex_hull.h>
33#include <SimoxUtility/math/convert/mat4f_to_pos.h>
34#include <SimoxUtility/math/convert/mat4f_to_rpy.h>
35#include <SimoxUtility/math/convert/pos_rpy_to_mat4f.h>
36#include <VirtualRobot/CollisionDetection/CollisionModel.h>
37#include <VirtualRobot/MathTools.h>
38#include <VirtualRobot/math/Helpers.h>
60 "RobotStateComponentName",
"RobotStateComponent",
"Name of the robot state component.");
63 "sourceFrameNameAuto",
65 "If enabled, try to get and use source frame name from point cloud provider.");
67 "sourceFrameName",
"DepthCamera",
"The source frame name.");
73 "Format of the input and output point cloud (XYZRGBA, XYZL, XYZRGBL).");
81 "Enable StatisticalOutlierRemoval (pre downsampling)");
83 "StatisticalOutlierRemoval_MeanK",
85 "(pcl parameter) number of nearest neighbors to use for mean distance estimation. ");
88 "(pcl parameter) standard deviation multiplier for the "
89 "distance threshold calculation. ");
93 Eigen::Vector3f(-1000.0f, -1000.0f, 0.0f),
94 "Minimal point of cropping box.",
97 Eigen::Vector3f(4800.0f, 11500.0f, 1800.0f),
98 "Maximal point of cropping box.",
103 "Roll, Pitch and Yaw applied to the points in the croping frame",
107 "ProviderFrameTranslation", Eigen::Vector3f(0.0f, 0.0f, 0.0f),
"",
',');
109 "ProviderFrameRotation", Eigen::Vector3f(0.0f, 0.0f, 0.0f),
"",
',');
112 "croppingFrame",
"Global",
"The coordinate frame in which cropping is applied.");
116 "Discard points that appear to belong to the robot itself.");
119 "RemoteGuiName",
"RemoteGuiProvider",
"Name of the remote GUI provider");
123 "If cropping is enabled, the points outside of the area are "
124 "reported in a separate cloud");
130 return "PointCloudFilter";
142 std::unique_lock lock(parametersMutex);
143 return parameters.targetFrameName;
148 const Vector3BasePtr&
max,
149 const std::string& frame,
152 std::unique_lock lock(parametersMutex);
153 parameters.croppingEnabled =
true;
154 parameters.croppingMinPoint = Vector3Ptr::dynamicCast(
min)->toEigen();
155 parameters.croppingMaxPoint = Vector3Ptr::dynamicCast(
max)->toEigen();
156 parameters.croppingFrameName = frame;
165 getProperty(parameters.sourceFrameName,
"sourceFrameName");
166 getProperty(parameters.targetFrameName,
"targetFrameName");
168 getProperty(parameters.croppingEnabled,
"EnableCropping");
169 getProperty(parameters.croppingFrameName,
"croppingFrame");
170 getProperty(parameters.croppingMinPoint,
"minPoint");
171 getProperty(parameters.croppingMaxPoint,
"maxPoint");
174 getProperty(parameters.downsamplingEnabled,
"EnableDownsampling");
177 getProperty(parameters.statisticalOutlierRemoval.enabled,
178 "StatisticalOutlierRemoval_enabled");
179 getProperty(parameters.statisticalOutlierRemoval.meanK,
"StatisticalOutlierRemoval_MeanK");
180 getProperty(parameters.statisticalOutlierRemoval.stddevMulThresh,
181 "StatisticalOutlierRemoval_StddevMulThresh");
184 parameters.providerFrameTransformation = simox::math::pos_rpy_to_mat4f(
190 if (!robotStateComponentName.empty())
196 ARMARX_INFO <<
"No RobotStateComponent configured, not performing any point cloud "
200 getProperty(parameters.applyCollisionModelFilter,
"applyCollisionModelFilter");
201 getProperty(parameters.reportCloudOutsideOfCroppingArea,
202 "reportCloudOutsideOfCroppingArea");
203 if (parameters.applyCollisionModelFilter && robotStateComponentName.empty())
205 ARMARX_WARNING <<
"Collision model filter activated, but no RobotStateComponent "
206 "configured, deactivating collision model filtering";
207 parameters.applyCollisionModelFilter =
false;
210 debugDrawer.setLayer(
getName());
211 debugDrawer.offeringTopic(*
this);
212 debugDrawer.setEnabled(
false);
218 const std::string robotStateComponentName =
220 if (!robotStateComponentName.empty())
222 getProxy(robotStateComponent, robotStateComponentName);
224 robotStateComponent, VirtualRobot::RobotIO::RobotDescription::eStructure);
232 if (
getProperty<bool>(
"sourceFrameNameAuto") && !providerSourceFrameName.empty())
234 ARMARX_INFO <<
"Using source frame '" << providerSourceFrameName
235 <<
"' from provider '" << providerNames.front() <<
"'.";
236 this->parameters.sourceFrameName = providerSourceFrameName;
240 if (pointCloudFormat ==
"XYZRGBA")
245 else if (pointCloudFormat ==
"XYZL")
250 else if (pointCloudFormat ==
"XYZRGBL")
257 ARMARX_ERROR <<
"Could not initialize point cloud, because format '" << pointCloudFormat
259 <<
"\nKnown formats are: XYZL, XYZRGBA, XYZGBL.";
268 remoteGuiTask->start();
271 debugDrawer.getTopic(*
this);
273 debugDrawer.getTopic()->clearLayer(debugDrawer.getLayer());
284 if (pointCloudFormat ==
"XYZRGBA")
288 else if (pointCloudFormat ==
"XYZL")
292 else if (pointCloudFormat ==
"XYZRGBL")
298 ARMARX_ERROR <<
"Could not process point cloud, because format '" << pointCloudFormat
300 <<
"\nKnown formats are: XYZL, XYZRGBA, XYZRGBL.";
309 remoteGuiTask->stop();
310 remoteGuiTask =
nullptr;
314 remoteGui->removeTab(
getName());
319 toUpper(
const std::string&
string)
322 std::transform(
string.begin(),
string.end(), std::back_inserter(upper), ::toupper);
326 template <
typename Po
intT>
330 using PointCloudPtr =
typename pcl::PointCloud<PointT>::Ptr;
335 std::unique_lock lock(parametersMutex);
336 params = this->parameters;
341 PointCloudPtr tempCloud(
new pcl::PointCloud<PointT>());
350 ARMARX_VERBOSE <<
"Timeout or error while waiting for point cloud data.";
354 const uint32_t originalWidth = inputCloud.
cloud->width;
355 const uint32_t originalHeight = inputCloud.
cloud->height;
358 if (robotStateComponent)
363 long timestampMicroseconds =
static_cast<long>(inputCloud.
cloud->header.stamp);
365 (void)timestampMicroseconds;
369 if (params.statisticalOutlierRemoval.
enabled)
373 pcl::StatisticalOutlierRemoval<PointT> sor;
374 sor.setMeanK(params.statisticalOutlierRemoval.
meanK);
375 sor.setStddevMulThresh(params.statisticalOutlierRemoval.
stddevMulThresh);
377 sor.setInputCloud(inputCloud.
cloud);
379 sor.filter(*tempCloud);
380 tempCloud.swap(inputCloud.
cloud);
383 if (params.downsamplingEnabled)
387 pcl::ApproximateVoxelGrid<PointT> grid;
388 grid.setLeafSize(params.gridLeafSize, params.gridLeafSize, params.gridLeafSize);
389 grid.setInputCloud(inputCloud.
cloud);
392 grid.filter(*tempCloud);
394 tempCloud.swap(inputCloud.
cloud);
399 ARMARX_DEBUG <<
"transformBy\n" << params.providerFrameTransformation;
400 inputCloud.
transformBy(params.providerFrameTransformation);
403 if (params.croppingEnabled)
408 changePointCloudFrame(inputCloud,
"cropping", params.croppingFrameName);
410 catch (
const armarx::LocalException& e)
413 <<
"Caught armarx::LocalException (stopping processing).\n"
423 outsideCloud.
cloud->clear();
426 VirtualRobot::MathTools::rpy2eigen3f(params.croppingRPY).inverse();
427 for (
const auto& p : inputCloud.
cloud->points)
429 const Eigen::Vector3f transfed =
transform * Eigen::Vector3f{p.x, p.y, p.z};
430 if (transfed(0) >= params.croppingMinPoint(0) &&
431 transfed(0) <= params.croppingMaxPoint(0) &&
432 transfed(1) >= params.croppingMinPoint(1) &&
433 transfed(1) <= params.croppingMaxPoint(1) &&
434 transfed(2) >= params.croppingMinPoint(2) &&
435 transfed(2) <= params.croppingMaxPoint(2))
437 tempCloud->push_back(p);
439 else if (params.reportCloudOutsideOfCroppingArea)
441 outsideCloud.
cloud->push_back(p);
444 tempCloud.swap(inputCloud.
cloud);
447 if (debugDrawer.enabled())
451 aabb.col(0) = params.croppingMinPoint;
452 aabb.col(1) = params.croppingMaxPoint;
453 debugDrawer.drawBoxEdges(
"cropBox",
456 VirtualRobot::MathTools::rpy2eigen4f(params.croppingRPY));
460 debugDrawer.removeboxEdges(
"cropBox");
463 const bool collisionModelFilterEnabled =
464 params.applyCollisionModelFilter && robotStateComponent;
465 if (collisionModelFilterEnabled)
469 if (params.reportCloudOutsideOfCroppingArea)
476 PointCloudPtr collisionCloudPtr(
new pcl::PointCloud<PointT>());
478 for (VirtualRobot::CollisionModelPtr collisionModel : localRobot->getCollisionModels())
480 std::vector<Eigen::Vector3f> vertices = collisionModel->getModelVeticesGlobal();
482 pcl::PointCloud<PointT> hullCloud;
483 hullCloud.width =
static_cast<uint32_t
>(vertices.size());
484 hullCloud.height = 1;
485 hullCloud.points.resize(vertices.size());
486 for (
size_t i = 0; i < vertices.size(); ++i)
488 hullCloud.points[i].getVector3fMap() = vertices[i].cast<
float>();
491 (*collisionCloudPtr) += hullCloud;
494 pcl::ConvexHull<PointT> hull;
495 hull.setInputCloud(collisionCloudPtr);
496 hull.setDimension(3);
498 std::vector<pcl::Vertices> polygons;
499 PointCloudPtr surfaceHull(
new pcl::PointCloud<PointT>);
500 hull.reconstruct(*surfaceHull, polygons);
502 pcl::CropHull<PointT> cropHull;
504 cropHull.setHullIndices(polygons);
505 cropHull.setHullCloud(surfaceHull);
506 cropHull.setCropOutside(
false);
507 cropHull.setInputCloud(inputCloud.
cloud);
510 cropHull.filter(*tempCloud);
512 tempCloud.swap(inputCloud.
cloud);
514 if (params.reportCloudOutsideOfCroppingArea)
516 cropHull.setInputCloud(outsideCloud.
cloud);
518 cropHull.filter(*tempCloud);
519 tempCloud.swap(outsideCloud.
cloud);
527 changePointCloudFrame(inputCloud,
"target", params.targetFrameName);
528 if (params.reportCloudOutsideOfCroppingArea)
530 changePointCloudFrame(
531 outsideCloud,
"collision model filter", params.targetFrameName);
534 catch (
const armarx::LocalException& e)
537 <<
"Caught armarx::LocalException (stopping processing).\n"
543 PointCloudPtr resultCloud = inputCloud.
cloud;
546 << originalHeight <<
" --> Filtered cloud " << resultCloud->width <<
" x "
547 << resultCloud->height;
554 PointCloudFilter::drawFrame(
const FramedPose& frame,
const std::string& role)
562 template <
typename Po
intT>
565 const std::string& role,
566 const std::string& frame)
568 ARMARX_DEBUG <<
"Transform from " << pointCloud.getFrame() <<
" to " << toUpper(role)
569 <<
" (" << frame <<
")";
570 pointCloud.changeFrame(frame, localRobot);
571 drawFrame(pointCloud.getFramedPose(localRobot), role);
582 PointCloudFilter::remoteGuiCreate()
586 const auto& p = parameters;
603 .
value(p.sourceFrameName)))
609 .
value(p.targetFrameName))
614 .addChild(
makeCheckBox(
"StatisticalOutlierRemoval_enabled")
616 .
value(p.statisticalOutlierRemoval.enabled))
621 .
value(p.statisticalOutlierRemoval.meanK))
627 .
value(p.statisticalOutlierRemoval.stddevMulThresh)))
633 .
value(p.downsamplingEnabled))
639 .
value(p.gridLeafSize)))
644 .
value(p.applyCollisionModelFilter)));
649 const Eigen::Vector3f pos = simox::math::mat4f_to_pos(p.providerFrameTransformation);
650 const Eigen::Vector3f rpy = simox::math::mat4f_to_rpy(p.providerFrameTransformation);
681 .
value(p.reportCloudOutsideOfCroppingArea)
682 .
label(
"Report points outside");
686 .addOptions(localRobot->getRobotNodeNames())
687 .
value(p.croppingFrameName);
693 .
value(p.croppingRPY)
709 rootLayout.addChild(
makeGroupBox(
"CropGroup").label(
"Cropping").child(cropGroupLayout));
722 makeGroupBox(
"VisuGroup").label(
"Visualization").child(visuGroupLayout));
726 const std::string tabName =
getName();
727 remoteGui->createTab(tabName, rootLayout);
728 remoteGuiTab = armarx::RemoteGui::TabProxy(remoteGui, tabName);
732 PointCloudFilter::remoteGuiRun()
734 int cycleDurationMs = 50;
735 CycleUtil
c(cycleDurationMs);
736 while (!remoteGuiTask->isStopped())
738 remoteGuiTab.receiveUpdates();
740 remoteGuiUpdate(remoteGuiTab);
742 remoteGuiTab.sendUpdates();
743 c.waitForCycleDuration();
748 PointCloudFilter::remoteGuiUpdate(RemoteGui::TabProxy& tab)
750 using namespace armarx::RemoteGui;
753 std::unique_lock lock(parametersMutex);
756 ValueProxy<std::string> sourceFrame = tab.
getValue<std::string>(
"SourceFrame");
758 if (tab.
getValue<
bool>(
"SourceFrameAutoEnabled").get())
760 parameters.sourceFrameName = this->providerSourceFrameName;
761 sourceFrame.
set(parameters.sourceFrameName);
766 parameters.sourceFrameName = sourceFrame.
get();
770 tab.
getValue(parameters.targetFrameName,
"TargetFrame");
773 tab.
getValue(parameters.downsamplingEnabled,
"DownsamplingEnabled");
774 tab.
getValue(parameters.gridLeafSize,
"DownsamplingGridLeafSize");
775 tab.
getValue(parameters.applyCollisionModelFilter,
"CollisionModelFilterEnabled");
776 tab.
getValue(parameters.reportCloudOutsideOfCroppingArea,
777 "reportCloudOutsideOfCroppingArea");
778 tab.
getValue(parameters.statisticalOutlierRemoval.enabled,
779 "StatisticalOutlierRemoval_enabled");
780 tab.
getValue(parameters.statisticalOutlierRemoval.meanK,
781 "StatisticalOutlierRemoval_MeanK");
782 tab.
getValue(parameters.statisticalOutlierRemoval.stddevMulThresh,
783 "StatisticalOutlierRemoval_StddevMulThresh");
786 tab.
getValue(parameters.croppingEnabled,
"CropEnabled");
787 tab.
getValue(parameters.croppingFrameName,
"CropFrame");
788 tab.
getValue(parameters.croppingMinPoint,
"CropMin");
789 tab.
getValue(parameters.croppingMaxPoint,
"CropMax");
790 tab.
getValue(parameters.croppingRPY,
"CropRPY");
792 parameters.providerFrameTransformation =
793 simox::math::pos_rpy_to_mat4f(tab.
getValue<Eigen::Vector3f>(
"transform.XYC").get(),
794 tab.
getValue<Eigen::Vector3f>(
"transform.RPY").get());
798 bool visuEnabled = tab.
getValue<
bool>(
"VisuEnabled").get();
802 debugDrawer.clearLayer(
false);
805 debugDrawer.setEnabled(visuEnabled);
#define ARMARX_REGISTER_COMPONENT_EXECUTABLE(ComponentT, applicationName)
SpamFilterDataPtr deactivateSpam(SpamFilterDataPtr const &spamFilter, float deactivationDurationSec, const std::string &identifier, bool deactivate)
bool usingProxyFromProperty(const std::string &propertyName, const std::string &endpoints="")
Use a proxy whose name is specified by the given property.
ProxyType getProxyFromProperty(const std::string &propertyName, bool addToDependencies=false, const std::string &endpoints="", bool throwOnProxyError=true)
Get a proxy whose name is specified by the given property.
std::string getConfigIdentifier()
Retrieve config identifier for this component as set in constructor.
Property< PropertyType > getProperty(const std::string &name)
void drawPose(const VisuID &id, const Eigen::Matrix4f &pose, bool ignoreLengthScale=false)
Draw a pose (with the preset scale).
bool enabled() const
Indicate whether visualization is enabled, i.e. a topic is set and enabled flag is set.
std::string getFrame() const
std::string getName() const
Retrieve name of object.
Ice::ObjectPrx getProxy(long timeoutMs=0, bool waitForScheduler=true) const
Returns the proxy of this object (optionally it waits for the proxy)
virtual Eigen::Matrix4f toEigen() const
PropertyDefinition< EigenVectorType > & defineOptionalPropertyVector(const std::string &name, EigenVectorType defaultValue, const std::string &description="", const std::string &delimiter=" ", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
Define a required property for an Eigen vector type.
std::string prefix
Prefix of the properties such as namespace, domain, component name, etc.
PropertyDefinition< PropertyType > & defineOptionalProperty(const std::string &name, PropertyType defaultValue, const std::string &description="", PropertyDefinitionBase::PropertyConstness constness=PropertyDefinitionBase::eConstant)
ValueProxy< T > getValue(std::string const &name)
void set(std::atomic< T1 > const &value)
static VirtualRobot::RobotPtr createLocalCloneFromFile(RobotStateComponentInterfacePrx robotStatePrx, VirtualRobot::RobotIO::RobotDescription loadMode=VirtualRobot::RobotIO::eFull)
This is a convenience function for createLocalClone, which automatically gets the filename from the R...
static bool synchronizeLocalClone(VirtualRobot::RobotPtr robot, RobotStateComponentInterfacePrx robotStatePrx)
A point cloud which keeps track of its reference coordinate frame and allows changing frames using ar...
void setFrameWithoutTransformation(const std::string &f)
armarx::FramedPose getFramedPose(const std::string &agentName) const
Get the current pose as FramedPose.
void transformBy(const Eigen::Matrix4f &transform)
PointCloudPtrT cloud
The point cloud.
Eigen::Matrix4f getGlobalPose(const VirtualRobot::RobotConstPtr &robot) const
Get the current global pose.
std::string getFrame() const
Get the current frame.
PointCloudFilterPropertyDefinitions(std::string prefix)
Brief description of class PointCloudFilter.
armarx::PropertyDefinitionsPtr createPropertyDefinitions() override
virtual void process() override
virtual void onExitPointCloudProcessor() override
virtual std::string getReferenceFrame(const Ice::Current &=Ice::emptyCurrent) override
virtual void onConnectPointCloudProcessor() override
virtual void onDisconnectPointCloudProcessor() override
static std::string GetDefaultName()
virtual void setCroppingParameters(const armarx::Vector3BasePtr &min, const armarx::Vector3BasePtr &max, const std::string &frame, const Ice::Current &=Ice::emptyCurrent) override
virtual void onInitPointCloudProcessor() override
std::string getDefaultName() const override
Retrieve default name of component.
PointCloudProcessorPropertyDefinitions(std::string prefix)
std::string getPointCloudFrame(const std::string &providerName, const std::string &defaultFrame="")
Get the reference frame of the point cloud by given provider.
void enableResultPointClouds(std::string resultProviderName="")
Enables visualization.
int getPointClouds(const PointCloudPtrT &pointCloudPtr)
Poll PointClouds from provider.
bool waitForPointClouds(int milliseconds=1000)
Wait for new PointClouds.
void provideResultPointClouds(const PointCloudPtrT &pointClouds, std::string providerName="")
sends result PointClouds for visualization
std::vector< std::string > getPointCloudProviderNames() const
Get the names of providers for which usingPointCloudProvider() has been called.
#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.
#define ARMARX_ERROR
The logging level for unexpected behaviour, that must be fixed.
#define ARMARX_DEBUG
The logging level for output that is only interesting while debugging.
#define ARMARX_WARNING
The logging level for unexpected behaviour, but not a serious problem.
#define ARMARX_VERBOSE
The logging level for verbose information.
std::string const GlobalFrame
Variable of the global coordinate system.
Matrix< float, 3, 2 > Matrix32f
A 3x2 matrix.
detail::IntSpinBoxBuilder makeIntSpinBox(std::string const &name)
detail::CheckBoxBuilder makeCheckBox(std::string const &name)
detail::ComboBoxBuilder makeComboBox(std::string const &name)
detail::VBoxLayoutBuilder makeVBoxLayout(std::string const &name="")
detail::FloatSpinBoxBuilder makeFloatSpinBox(std::string const &name)
detail::LabelBuilder makeTextLabel(std::string const &text)
detail::HBoxLayoutBuilder makeHBoxLayout(std::string const &name="")
detail::Vector3fSpinBoxesBuilder makeVector3fSpinBoxes(std::string const &name, float limpos=1000)
detail::SimpleGridLayoutBuilder makeSimpleGridLayout(std::string const &name="")
detail::GroupBoxBuilder makeGroupBox(std::string const &name="")
This file offers overloads of toIce() and fromIce() functions for STL container types.
auto transform(const Container< InputT, Alloc > &in, OutputT(*func)(InputT const &)) -> Container< OutputT, typename std::allocator_traits< Alloc >::template rebind_alloc< OutputT > >
Convenience function (with less typing) to transform a container of type InputT into the same contain...
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
std::vector< T > max(const std::vector< T > &v1, const std::vector< T > &v2)
std::vector< T > min(const std::vector< T > &v1, const std::vector< T > &v2)
SimpleRunningTask(Ts...) -> SimpleRunningTask< std::function< void(void)> >
std::shared_ptr< Value > value()
Derived & addChild(WidgetPtr const &child)
ComboBoxBuilder & addOptions(std::vector< std::string > const &options)
ComboBoxBuilder & options(std::vector< std::string > const &options)
Derived & label(std::string const &label)
SimpleGridLayoutBuilder & addChild(WidgetPtr const &child, int colspan)
Derived & value(ValueT const &value)
Vector3fSpinBoxesBuilder & decimals(const Eigen::Vector3i decimals)