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