PointCloudObjectLocalizer.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of ArmarX.
3  *
4  * Copyright (C) 2011-2016, High Performance Humanoid Technologies (H2T), Karlsruhe Institute of Technology (KIT), all rights reserved.
5  *
6  * ArmarX is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * ArmarX is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * @package VisionX::ArmarXObjects::PointCloudObjectLocalizer
19  * @author Markus Grotz ( markus dot grotz at kit dot edu )
20  * @date 2015
21  * @copyright http://www.gnu.org/licenses/gpl-2.0.txt
22  * GNU General Public License
23  */
24 
26 
27 #include <pcl/PointIndices.h>
28 
30 
31 
32 using namespace armarx;
33 
34 namespace visionx
35 {
36 
37 
38  void
39  PointCloudObjectLocalizer::onInitPointCloudProcessor()
40  {
41  std::scoped_lock lock(pointCloudMutex);
42 
43  pcl::console::setVerbosityLevel(pcl::console::L_ALWAYS);
44 
45  providerName = getProperty<std::string>("providerName").getValue();
46 
47  ARMARX_LOG << "using point cloud provider " << providerName << flush;
48 
49  agentName = getProperty<std::string>("agentName").getValue();
50 
51  sourceNodeName = getProperty<std::string>("sourceNodeName").getValue();
52 
53  icpOnly = getProperty<bool>("icpOnly").getValue();
54 
55  icp.setMaximumIterations(100);
56  icp.setMaxCorrespondenceDistance(500.0);
57 
58  modelKeypoints.reset(new pcl::PointCloud<PointT>);
59 
60  std::string modelFileName = getProperty<std::string>("modelFileName").getValue();
61  armarx::CMakePackageFinder finder("VisionX");
63  pcl::PointCloud<PointT>::Ptr cloudPtr(new pcl::PointCloud<PointT>());
64  if (!ArmarXDataPath::getAbsolutePath(modelFileName, modelFileName))
65  {
66  ARMARX_FATAL << "Could not find point cloud file in ArmarXDataPath: " << modelFileName;
67  return;
68  }
69  else if (pcl::io::loadPCDFile<PointT>(modelFileName.c_str(), *cloudPtr) == -1)
70  {
71  ARMARX_FATAL << "unable to load point cloud from file " << modelFileName;
72  return;
73  }
74 
75  float leafSize = getProperty<float>("sceneLeafSize").getValue();
76  grid.setLeafSize(Eigen::Vector3f(leafSize, leafSize, leafSize));
77 
78  grid.setInputCloud(cloudPtr);
79  grid.filter(*modelKeypoints);
80 
81  if (!icpOnly)
82 
83  {
84  modelDescriptors.reset(new pcl::PointCloud<PointD>());
85 
86  pcl::PointCloud<pcl::Normal>::Ptr pointCloudModelNormals(
87  new pcl::PointCloud<pcl::Normal>);
88  ARMARX_DEBUG << "computing normals";
89  normalEstimation.setInputCloud(cloudPtr);
90  normalEstimation.setRadiusSearch(10.0);
91  normalEstimation.compute(*pointCloudModelNormals);
92 
93  ARMARX_DEBUG << "computing features";
94  featureEstimation.setInputCloud(modelKeypoints);
95  featureEstimation.setInputNormals(pointCloudModelNormals);
96  featureEstimation.setSearchSurface(cloudPtr);
97  featureEstimation.setRadiusSearch(20.0);
98  featureEstimation.compute(*modelDescriptors);
99 
100  matchSearchTree.setInputCloud(modelDescriptors);
101 
102  clusterer.setGCSize(getProperty<double>("recGCSize").getValue());
103  clusterer.setGCThreshold(getProperty<int>("recGCThreshold").getValue());
104  clusterer.setInputCloud(modelKeypoints);
105  }
106 
107 
108  offeringTopic(getProperty<std::string>("DebugDrawerTopic").getValue());
109 
110  usingPointCloudProvider(providerName);
111  }
112 
113  void
114  PointCloudObjectLocalizer::onConnectPointCloudProcessor()
115  {
116  std::scoped_lock lock(pointCloudMutex);
117 
118  debugDrawerPrx = getTopic<DebugDrawerInterfacePrx>(
119  getProperty<std::string>("DebugDrawerTopic").getValue());
120 
121  enableResultPointClouds<PointT>("Input");
122  enableResultPointClouds<PointT>("BeforeICPResult");
123  enableResultPointClouds<PointT>("AfterICPResult");
124  enableResultPointClouds<PointT>("BestMatch");
125  }
126 
127  void
128  PointCloudObjectLocalizer::onDisconnectPointCloudProcessor()
129  {
130  }
131 
132  void
133  PointCloudObjectLocalizer::onExitPointCloudProcessor()
134  {
135  }
136 
137  void
138  PointCloudObjectLocalizer::process()
139  {
140 
141  std::scoped_lock lock(pointCloudMutex);
142 
143  pcl::PointCloud<PointL>::Ptr cloudPtr(new pcl::PointCloud<PointL>());
144 
145  if (!waitForPointClouds(providerName, 10000))
146  {
147  ARMARX_WARNING << "Timeout or error while waiting for point cloud data"
148  << armarx::flush;
149  return;
150  }
151  else
152  {
153  getPointClouds(providerName, cloudPtr);
154  }
155 
156  float bestFitnessScore = std::numeric_limits<float>::max();
157  Eigen::Matrix4f bestTransform = Eigen::Matrix4f::Identity();
158 
159  pcl::PointCloud<PointT>::Ptr afterICPResultPointCloud(new pcl::PointCloud<PointT>());
160  pcl::PointCloud<PointT>::Ptr beforeICPResultPointCloud(new pcl::PointCloud<PointT>());
161 
162  std::map<uint32_t, pcl::PointIndices> labeledPointMap;
163  visionx::tools::fillLabelMap<pcl::PointCloud<PointL>::Ptr>(cloudPtr, labeledPointMap);
164 
165  for (auto& it : labeledPointMap)
166  {
167 
168  ARMARX_LOG << " checking label " << it.first;
169 
170  pcl::PointCloud<PointT>::Ptr segment(new pcl::PointCloud<PointT>());
171  copyPointCloud(*cloudPtr, it.second, *segment);
172 
173  pcl::PointCloud<PointT>::Ptr transformedCloudPtr(new pcl::PointCloud<PointT>());
174  pcl::PointCloud<PointT>::Ptr cloudDownsampledPtr(new pcl::PointCloud<PointT>());
175  pcl::PointCloud<pcl::Normal>::Ptr normalPtr(new pcl::PointCloud<pcl::Normal>());
176  pcl::PointCloud<PointD>::Ptr descriptorPtr(new pcl::PointCloud<PointD>());
177  pcl::CorrespondencesPtr correspondencesPtr(new pcl::Correspondences());
178 
179  pcl::copyPointCloud(*segment, *transformedCloudPtr);
180 
181  grid.setInputCloud(transformedCloudPtr);
182  grid.filter(*cloudDownsampledPtr);
183 
184  provideResultPointClouds(cloudDownsampledPtr, "Input");
185 
186  std::vector<Eigen::Matrix4f, Eigen::aligned_allocator<Eigen::Matrix4f>> transformations;
187 
188  if (icpOnly)
189  {
190  Eigen::Vector4f centroid;
191  pcl::compute3DCentroid(*cloudDownsampledPtr, centroid);
192 
193  for (float i = 0.0; i < 360.0; i += 45.0)
194  {
195  Eigen::Affine3f transform(
196  Eigen::AngleAxisf(i * 180.0 / M_PI, Eigen::Vector3f::UnitZ()));
197 
198  Eigen::Matrix4f transform2 = transform.matrix();
199  transform2.col(3) = centroid;
200  transformations.push_back(transform2);
201  }
202  }
203  else
204  {
205  ARMARX_LOG << "computing normals";
206  normalEstimation.setInputCloud(transformedCloudPtr);
207  normalEstimation.compute(*normalPtr);
208 
209  ARMARX_LOG << "computing features";
210  featureEstimation.setInputCloud(cloudDownsampledPtr);
211  featureEstimation.setInputNormals(normalPtr);
212  featureEstimation.setSearchSurface(transformedCloudPtr);
213  featureEstimation.compute(*descriptorPtr);
214  ARMARX_LOG << "found " << descriptorPtr->size() << " features";
215 
216  int i = 0;
217  const int k = 1;
218  for (PointD& d : descriptorPtr->points)
219  {
220  // if (!std::isfinite(d.descriptor[0])) //skipping NaNs
221  // {
222  // continue;
223  // }
224 
225  std::vector<int> k_indices(k);
226  std::vector<float> k_sqr_distances(k);
227  int numNeighborsFound =
228  matchSearchTree.nearestKSearch(d, k, k_indices, k_sqr_distances);
229 
230  if (numNeighborsFound == 1) // && k_sqr_distances[0] < 0.25f)
231  {
232  pcl::Correspondence corr(k_indices[0], i, k_sqr_distances[0]);
233  correspondencesPtr->push_back(corr);
234  }
235  i++;
236  }
237 
238  std::vector<pcl::Correspondences> clusteredCorrespondences;
239 
240  clusterer.setSceneCloud(cloudDownsampledPtr);
241  clusterer.setModelSceneCorrespondences(correspondencesPtr);
242  clusterer.recognize(transformations, clusteredCorrespondences);
243 
244  ARMARX_LOG << " found " << transformations.size() << " transformations";
245  }
246 
247 
248  for (Eigen::Matrix4f& t : transformations)
249  {
250  pcl::PointCloud<PointT>::Ptr transformedModelPtr3(new pcl::PointCloud<PointT>());
251  pcl::transformPointCloud(*modelKeypoints, *transformedModelPtr3, t);
252  visionx::tools::colorizeSegment(transformedModelPtr3);
253  *beforeICPResultPointCloud += *transformedModelPtr3;
254 
255  icp.setInputTarget(cloudDownsampledPtr);
256  icp.setInputSource(modelKeypoints);
257  pcl::PointCloud<PointT>::Ptr registered(new pcl::PointCloud<PointT>);
258  icp.align(*registered, t);
259 
260  if (icp.hasConverged())
261  {
262  float fitnessScore = icp.getFitnessScore();
263  Eigen::Matrix4f transform = icp.getFinalTransformation();
264 
265  ARMARX_LOG << "transformation after ICP " << transform;
266  ARMARX_LOG << "fitness score " << fitnessScore;
267 
268  pcl::PointCloud<PointT>::Ptr transformedModelPtr2(
269  new pcl::PointCloud<PointT>());
270  pcl::transformPointCloud(*modelKeypoints, *transformedModelPtr2, transform);
271  visionx::tools::colorizeSegment(transformedModelPtr2);
272  *afterICPResultPointCloud += *transformedModelPtr2;
273 
274  if (fitnessScore <= bestFitnessScore)
275  {
276  bestFitnessScore = fitnessScore;
277  bestTransform = transform;
278 
279  std::scoped_lock lock(localizeMutex);
280 
281  //pose = new armarx::FramedPose(bestTransform, poseInRootFrame->frame, agentName);
282  //FramedPosePtr::dynamicCast(pose)->changeFrame(robotStateComponent->getSynchronizedRobot(), sourceNodeName);
283 
284  pose = new armarx::FramedPose(bestTransform, sourceNodeName, agentName);
285 
286  debugDrawerPrx->setPoseVisu(
287  "PointCloudLocalizer", "label " + it.first, pose);
288  }
289  }
290  }
291  }
292 
293  provideResultPointClouds(beforeICPResultPointCloud, "BeforeICPResult");
294  provideResultPointClouds(afterICPResultPointCloud, "AfterICPResult");
295 
296  if (bestFitnessScore < 2000.0)
297  {
298  ARMARX_LOG << "best transformation " << bestTransform;
299  pcl::PointCloud<PointT>::Ptr BestResultPointCloud(new pcl::PointCloud<PointT>());
300  pcl::transformPointCloud(*modelKeypoints, *BestResultPointCloud, bestTransform);
301  provideResultPointClouds(BestResultPointCloud, "BestMatch");
302  }
303  }
304 
305  memoryx::ObjectLocalizationResultList
306  PointCloudObjectLocalizer::localizeObjectClasses(
307  const memoryx::ObjectClassNameList& objectClassNames,
308  const Ice::Current& c)
309  {
310  std::scoped_lock lock(localizeMutex);
311  ARMARX_LOG << "localizing object...";
312 
313  memoryx::ObjectLocalizationResultList resultList;
314 
315  std::string objectClassName = getProperty<std::string>("objectClassName").getValue();
316 
317  for (std::string name : objectClassNames)
318  {
319  if (name == objectClassName && pose)
320  {
321  memoryx::ObjectLocalizationResult result;
322  result.position = pose->getPosition();
323  result.orientation = pose->getOrientation();
324  result.objectClassName = objectClassName;
325  result.recognitionCertainty = 1.0f;
326  Eigen::Vector3f mean;
327  mean << 0.0, 0.0, 0.0;
329  memoryx::MultivariateNormalDistributionBasePtr dummy(
331  result.positionNoise = dummy;
332  resultList.push_back(result);
333  }
334  }
335 
336  return resultList;
337  }
338 
339  void
340  PointCloudObjectLocalizer::getLocation(FramedOrientationBasePtr& orientation,
341  FramedPositionBasePtr& position,
342  const Ice::Current& c)
343  {
344  std::scoped_lock lock(localizeMutex);
345 
346  orientation = this->pose->getOrientation();
347  position = this->pose->getPosition();
348  }
349 
351  PointCloudObjectLocalizer::createPropertyDefinitions()
352  {
353  return PropertyDefinitionsPtr(
354  new PointCloudObjectLocalizerPropertyDefinitions(getConfigIdentifier()));
355  }
356 } // namespace visionx
PointCloudObjectLocalizer.h
visionx::tools::colorizeSegment
std::tuple< uint8_t, uint8_t, uint8_t > colorizeSegment(PointCloudPtrT &segment)
Definition: PCLUtilities.h:48
visionx
ArmarX headers.
Definition: OpenPoseStressTest.h:38
armarx::VariantType::FramedPose
const VariantTypeId FramedPose
Definition: FramedPose.h:36
GfxTL::Matrix4f
MatrixXX< 4, 4, float > Matrix4f
Definition: MatrixXX.h:650
visionx::PointD
pcl::FPFHSignature33 PointD
Definition: MaskRCNNPointCloudObjectLocalizer.h:79
armarx::CMakePackageFinder
The CMakePackageFinder class provides an interface to the CMake Package finder capabilities.
Definition: CMakePackageFinder.h:52
c
constexpr T c
Definition: UnscentedKalmanFilterTest.cpp:46
ARMARX_FATAL
#define ARMARX_FATAL
Definition: Logging.h:199
GfxTL::Identity
void Identity(MatrixXX< N, N, T > *a)
Definition: MatrixXX.h:570
armarx::mean
std::optional< float > mean(const boost::circular_buffer< NameValueMap > &buffer, const std::string &key)
Definition: KinematicUnitGuiPlugin.cpp:1620
M_PI
#define M_PI
Definition: MathTools.h:17
memoryx::MultivariateNormalDistribution
The MultivariateNormalDistribution class.
Definition: ProbabilityMeasures.h:285
armarx::flush
const LogSender::manipulator flush
Definition: LogSender.h:251
ARMARX_DEBUG
#define ARMARX_DEBUG
Definition: Logging.h:184
armarx::CMakePackageFinder::getDataDir
std::string getDataDir() const
Definition: CMakePackageFinder.h:194
visionx::PointCloudObjectLocalizerPropertyDefinitions
Definition: PointCloudObjectLocalizer.h:80
max
T max(T t1, T t2)
Definition: gdiam.h:51
ARMARX_LOG
#define ARMARX_LOG
Definition: Logging.h:165
armarx::transform
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...
Definition: algorithm.h:351
CMakePackageFinder.h
armarx::ArmarXDataPath::addDataPaths
static void addDataPaths(const std::string &dataPathList)
Definition: ArmarXDataPath.cpp:554
IceUtil::Handle< class PropertyDefinitionContainer >
armarx::ArmarXDataPath::getAbsolutePath
static bool getAbsolutePath(const std::string &relativeFilename, std::string &storeAbsoluteFilename, const std::vector< std::string > &additionalSearchPaths={}, bool verbose=true)
Definition: ArmarXDataPath.cpp:109
GfxTL::Matrix3f
MatrixXX< 3, 3, float > Matrix3f
Definition: MatrixXX.h:649
ARMARX_WARNING
#define ARMARX_WARNING
Definition: Logging.h:193
armarx::PropertyDefinitionsPtr
IceUtil::Handle< class PropertyDefinitionContainer > PropertyDefinitionsPtr
PropertyDefinitions smart pointer type.
Definition: forward_declarations.h:35
armarx
This file offers overloads of toIce() and fromIce() functions for STL container types.
Definition: ArmarXTimeserver.cpp:27