40 #include <pcl/2d/convolution.h>
41 #include <pcl/2d/edge.h>
46 template <
typename Po
intInT,
typename Po
intOutT>
50 convolution_.setInputCloud(input_);
54 kernel_.fetchKernel(*kernel_x);
55 convolution_.setKernel(*kernel_x);
56 convolution_.filter(*magnitude_x);
61 kernel_.fetchKernel(*kernel_y);
62 convolution_.setKernel(*kernel_y);
63 convolution_.filter(*magnitude_y);
65 const int height = input_->height;
66 const int width = input_->width;
68 output.
resize(height * width);
72 for (std::size_t i = 0; i < output.
size(); ++i) {
73 output[i].magnitude_x = (*magnitude_x)[i].intensity;
74 output[i].magnitude_y = (*magnitude_y)[i].intensity;
76 std::sqrt((*magnitude_x)[i].intensity * (*magnitude_x)[i].intensity +
77 (*magnitude_y)[i].intensity * (*magnitude_y)[i].intensity);
79 std::atan2((*magnitude_y)[i].intensity, (*magnitude_x)[i].intensity);
83 template <
typename Po
intInT,
typename Po
intOutT>
90 convolution_.setInputCloud(input_x.
makeShared());
94 kernel_.fetchKernel(*kernel_x);
95 convolution_.setKernel(*kernel_x);
96 convolution_.filter(*magnitude_x);
98 convolution_.setInputCloud(input_y.
makeShared());
102 kernel_.fetchKernel(*kernel_y);
103 convolution_.setKernel(*kernel_y);
104 convolution_.filter(*magnitude_y);
106 const int height = input_x.
height;
107 const int width = input_x.
width;
109 output.
resize(height * width);
111 output.
width = width;
113 for (std::size_t i = 0; i < output.
size(); ++i) {
114 output[i].magnitude_x = (*magnitude_x)[i].intensity;
115 output[i].magnitude_y = (*magnitude_y)[i].intensity;
116 output[i].magnitude =
117 std::sqrt((*magnitude_x)[i].intensity * (*magnitude_x)[i].intensity +
118 (*magnitude_y)[i].intensity * (*magnitude_y)[i].intensity);
119 output[i].direction =
120 std::atan2((*magnitude_y)[i].intensity, (*magnitude_x)[i].intensity);
124 template <
typename Po
intInT,
typename Po
intOutT>
128 convolution_.setInputCloud(input_);
133 kernel_.fetchKernel(*kernel_x);
134 convolution_.setKernel(*kernel_x);
135 convolution_.filter(*magnitude_x);
140 kernel_.fetchKernel(*kernel_y);
141 convolution_.setKernel(*kernel_y);
142 convolution_.filter(*magnitude_y);
144 const int height = input_->height;
145 const int width = input_->width;
147 output.
resize(height * width);
149 output.
width = width;
151 for (std::size_t i = 0; i < output.
size(); ++i) {
152 output[i].magnitude_x = (*magnitude_x)[i].intensity;
153 output[i].magnitude_y = (*magnitude_y)[i].intensity;
154 output[i].magnitude =
155 std::sqrt((*magnitude_x)[i].intensity * (*magnitude_x)[i].intensity +
156 (*magnitude_y)[i].intensity * (*magnitude_y)[i].intensity);
157 output[i].direction =
158 std::atan2((*magnitude_y)[i].intensity, (*magnitude_x)[i].intensity);
162 template <
typename Po
intInT,
typename Po
intOutT>
166 convolution_.setInputCloud(input_);
171 kernel_.fetchKernel(*kernel_x);
172 convolution_.setKernel(*kernel_x);
173 convolution_.filter(*magnitude_x);
178 kernel_.fetchKernel(*kernel_y);
179 convolution_.setKernel(*kernel_y);
180 convolution_.filter(*magnitude_y);
182 const int height = input_->height;
183 const int width = input_->width;
185 output.
resize(height * width);
187 output.
width = width;
189 for (std::size_t i = 0; i < output.
size(); ++i) {
190 output[i].magnitude_x = (*magnitude_x)[i].intensity;
191 output[i].magnitude_y = (*magnitude_y)[i].intensity;
192 output[i].magnitude =
193 std::sqrt((*magnitude_x)[i].intensity * (*magnitude_x)[i].intensity +
194 (*magnitude_y)[i].intensity * (*magnitude_y)[i].intensity);
195 output[i].direction =
196 std::atan2((*magnitude_y)[i].intensity, (*magnitude_x)[i].intensity);
200 template <
typename Po
intInT,
typename Po
intOutT>
202 Edge<PointInT, PointOutT>::cannyTraceEdge(
205 int newRow = row + rowOffset;
206 int newCol = col + colOffset;
209 if (newRow > 0 && newRow <
static_cast<int>(maxima.
height) && newCol > 0 &&
210 newCol <
static_cast<int>(maxima.
width)) {
214 pt.
intensity = std::numeric_limits<float>::max();
215 cannyTraceEdge(1, 0, newRow, newCol, maxima);
216 cannyTraceEdge(-1, 0, newRow, newCol, maxima);
217 cannyTraceEdge(1, 1, newRow, newCol, maxima);
218 cannyTraceEdge(-1, -1, newRow, newCol, maxima);
219 cannyTraceEdge(0, -1, newRow, newCol, maxima);
220 cannyTraceEdge(0, 1, newRow, newCol, maxima);
221 cannyTraceEdge(-1, 1, newRow, newCol, maxima);
222 cannyTraceEdge(1, -1, newRow, newCol, maxima);
226 template <
typename Po
intInT,
typename Po
intOutT>
230 const int height = thet.
height;
231 const int width = thet.
width;
233 for (
int i = 0; i < height; i++) {
234 for (
int j = 0; j < width; j++) {
236 if (((angle <= 22.5) && (angle >= -22.5)) || (angle >= 157.5) ||
238 thet(j, i).direction = 0;
239 else if (((angle > 22.5) && (angle < 67.5)) ||
240 ((angle < -112.5) && (angle > -157.5)))
241 thet(j, i).direction = 45;
242 else if (((angle >= 67.5) && (angle <= 112.5)) ||
243 ((angle <= -67.5) && (angle >= -112.5)))
244 thet(j, i).direction = 90;
245 else if (((angle > 112.5) && (angle < 157.5)) ||
246 ((angle < -22.5) && (angle > -67.5)))
247 thet(j, i).direction = 135;
252 template <
typename Po
intInT,
typename Po
intOutT>
254 Edge<PointInT, PointOutT>::suppressNonMaxima(
259 const int height = edges.
height;
260 const int width = edges.
width;
264 for (
auto& point : maxima)
265 point.intensity = 0.0f;
268 for (
int i = 1; i < height - 1; i++) {
269 for (
int j = 1; j < width - 1; j++) {
270 const PointXYZIEdge& ptedge = edges(j, i);
271 PointXYZI& ptmax = maxima(j, i);
273 if (ptedge.magnitude < tLow)
278 switch (
static_cast<int>(ptedge.direction)) {
280 if (ptedge.magnitude >= edges(j - 1, i).magnitude &&
281 ptedge.magnitude >= edges(j + 1, i).magnitude)
282 ptmax.intensity = ptedge.magnitude;
286 if (ptedge.magnitude >= edges(j - 1, i - 1).magnitude &&
287 ptedge.magnitude >= edges(j + 1, i + 1).magnitude)
288 ptmax.intensity = ptedge.magnitude;
292 if (ptedge.magnitude >= edges(j, i - 1).magnitude &&
293 ptedge.magnitude >= edges(j, i + 1).magnitude)
294 ptmax.intensity = ptedge.magnitude;
298 if (ptedge.magnitude >= edges(j + 1, i - 1).magnitude &&
299 ptedge.magnitude >= edges(j - 1, i + 1).magnitude)
300 ptmax.intensity = ptedge.magnitude;
308 template <
typename Po
intInT,
typename Po
intOutT>
312 float tHigh = hysteresis_threshold_high_;
313 float tLow = hysteresis_threshold_low_;
314 const int height = input_->height;
315 const int width = input_->width;
317 output.
resize(height * width);
319 output.
width = width;
324 kernel_.setKernelSize(3);
325 kernel_.setKernelSigma(1.0);
327 kernel_.fetchKernel(*gaussian_kernel);
328 convolution_.setKernel(*gaussian_kernel);
329 convolution_.setInputCloud(input_);
330 convolution_.filter(*smoothed_cloud);
334 setInputCloud(smoothed_cloud);
335 detectEdgeSobel(*edges);
338 discretizeAngles(*edges);
342 suppressNonMaxima(*edges, *maxima, tLow);
345 for (
int i = 0; i < height; i++) {
346 for (
int j = 0; j < width; j++) {
347 if ((*maxima)(j, i).intensity < tHigh ||
348 (*maxima)(j, i).intensity == std::numeric_limits<float>::max())
351 (*maxima)(j, i).intensity = std::numeric_limits<float>::max();
352 cannyTraceEdge(1, 0, i, j, *maxima);
353 cannyTraceEdge(-1, 0, i, j, *maxima);
354 cannyTraceEdge(1, 1, i, j, *maxima);
355 cannyTraceEdge(-1, -1, i, j, *maxima);
356 cannyTraceEdge(0, -1, i, j, *maxima);
357 cannyTraceEdge(0, 1, i, j, *maxima);
358 cannyTraceEdge(-1, 1, i, j, *maxima);
359 cannyTraceEdge(1, -1, i, j, *maxima);
364 for (std::size_t i = 0; i < input_->size(); ++i) {
365 if ((*maxima)[i].intensity == std::numeric_limits<float>::max())
366 output[i].magnitude = 255;
368 output[i].magnitude = 0;
372 template <
typename Po
intInT,
typename Po
intOutT>
378 float tHigh = hysteresis_threshold_high_;
379 float tLow = hysteresis_threshold_low_;
380 const int height = input_x.
height;
381 const int width = input_x.
width;
383 output.
resize(height * width);
385 output.
width = width;
389 kernel_.setKernelSize(3);
390 kernel_.setKernelSigma(1.0);
392 kernel_.fetchKernel(*gaussian_kernel);
393 convolution_.setKernel(*gaussian_kernel);
396 convolution_.setInputCloud(input_x.
makeShared());
397 convolution_.filter(smoothed_cloud_x);
400 convolution_.setInputCloud(input_y.
makeShared());
401 convolution_.filter(smoothed_cloud_y);
405 sobelMagnitudeDirection(smoothed_cloud_x, smoothed_cloud_y, *edges.get());
408 discretizeAngles(*edges);
411 suppressNonMaxima(*edges, *maxima, tLow);
414 for (
int i = 0; i < height; i++) {
415 for (
int j = 0; j < width; j++) {
416 if ((*maxima)(j, i).intensity < tHigh ||
417 (*maxima)(j, i).intensity == std::numeric_limits<float>::max())
420 (*maxima)(j, i).intensity = std::numeric_limits<float>::max();
423 cannyTraceEdge( 1, 0, i, j, *maxima);
424 cannyTraceEdge(-1, 0, i, j, *maxima);
425 cannyTraceEdge( 1, 1, i, j, *maxima);
426 cannyTraceEdge(-1, -1, i, j, *maxima);
427 cannyTraceEdge( 0, -1, i, j, *maxima);
428 cannyTraceEdge( 0, 1, i, j, *maxima);
429 cannyTraceEdge(-1, 1, i, j, *maxima);
430 cannyTraceEdge( 1, -1, i, j, *maxima);
436 for (
int i = 0; i < height; i++) {
437 for (
int j = 0; j < width; j++) {
438 if ((*maxima)(j, i).intensity == std::numeric_limits<float>::max())
439 output(j, i).magnitude = 255;
441 output(j, i).magnitude = 0;
446 template <
typename Po
intInT,
typename Po
intOutT>
449 const float kernel_size,
452 convolution_.setInputCloud(input_);
456 kernel_.setKernelSigma(kernel_sigma);
457 kernel_.setKernelSize(kernel_size);
458 kernel_.fetchKernel(*log_kernel);
459 convolution_.setKernel(*log_kernel);
460 convolution_.filter(output);
Define standard C methods to do angle calculations.
void detectEdgePrewitt(pcl::PointCloud< PointOutT > &output)
Uses the Prewitt kernel for edge detection.
void detectEdgeLoG(const float kernel_sigma, const float kernel_size, pcl::PointCloud< PointOutT > &output)
Uses the LoG kernel for edge detection.
void detectEdgeSobel(pcl::PointCloud< PointOutT > &output)
Uses the Sobel kernel for edge detection.
void canny(const pcl::PointCloud< PointInT > &input_x, const pcl::PointCloud< PointInT > &input_y, pcl::PointCloud< PointOutT > &output)
Perform Canny edge detection with two separated input images for horizontal and vertical derivatives.
void sobelMagnitudeDirection(const pcl::PointCloud< PointInT > &input_x, const pcl::PointCloud< PointInT > &input_y, pcl::PointCloud< PointOutT > &output)
void detectEdgeRoberts(pcl::PointCloud< PointOutT > &output)
Uses the Roberts kernel for edge detection.
void detectEdgeCanny(pcl::PointCloud< PointOutT > &output)
All edges of magnitude above t_high are always classified as edges.
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).
shared_ptr< PointCloud< PointT > > Ptr
Ptr makeShared() const
Copy the cloud to the heap and return a smart pointer Note that deep copy is performed,...
float rad2deg(float alpha)
Convert an angle from radians to degrees.