Point Cloud Library (PCL)  1.8.0
morphology.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2012-, Open Perception, Inc.
6  *
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the copyright holder(s) nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  */
37 
38 #ifndef PCL_2D_MORPHOLOGY_HPP_
39 #define PCL_2D_MORPHOLOGY_HPP_
40 
41 //////////////////////////////////////////////////////////////////////////////
42 // Assumes input, kernel and output images have 0's and 1's only
43 template<typename PointT> void
45 {
46  const int height = input_->height;
47  const int width = input_->width;
48  const int kernel_height = structuring_element_->height;
49  const int kernel_width = structuring_element_->width;
50  bool mismatch_flag;
51 
52  output.width = width;
53  output.height = height;
54  output.resize (width * height);
55 
56  for (int i = 0; i < height; i++)
57  {
58  for (int j = 0; j < width; j++)
59  {
60  // Operation done only at 1's
61  if ((*input_)(j, i).intensity == 0)
62  {
63  output (j, i).intensity = 0;
64  continue;
65  }
66  mismatch_flag = false;
67  for (int k = 0; k < kernel_height; k++)
68  {
69  if (mismatch_flag)
70  break;
71  for (int l = 0; l < kernel_width; l++)
72  {
73  // We only check for 1's in the kernel
74  if ((*structuring_element_)(l, k).intensity == 0)
75  continue;
76  if ((i + k - kernel_height / 2) < 0 || (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 || (j + l - kernel_width / 2) >= width)
77  {
78  continue;
79  }
80  // If one of the elements of the kernel and image dont match,
81  // the output image is 0. So, move to the next point.
82  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity != 1)
83  {
84  output (j, i).intensity = 0;
85  mismatch_flag = true;
86  break;
87  }
88  }
89  }
90  // Assign value according to mismatch flag
91  output (j, i).intensity = (mismatch_flag) ? 0 : 1;
92  }
93  }
94 }
95 
96 //////////////////////////////////////////////////////////////////////////////
97 // Assumes input, kernel and output images have 0's and 1's only
98 template <typename PointT> void
100 {
101  const int height = input_->height;
102  const int width = input_->width;
103  const int kernel_height = structuring_element_->height;
104  const int kernel_width = structuring_element_->width;
105  bool match_flag;
106 
107  output.width = width;
108  output.height = height;
109  output.resize (width * height);
110 
111  for (int i = 0; i < height; i++)
112  {
113  for (int j = 0; j < width; j++)
114  {
115  match_flag = false;
116  for (int k = 0; k < kernel_height; k++)
117  {
118  if (match_flag)
119  break;
120  for (int l = 0; l < kernel_width; l++)
121  {
122  // We only check for 1's in the kernel
123  if ((*structuring_element_)(l, k).intensity == 0)
124  continue;
125  if ((i + k - kernel_height / 2) < 0 || (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 || (j + l - kernel_width / 2) >= height)
126  {
127  continue;
128  }
129  // If any position where kernel is 1 and image is also one is detected,
130  // matching occurs
131  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity == 1)
132  {
133  match_flag = true;
134  break;
135  }
136  }
137  }
138  // Assign value according to match flag
139  output (j, i).intensity = (match_flag) ? 1 : 0;
140  }
141  }
142 }
143 
144 //////////////////////////////////////////////////////////////////////////////
145 // Assumes input, kernel and output images have 0's and 1's only
146 template <typename PointT> void
148 {
149  PointCloudInPtr intermediate_output (new PointCloudIn);
150  erosionBinary (*intermediate_output);
151  this->setInputCloud (intermediate_output);
152  dilationBinary (output);
153 }
154 
155 //////////////////////////////////////////////////////////////////////////////
156 // Assumes input, kernel and output images have 0's and 1's only
157 template <typename PointT> void
159 {
160  PointCloudInPtr intermediate_output (new PointCloudIn);
161  dilationBinary (*intermediate_output);
162  this->setInputCloud (intermediate_output);
163  erosionBinary (output);
164 }
165 
166 //////////////////////////////////////////////////////////////////////////////
167 template <typename PointT> void
169 {
170  const int height = input_->height;
171  const int width = input_->width;
172  const int kernel_height = structuring_element_->height;
173  const int kernel_width = structuring_element_->width;
174  float min;
175  output.resize (width * height);
176  output.width = width;
177  output.height = height;
178 
179  for (int i = 0; i < height; i++)
180  {
181  for (int j = 0; j < width; j++)
182  {
183  min = -1;
184  for (int k = 0; k < kernel_height; k++)
185  {
186  for (int l = 0; l < kernel_width; l++)
187  {
188  // We only check for 1's in the kernel
189  if ((*structuring_element_)(l, k).intensity == 0)
190  continue;
191  if ((i + k - kernel_height / 2) < 0 || (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 || (j + l - kernel_width / 2) >= width)
192  {
193  continue;
194  }
195  // If one of the elements of the kernel and image dont match,
196  // the output image is 0. So, move to the next point.
197  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity < min || min == -1)
198  {
199  min = (*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity;
200  }
201  }
202  }
203  // Assign value according to mismatch flag
204  output (j, i).intensity = min;
205  }
206  }
207 }
208 
209 //////////////////////////////////////////////////////////////////////////////
210 template <typename PointT> void
212 {
213  const int height = input_->height;
214  const int width = input_->width;
215  const int kernel_height = structuring_element_->height;
216  const int kernel_width = structuring_element_->width;
217  float max;
218 
219  output.resize (width * height);
220  output.width = width;
221  output.height = height;
222 
223  for (int i = 0; i < height; i++)
224  {
225  for (int j = 0; j < width; j++)
226  {
227  max = -1;
228  for (int k = 0; k < kernel_height; k++)
229  {
230  for (int l = 0; l < kernel_width; l++)
231  {
232  // We only check for 1's in the kernel
233  if ((*structuring_element_)(l, k).intensity == 0)
234  continue;
235  if ((i + k - kernel_height / 2) < 0 || (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 || (j + l - kernel_width / 2) >= width)
236  {
237  continue;
238  }
239  // If one of the elements of the kernel and image dont match,
240  // the output image is 0. So, move to the next point.
241  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity > max || max == -1)
242  {
243  max = (*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity;
244  }
245  }
246  }
247  // Assign value according to mismatch flag
248  output (j, i).intensity = max;
249  }
250  }
251 }
252 
253 //////////////////////////////////////////////////////////////////////////////
254 template <typename PointT> void
256 {
257  PointCloudInPtr intermediate_output (new PointCloudIn);
258  erosionGray (*intermediate_output);
259  this->setInputCloud (intermediate_output);
260  dilationGray (output);
261 }
262 
263 //////////////////////////////////////////////////////////////////////////////
264 template <typename PointT> void
266 {
267  PointCloudInPtr intermediate_output (new PointCloudIn);
268  dilationGray (*intermediate_output);
269  this->setInputCloud (intermediate_output);
270  erosionGray (output);
271 }
272 
273 //////////////////////////////////////////////////////////////////////////////
274 template <typename PointT> void
276  pcl::PointCloud<PointT> &output,
277  const pcl::PointCloud<PointT> &input1,
278  const pcl::PointCloud<PointT> &input2)
279 {
280  const int height = (input1.height < input2.hieght) ? input1.height : input2.height;
281  const int width = (input1.width < input2.width) ? input1.width : input2.width;
282  output.width = width;
283  output.height = height;
284  output.resize (height * width);
285 
286  for (size_t i = 0; i < output.size (); ++i)
287  {
288  if (input1[i].intensity == 1 && input2[i].intensity == 0)
289  output[i].intensity = 1;
290  else
291  output[i].intensity = 0;
292  }
293 }
294 
295 //////////////////////////////////////////////////////////////////////////////
296 template <typename PointT> void
298  pcl::PointCloud<PointT> &output,
299  const pcl::PointCloud<PointT> &input1,
300  const pcl::PointCloud<PointT> &input2)
301 {
302  const int height = (input1.height < input2.hieght) ? input1.height : input2.height;
303  const int width = (input1.width < input2.width) ? input1.width : input2.width;
304  output.width = width;
305  output.height = height;
306  output.resize (height * width);
307 
308  for (size_t i = 0; i < output.size (); ++i)
309  {
310  if (input1[i].intensity == 1 || input2[i].intensity == 1)
311  output[i].intensity = 1;
312  else
313  output[i].intensity = 0;
314  }
315 }
316 
317 //////////////////////////////////////////////////////////////////////////////
318 template <typename PointT> void
320  pcl::PointCloud<PointT> &output,
321  const pcl::PointCloud<PointT> &input1,
322  const pcl::PointCloud<PointT> &input2)
323 {
324  const int height = (input1.height < input2.height) ? input1.height : input2.height;
325  const int width = (input1.width < input2.width) ? input1.width : input2.width;
326  output.width = width;
327  output.height = height;
328  output.resize (height * width);
329 
330  for (size_t i = 0; i < output.size (); ++i)
331  {
332  if (input1[i].intensity == 1 && input2[i].intensity == 1)
333  output[i].intensity = 1;
334  else
335  output[i].intensity = 0;
336  }
337 }
338 
339 //////////////////////////////////////////////////////////////////////////////
340 template <typename PointT> void
342  pcl::PointCloud<PointT> &kernel, const int radius)
343 {
344  const int dim = 2 * radius;
345  kernel.height = dim;
346  kernel.width = dim;
347  kernel.resize (dim * dim);
348 
349  for (int i = 0; i < dim; i++)
350  {
351  for (int j = 0; j < dim; j++)
352  {
353  if (((i - radius) * (i - radius) + (j - radius) * (j - radius)) < radius * radius)
354  kernel (j, i).intensity = 1;
355  else
356  kernel (j, i).intensity = 0;
357  }
358  }
359 }
360 
361 //////////////////////////////////////////////////////////////////////////////
362 template <typename PointT> void
364  pcl::PointCloud<PointT> &kernel, const int height, const int width)
365 {
366  kernel.height = height;
367  kernel.width = width;
368  kernel.resize (height * width);
369  for (size_t i = 0; i < kernel.size (); ++i)
370  kernel[i].intensity = 1;
371 }
372 
373 //////////////////////////////////////////////////////////////////////////////
374 template <typename PointT> void
375 pcl::Morphology<PointT>::setStructuringElement (const PointCloudInPtr &structuring_element)
376 {
377  structuring_element_ = structuring_element;
378 }
379 
380 #endif // PCL_2D_MORPHOLOGY_HPP_
void setStructuringElement(const PointCloudInPtr &structuring_element)
Definition: morphology.hpp:375
void dilationGray(pcl::PointCloud< PointT > &output)
Takes the max of the pixels where kernel is 1.
Definition: morphology.hpp:211
size_t size() const
Definition: point_cloud.h:440
void openingGray(pcl::PointCloud< PointT > &output)
Grayscale erosion followed by dilation.
Definition: morphology.hpp:255
void subtractionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation output = input1 - input2.
Definition: morphology.hpp:275
void structuringElementCircular(pcl::PointCloud< PointT > &kernel, const int radius)
Creates a circular structing element.
Definition: morphology.hpp:341
void erosionBinary(pcl::PointCloud< PointT > &output)
Binary dilation is similar to a logical disjunction of sets.
Definition: morphology.hpp:44
void openingBinary(pcl::PointCloud< PointT > &output)
This function performs erosion followed by dilation.
Definition: morphology.hpp:147
void unionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
Definition: morphology.hpp:297
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:415
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:413
void closingBinary(pcl::PointCloud< PointT > &output)
This function performs dilation followed by erosion.
Definition: morphology.hpp:158
void erosionGray(pcl::PointCloud< PointT > &output)
Takes the min of the pixels where kernel is 1.
Definition: morphology.hpp:168
PointCloud represents the base class in PCL for storing collections of 3D points. ...
void dilationBinary(pcl::PointCloud< PointT > &output)
Binary erosion is similar to a logical addition of sets.
Definition: morphology.hpp:99
void resize(size_t n)
Resize the cloud.
Definition: point_cloud.h:447
void structuringElementRectangle(pcl::PointCloud< PointT > &kernel, const int height, const int width)
Creates a rectangular structing element of size height x width.
Definition: morphology.hpp:363
void closingGray(pcl::PointCloud< PointT > &output)
Grayscale dilation followed by erosion.
Definition: morphology.hpp:265
void intersectionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
Definition: morphology.hpp:319