RTAB-Map 0.23.10
Real-Time Appearance-Based Mapping
Loading...
Searching...
No Matches
util3d_mapping.hpp
1/*
2Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the Universite de Sherbrooke nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#ifndef UTIL3D_MAPPING_HPP_
29#define UTIL3D_MAPPING_HPP_
30
31#include <rtabmap/core/util3d_filtering.h>
32#include <rtabmap/core/util3d.h>
33#include <pcl/common/common.h>
34#include <pcl/common/centroid.h>
35#include <pcl/common/io.h>
36
37namespace rtabmap{
38namespace util3d{
39
40template<typename PointT>
41typename pcl::PointCloud<PointT>::Ptr projectCloudOnXYPlane(
42 const typename pcl::PointCloud<PointT> & cloud)
43{
44 typename pcl::PointCloud<PointT>::Ptr output(new pcl::PointCloud<PointT>);
45 *output = cloud;
46 for(unsigned int i=0; i<output->size(); ++i)
47 {
48 output->at(i).z = 0;
49 }
50 return output;
51}
52
53template<typename PointT>
54void segmentObstaclesFromGround(
55 const typename pcl::PointCloud<PointT>::Ptr & cloud,
56 const typename pcl::IndicesPtr & indices,
57 pcl::IndicesPtr & ground,
58 pcl::IndicesPtr & obstacles,
59 int normalKSearch,
60 float groundNormalAngle,
61 float clusterRadius,
62 int minClusterSize,
63 bool segmentFlatObstacles,
64 float maxGroundHeight,
65 pcl::IndicesPtr * flatObstacles,
66 const Eigen::Vector4f & viewPoint,
67 float groundNormalsUp)
68{
69 ground.reset(new std::vector<int>);
70 obstacles.reset(new std::vector<int>);
71 if(flatObstacles)
72 {
73 flatObstacles->reset(new std::vector<int>);
74 }
75
76 if(cloud->size())
77 {
78 // Find the ground
79 pcl::IndicesPtr flatSurfaces = normalFiltering(
80 cloud,
81 indices,
82 groundNormalAngle,
83 Eigen::Vector4f(0,0,1,0),
84 normalKSearch,
85 viewPoint,
86 groundNormalsUp);
87
88 if(flatSurfaces->size() &&
89 (segmentFlatObstacles || maxGroundHeight != 0.0f || minClusterSize>1))
90 {
91 int biggestFlatSurfaceIndex;
92 std::vector<pcl::IndicesPtr> clusteredFlatSurfaces = extractClusters(
93 cloud,
94 flatSurfaces,
95 clusterRadius,
96 minClusterSize,
97 std::numeric_limits<int>::max(),
98 &biggestFlatSurfaceIndex);
99
100 // cluster all surfaces for which the centroid is in the Z-range of the bigger surface
101 if(clusteredFlatSurfaces.size())
102 {
103 Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax;
104 if(maxGroundHeight != 0.0f)
105 {
106 // Search for biggest surface under max ground height
107 size_t points = 0;
108 biggestFlatSurfaceIndex = -1;
109 for(size_t i=0;i<clusteredFlatSurfaces.size();++i)
110 {
111 Eigen::Vector4f min,max;
112 pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(i), min, max);
113 if(min[2]<maxGroundHeight && clusteredFlatSurfaces.at(i)->size() > points)
114 {
115 points = clusteredFlatSurfaces.at(i)->size();
116 biggestFlatSurfaceIndex = i;
117 biggestSurfaceMin = min;
118 biggestSurfaceMax = max;
119 }
120 }
121 }
122 else
123 {
124 pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(biggestFlatSurfaceIndex), biggestSurfaceMin, biggestSurfaceMax);
125 }
126 if(biggestFlatSurfaceIndex>=0)
127 {
128 ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
129 }
130
131 if(!ground->empty() && (maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
132 {
133 for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
134 {
135 if((int)i!=biggestFlatSurfaceIndex)
136 {
137 Eigen::Vector4f centroid(0,0,0,1);
138 pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
139 if((maxGroundHeight!=0.0f && centroid[2] <= maxGroundHeight) ||
140 centroid[2] <= biggestSurfaceMax[2] ||
141 (maxGroundHeight==0.0f && !segmentFlatObstacles))
142 {
143 ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
144 }
145 else if(flatObstacles)
146 {
147 *flatObstacles = util3d::concatenate(*flatObstacles, clusteredFlatSurfaces.at(i));
148 }
149 }
150 }
151 }
152 else
153 {
154 // reject ground!
155 ground.reset(new std::vector<int>);
156 if(flatObstacles)
157 {
158 *flatObstacles = flatSurfaces;
159 }
160 }
161 }
162 }
163 else
164 {
165 ground = flatSurfaces;
166 }
167
168 if(ground->size() != cloud->size())
169 {
170 // Remove ground
171 pcl::IndicesPtr notObstacles = ground;
172 if(indices->size())
173 {
174 notObstacles = util3d::extractIndices(cloud, indices, true);
175 notObstacles = util3d::concatenate(notObstacles, ground);
176 }
177 pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
178
179 // If ground height is set, remove obstacles under it
180 if(maxGroundHeight != 0.0f)
181 {
182 otherStuffIndices = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", maxGroundHeight, std::numeric_limits<float>::max());
183 }
184
185 //Cluster remaining stuff (obstacles)
186 if(otherStuffIndices->size())
187 {
188 std::vector<pcl::IndicesPtr> clusteredObstaclesSurfaces = util3d::extractClusters(
189 cloud,
190 otherStuffIndices,
191 clusterRadius,
192 minClusterSize);
193
194 // merge indices
195 obstacles = util3d::concatenate(clusteredObstaclesSurfaces);
196 }
197 }
198 }
199}
200
201template<typename PointT>
202void segmentObstaclesFromGround(
203 const typename pcl::PointCloud<PointT>::Ptr & cloud,
204 pcl::IndicesPtr & ground,
205 pcl::IndicesPtr & obstacles,
206 int normalKSearch,
207 float groundNormalAngle,
208 float clusterRadius,
209 int minClusterSize,
210 bool segmentFlatObstacles,
211 float maxGroundHeight,
212 pcl::IndicesPtr * flatObstacles,
213 const Eigen::Vector4f & viewPoint,
214 float groundNormalsUp)
215{
216 pcl::IndicesPtr indices(new std::vector<int>);
217 segmentObstaclesFromGround<PointT>(
218 cloud,
219 indices,
220 ground,
221 obstacles,
222 normalKSearch,
223 groundNormalAngle,
224 clusterRadius,
225 minClusterSize,
226 segmentFlatObstacles,
227 maxGroundHeight,
228 flatObstacles,
229 viewPoint,
230 groundNormalsUp);
231}
232
233template<typename PointT>
235 const typename pcl::PointCloud<PointT>::Ptr & cloud,
236 const pcl::IndicesPtr & groundIndices,
237 const pcl::IndicesPtr & obstaclesIndices,
238 cv::Mat & ground,
239 cv::Mat & obstacles,
240 float cellSize)
241{
242 typename pcl::PointCloud<PointT>::Ptr groundCloud(new pcl::PointCloud<PointT>);
243 typename pcl::PointCloud<PointT>::Ptr obstaclesCloud(new pcl::PointCloud<PointT>);
244
245 if(groundIndices->size())
246 {
247 pcl::copyPointCloud(*cloud, *groundIndices, *groundCloud);
248 }
249
250 if(obstaclesIndices->size())
251 {
252 pcl::copyPointCloud(*cloud, *obstaclesIndices, *obstaclesCloud);
253 }
254
255 occupancy2DFromGroundObstacles<PointT>(
256 groundCloud,
257 obstaclesCloud,
258 ground,
259 obstacles,
260 cellSize);
261}
262
263template<typename PointT>
265 const typename pcl::PointCloud<PointT>::Ptr & groundCloud,
266 const typename pcl::PointCloud<PointT>::Ptr & obstaclesCloud,
267 cv::Mat & ground,
268 cv::Mat & obstacles,
269 float cellSize)
270{
271 ground = cv::Mat();
272 if(groundCloud->size())
273 {
274 //project on XY plane
275 typename pcl::PointCloud<PointT>::Ptr groundCloudProjected;
276 groundCloudProjected = util3d::projectCloudOnXYPlane(*groundCloud);
277 //voxelize to grid cell size
278 groundCloudProjected = util3d::voxelize(groundCloudProjected, cellSize);
279
280 ground = cv::Mat(1, (int)groundCloudProjected->size(), CV_32FC2);
281 for(unsigned int i=0;i<groundCloudProjected->size(); ++i)
282 {
283 cv::Vec2f * ptr = ground.ptr<cv::Vec2f>();
284 ptr[i][0] = groundCloudProjected->at(i).x;
285 ptr[i][1] = groundCloudProjected->at(i).y;
286 }
287 }
288
289 obstacles = cv::Mat();
290 if(obstaclesCloud->size())
291 {
292 //project on XY plane
293 typename pcl::PointCloud<PointT>::Ptr obstaclesCloudProjected;
294 obstaclesCloudProjected = util3d::projectCloudOnXYPlane(*obstaclesCloud);
295 //voxelize to grid cell size
296 obstaclesCloudProjected = util3d::voxelize(obstaclesCloudProjected, cellSize);
297
298 obstacles = cv::Mat(1, (int)obstaclesCloudProjected->size(), CV_32FC2);
299 for(unsigned int i=0;i<obstaclesCloudProjected->size(); ++i)
300 {
301 cv::Vec2f * ptr = obstacles.ptr<cv::Vec2f>();
302 ptr[i][0] = obstaclesCloudProjected->at(i).x;
303 ptr[i][1] = obstaclesCloudProjected->at(i).y;
304 }
305 }
306}
307
308template<typename PointT>
310 const typename pcl::PointCloud<PointT>::Ptr & cloud,
311 const pcl::IndicesPtr & indices,
312 cv::Mat & ground,
313 cv::Mat & obstacles,
314 float cellSize,
315 float groundNormalAngle,
316 int minClusterSize,
317 bool segmentFlatObstacles,
318 float maxGroundHeight)
319{
320 if(cloud->size() == 0)
321 {
322 return;
323 }
324 pcl::IndicesPtr groundIndices, obstaclesIndices;
325
326 segmentObstaclesFromGround<PointT>(
327 cloud,
328 indices,
329 groundIndices,
330 obstaclesIndices,
331 20,
332 groundNormalAngle,
333 cellSize*2.0f,
334 minClusterSize,
335 segmentFlatObstacles,
336 maxGroundHeight);
337
338 occupancy2DFromGroundObstacles<PointT>(
339 cloud,
340 groundIndices,
341 obstaclesIndices,
342 ground,
343 obstacles,
344 cellSize);
345}
346
347template<typename PointT>
349 const typename pcl::PointCloud<PointT>::Ptr & cloud,
350 cv::Mat & ground,
351 cv::Mat & obstacles,
352 float cellSize,
353 float groundNormalAngle,
354 int minClusterSize,
355 bool segmentFlatObstacles,
356 float maxGroundHeight)
357{
358 pcl::IndicesPtr indices(new std::vector<int>);
359 occupancy2DFromCloud3D<PointT>(cloud, indices, ground, obstacles, cellSize, groundNormalAngle, minClusterSize, segmentFlatObstacles, maxGroundHeight);
360}
361
362}
363}
364
365#endif /* UTIL3D_MAPPING_HPP_ */
std::vector< pcl::IndicesPtr > RTABMAP_CORE_EXPORT extractClusters(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, float clusterTolerance, int minClusterSize, int maxClusterSize=std::numeric_limits< int >::max(), int *biggestClusterIndex=0)
Extract clusters from point cloud of type pcl::PointXYZ.
pcl::IndicesPtr RTABMAP_CORE_EXPORT extractIndices(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, bool negative)
Extract indices from point cloud of type pcl::PointXYZ.
pcl::IndicesPtr RTABMAP_CORE_EXPORT passThrough(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, const std::string &axis, float min, float max, bool negative=false)
Performs pass-through filtering on a point cloud of type pcl::PointXYZ and returns filtered indices.
pcl::IndicesPtr RTABMAP_CORE_EXPORT normalFiltering(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, float angleMax, const Eigen::Vector4f &normal, int normalKSearch, const Eigen::Vector4f &viewpoint, float groundNormalsUp=0.0f)
Point normal filtering for point cloud of type pcl::PointXYZ.
pcl::PointCloud< pcl::PointXYZ >::Ptr RTABMAP_CORE_EXPORT voxelize(const pcl::PointCloud< pcl::PointXYZ >::Ptr &cloud, const pcl::IndicesPtr &indices, float voxelSize)
Performs voxel grid downsampling on a point cloud of type pcl::PointXYZ on provided indices.
pcl::PointCloud< PointT >::Ptr projectCloudOnXYPlane(const typename pcl::PointCloud< PointT > &cloud)
Projects a point cloud onto the XY plane by setting all Z coordinates to zero.
void occupancy2DFromCloud3D(const typename pcl::PointCloud< PointT >::Ptr &cloud, const pcl::IndicesPtr &indices, cv::Mat &ground, cv::Mat &obstacles, float cellSize, float groundNormalAngle, int minClusterSize, bool segmentFlatObstacles, float maxGroundHeight)
Generates 2D ground and obstacle occupancy data from a 3D point cloud.
void occupancy2DFromGroundObstacles(const typename pcl::PointCloud< PointT >::Ptr &cloud, const pcl::IndicesPtr &groundIndices, const pcl::IndicesPtr &obstaclesIndices, cv::Mat &ground, cv::Mat &obstacles, float cellSize)
Projects 3D ground and obstacle point clouds onto the 2D XY plane and voxelizes them into 2D occupanc...
pcl::IndicesPtr RTABMAP_CORE_EXPORT concatenate(const std::vector< pcl::IndicesPtr > &indices)
Concatenates multiple sets of indices into a single index vector.