Point Cloud Library (PCL) 1.14.0
Loading...
Searching...
No Matches
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
42namespace pcl {
43
44// Assumes input, kernel and output images have 0's and 1's only
45template <typename PointT>
46void
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
96template <typename PointT>
97void
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
141template <typename PointT>
142void
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
152template <typename PointT>
153void
155{
156 PointCloudInPtr intermediate_output(new PointCloudIn);
157 dilationBinary(*intermediate_output);
158 this->setInputCloud(intermediate_output);
159 erosionBinary(output);
160}
161
162template <typename PointT>
163void
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
204template <typename PointT>
205void
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
247template <typename PointT>
248void
250{
251 PointCloudInPtr intermediate_output(new PointCloudIn);
252 erosionGray(*intermediate_output);
253 this->setInputCloud(intermediate_output);
254 dilationGray(output);
255}
256
257template <typename PointT>
258void
260{
261 PointCloudInPtr intermediate_output(new PointCloudIn);
262 dilationGray(*intermediate_output);
263 this->setInputCloud(intermediate_output);
264 erosionGray(output);
265}
266
267template <typename PointT>
268void
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
287template <typename PointT>
288void
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
307template <typename PointT>
308void
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
327template <typename PointT>
328void
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
347template <typename PointT>
348void
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
360template <typename PointT>
361void
362Morphology<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.
void subtractionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation output = input1 - input2.
void erosionGray(pcl::PointCloud< PointT > &output)
Takes the min of the pixels where kernel is 1.
void openingBinary(pcl::PointCloud< PointT > &output)
This function performs erosion followed by dilation.
void erosionBinary(pcl::PointCloud< PointT > &output)
Binary dilation is similar to a logical disjunction of sets.
void setStructuringElement(const PointCloudInPtr &structuring_element)
void closingGray(pcl::PointCloud< PointT > &output)
Grayscale dilation followed by erosion.
void closingBinary(pcl::PointCloud< PointT > &output)
This function performs dilation followed by erosion.
void intersectionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
void unionBinary(pcl::PointCloud< PointT > &output, const pcl::PointCloud< PointT > &input1, const pcl::PointCloud< PointT > &input2)
Set operation .
void structuringElementRectangle(pcl::PointCloud< PointT > &kernel, const int height, const int width)
Creates a rectangular structing element of size height x width.
void openingGray(pcl::PointCloud< PointT > &output)
Grayscale erosion followed by dilation.
void structuringElementCircular(pcl::PointCloud< PointT > &kernel, const int radius)
Creates a circular structing element.
void dilationGray(pcl::PointCloud< PointT > &output)
Takes the max of the pixels where kernel is 1.
PointCloud represents the base class in PCL for storing collections of 3D points.
void resize(std::size_t count)
Resizes the container to contain count elements.
std::uint32_t width
The point cloud width (if organized as an image-structure).
std::uint32_t height
The point cloud height (if organized as an image-structure).
std::size_t size() const