Point Cloud Library (PCL)  1.9.1-dev
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>
44 void
46 {
47  const int height = input_->height;
48  const int width = input_->width;
49  const int kernel_height = structuring_element_->height;
50  const int kernel_width = structuring_element_->width;
51  bool mismatch_flag;
52 
53  output.width = width;
54  output.height = height;
55  output.resize(width * height);
56 
57  for (int i = 0; i < height; i++) {
58  for (int j = 0; j < width; j++) {
59  // Operation done only at 1's
60  if ((*input_)(j, i).intensity == 0) {
61  output(j, i).intensity = 0;
62  continue;
63  }
64  mismatch_flag = false;
65  for (int k = 0; k < kernel_height; k++) {
66  if (mismatch_flag)
67  break;
68  for (int l = 0; l < kernel_width; l++) {
69  // We only check for 1's in the kernel
70  if ((*structuring_element_)(l, k).intensity == 0)
71  continue;
72  if ((i + k - kernel_height / 2) < 0 ||
73  (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 ||
74  (j + l - kernel_width / 2) >= width) {
75  continue;
76  }
77  // If one of the elements of the kernel and image don't match,
78  // the output image is 0. So, move to the next point.
79  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2)
80  .intensity != 1) {
81  output(j, i).intensity = 0;
82  mismatch_flag = true;
83  break;
84  }
85  }
86  }
87  // Assign value according to mismatch flag
88  output(j, i).intensity = (mismatch_flag) ? 0 : 1;
89  }
90  }
91 }
92 
93 //////////////////////////////////////////////////////////////////////////////
94 // Assumes input, kernel and output images have 0's and 1's only
95 template <typename PointT>
96 void
98 {
99  const int height = input_->height;
100  const int width = input_->width;
101  const int kernel_height = structuring_element_->height;
102  const int kernel_width = structuring_element_->width;
103  bool match_flag;
104 
105  output.width = width;
106  output.height = height;
107  output.resize(width * height);
108 
109  for (int i = 0; i < height; i++) {
110  for (int j = 0; j < width; j++) {
111  match_flag = false;
112  for (int k = 0; k < kernel_height; k++) {
113  if (match_flag)
114  break;
115  for (int l = 0; l < kernel_width; l++) {
116  // We only check for 1's in the kernel
117  if ((*structuring_element_)(l, k).intensity == 0)
118  continue;
119  if ((i + k - kernel_height / 2) < 0 ||
120  (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 ||
121  (j + l - kernel_width / 2) >= height) {
122  continue;
123  }
124  // If any position where kernel is 1 and image is also one is detected,
125  // matching occurs
126  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2)
127  .intensity == 1) {
128  match_flag = true;
129  break;
130  }
131  }
132  }
133  // Assign value according to match flag
134  output(j, i).intensity = (match_flag) ? 1 : 0;
135  }
136  }
137 }
138 
139 //////////////////////////////////////////////////////////////////////////////
140 // Assumes input, kernel and output images have 0's and 1's only
141 template <typename PointT>
142 void
144 {
145  PointCloudInPtr intermediate_output(new PointCloudIn);
146  erosionBinary(*intermediate_output);
147  this->setInputCloud(intermediate_output);
148  dilationBinary(output);
149 }
150 
151 //////////////////////////////////////////////////////////////////////////////
152 // Assumes input, kernel and output images have 0's and 1's only
153 template <typename PointT>
154 void
156 {
157  PointCloudInPtr intermediate_output(new PointCloudIn);
158  dilationBinary(*intermediate_output);
159  this->setInputCloud(intermediate_output);
160  erosionBinary(output);
161 }
162 
163 //////////////////////////////////////////////////////////////////////////////
164 template <typename PointT>
165 void
167 {
168  const int height = input_->height;
169  const int width = input_->width;
170  const int kernel_height = structuring_element_->height;
171  const int kernel_width = structuring_element_->width;
172  float min;
173  output.resize(width * height);
174  output.width = width;
175  output.height = height;
176 
177  for (int i = 0; i < height; i++) {
178  for (int j = 0; j < width; j++) {
179  min = -1;
180  for (int k = 0; k < kernel_height; k++) {
181  for (int l = 0; l < kernel_width; l++) {
182  // We only check for 1's in the kernel
183  if ((*structuring_element_)(l, k).intensity == 0)
184  continue;
185  if ((i + k - kernel_height / 2) < 0 ||
186  (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 ||
187  (j + l - kernel_width / 2) >= width) {
188  continue;
189  }
190  // If one of the elements of the kernel and image don't match,
191  // the output image is 0. So, move to the next point.
192  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity <
193  min ||
194  min == -1) {
195  min = (*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2)
196  .intensity;
197  }
198  }
199  }
200  // Assign value according to mismatch flag
201  output(j, i).intensity = min;
202  }
203  }
204 }
205 
206 //////////////////////////////////////////////////////////////////////////////
207 template <typename PointT>
208 void
210 {
211  const int height = input_->height;
212  const int width = input_->width;
213  const int kernel_height = structuring_element_->height;
214  const int kernel_width = structuring_element_->width;
215  float max;
216 
217  output.resize(width * height);
218  output.width = width;
219  output.height = height;
220 
221  for (int i = 0; i < height; i++) {
222  for (int j = 0; j < width; j++) {
223  max = -1;
224  for (int k = 0; k < kernel_height; k++) {
225  for (int l = 0; l < kernel_width; l++) {
226  // We only check for 1's in the kernel
227  if ((*structuring_element_)(l, k).intensity == 0)
228  continue;
229  if ((i + k - kernel_height / 2) < 0 ||
230  (i + k - kernel_height / 2) >= height || (j + l - kernel_width / 2) < 0 ||
231  (j + l - kernel_width / 2) >= width) {
232  continue;
233  }
234  // If one of the elements of the kernel and image don't match,
235  // the output image is 0. So, move to the next point.
236  if ((*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2).intensity >
237  max ||
238  max == -1) {
239  max = (*input_)(j + l - kernel_width / 2, i + k - kernel_height / 2)
240  .intensity;
241  }
242  }
243  }
244  // Assign value according to mismatch flag
245  output(j, i).intensity = max;
246  }
247  }
248 }
249 
250 //////////////////////////////////////////////////////////////////////////////
251 template <typename PointT>
252 void
254 {
255  PointCloudInPtr intermediate_output(new PointCloudIn);
256  erosionGray(*intermediate_output);
257  this->setInputCloud(intermediate_output);
258  dilationGray(output);
259 }
260 
261 //////////////////////////////////////////////////////////////////////////////
262 template <typename PointT>
263 void
265 {
266  PointCloudInPtr intermediate_output(new PointCloudIn);
267  dilationGray(*intermediate_output);
268  this->setInputCloud(intermediate_output);
269  erosionGray(output);
270 }
271 
272 //////////////////////////////////////////////////////////////////////////////
273 template <typename PointT>
274 void
276  const pcl::PointCloud<PointT>& input1,
277  const pcl::PointCloud<PointT>& input2)
278 {
279  const int height = (input1.height < input2.height) ? input1.height : input2.height;
280  const int width = (input1.width < input2.width) ? input1.width : input2.width;
281  output.width = width;
282  output.height = height;
283  output.resize(height * width);
284 
285  for (size_t i = 0; i < output.size(); ++i) {
286  if (input1[i].intensity == 1 && input2[i].intensity == 0)
287  output[i].intensity = 1;
288  else
289  output[i].intensity = 0;
290  }
291 }
292 
293 //////////////////////////////////////////////////////////////////////////////
294 template <typename PointT>
295 void
297  const pcl::PointCloud<PointT>& input1,
298  const pcl::PointCloud<PointT>& input2)
299 {
300  const int height = (input1.height < input2.height) ? input1.height : input2.height;
301  const int width = (input1.width < input2.width) ? input1.width : input2.width;
302  output.width = width;
303  output.height = height;
304  output.resize(height * width);
305 
306  for (size_t i = 0; i < output.size(); ++i) {
307  if (input1[i].intensity == 1 || input2[i].intensity == 1)
308  output[i].intensity = 1;
309  else
310  output[i].intensity = 0;
311  }
312 }
313 
314 //////////////////////////////////////////////////////////////////////////////
315 template <typename PointT>
316 void
318  const pcl::PointCloud<PointT>& input1,
319  const pcl::PointCloud<PointT>& input2)
320 {
321  const int height = (input1.height < input2.height) ? input1.height : input2.height;
322  const int width = (input1.width < input2.width) ? input1.width : input2.width;
323  output.width = width;
324  output.height = height;
325  output.resize(height * width);
326 
327  for (size_t i = 0; i < output.size(); ++i) {
328  if (input1[i].intensity == 1 && input2[i].intensity == 1)
329  output[i].intensity = 1;
330  else
331  output[i].intensity = 0;
332  }
333 }
334 
335 //////////////////////////////////////////////////////////////////////////////
336 template <typename PointT>
337 void
339  const int radius)
340 {
341  const int dim = 2 * radius;
342  kernel.height = dim;
343  kernel.width = dim;
344  kernel.resize(dim * dim);
345 
346  for (int i = 0; i < dim; i++) {
347  for (int j = 0; j < dim; j++) {
348  if (((i - radius) * (i - radius) + (j - radius) * (j - radius)) < radius * radius)
349  kernel(j, i).intensity = 1;
350  else
351  kernel(j, i).intensity = 0;
352  }
353  }
354 }
355 
356 //////////////////////////////////////////////////////////////////////////////
357 template <typename PointT>
358 void
360  const int height,
361  const int width)
362 {
363  kernel.height = height;
364  kernel.width = width;
365  kernel.resize(height * width);
366  for (size_t i = 0; i < kernel.size(); ++i)
367  kernel[i].intensity = 1;
368 }
369 
370 //////////////////////////////////////////////////////////////////////////////
371 template <typename PointT>
372 void
374  const PointCloudInPtr& structuring_element)
375 {
376  structuring_element_ = structuring_element;
377 }
378 
379 #endif // PCL_2D_MORPHOLOGY_HPP_
void setStructuringElement(const PointCloudInPtr &structuring_element)
Definition: morphology.hpp:373
void dilationGray(pcl::PointCloud< PointT > &output)
Takes the max of the pixels where kernel is 1.
Definition: morphology.hpp:209
void openingGray(pcl::PointCloud< PointT > &output)
Grayscale erosion followed by dilation.
Definition: morphology.hpp:253
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:338
void erosionBinary(pcl::PointCloud< PointT > &output)
Binary dilation is similar to a logical disjunction of sets.
Definition: morphology.hpp:45
void openingBinary(pcl::PointCloud< PointT > &output)
This function performs erosion followed by dilation.
Definition: morphology.hpp:143
void unionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
Definition: morphology.hpp:296
uint32_t height
The point cloud height (if organized as an image-structure).
Definition: point_cloud.h:428
uint32_t width
The point cloud width (if organized as an image-structure).
Definition: point_cloud.h:426
void closingBinary(pcl::PointCloud< PointT > &output)
This function performs dilation followed by erosion.
Definition: morphology.hpp:155
void erosionGray(pcl::PointCloud< PointT > &output)
Takes the min of the pixels where kernel is 1.
Definition: morphology.hpp:166
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:97
void resize(size_t n)
Resize the cloud.
Definition: point_cloud.h:468
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:359
void closingGray(pcl::PointCloud< PointT > &output)
Grayscale dilation followed by erosion.
Definition: morphology.hpp:264
void intersectionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
Definition: morphology.hpp:317
size_t size() const
Definition: point_cloud.h:461