Point Cloud Library (PCL)  1.15.1-dev
harris_2d.hpp
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Point Cloud Library (PCL) - www.pointclouds.org
5  * Copyright (c) 2010-2011, Willow Garage, 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 Willow Garage, Inc. 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  * $Id$
37  *
38  */
39 
40 
41 #ifndef PCL_HARRIS_KEYPOINT_2D_IMPL_H_
42 #define PCL_HARRIS_KEYPOINT_2D_IMPL_H_
43 
44 #include <pcl/common/point_tests.h>
45 
46 #include <cmath>
47 
48 namespace pcl
49 {
50 
51 template <typename PointInT, typename PointOutT, typename IntensityT> void
53 {
54  method_ = method;
55 }
56 
57 
58 template <typename PointInT, typename PointOutT, typename IntensityT> void
60 {
61  threshold_= threshold;
62 }
63 
64 
65 template <typename PointInT, typename PointOutT, typename IntensityT> void
67 {
68  refine_ = do_refine;
69 }
70 
71 
72 template <typename PointInT, typename PointOutT, typename IntensityT> void
74 {
75  nonmax_ = nonmax;
76 }
77 
78 
79 template <typename PointInT, typename PointOutT, typename IntensityT> void
81 {
82  window_width_= window_width;
83 }
84 
85 
86 template <typename PointInT, typename PointOutT, typename IntensityT> void
88 {
89  window_height_= window_height;
90 }
91 
92 
93 template <typename PointInT, typename PointOutT, typename IntensityT> void
95 {
96  skipped_pixels_= skipped_pixels;
97 }
98 
99 
100 template <typename PointInT, typename PointOutT, typename IntensityT> void
102 {
103  min_distance_ = min_distance;
104 }
105 
106 
107 template <typename PointInT, typename PointOutT, typename IntensityT> void
109 {
110  static const int width = static_cast<int> (input_->width);
111  static const int height = static_cast<int> (input_->height);
112 
113  int x = static_cast<int> (index % input_->width);
114  int y = static_cast<int> (index / input_->width);
115  // indices 0 1 2
116  // coefficients: ixix ixiy iyiy
117  std::fill_n(coefficients, 3, 0);
118 
119  int endx = std::min (width, x + half_window_width_);
120  int endy = std::min (height, y + half_window_height_);
121  for (int xx = std::max (0, x - half_window_width_); xx < endx; ++xx)
122  for (int yy = std::max (0, y - half_window_height_); yy < endy; ++yy)
123  {
124  const float& ix = derivatives_rows_ (xx,yy);
125  const float& iy = derivatives_cols_ (xx,yy);
126  coefficients[0]+= ix * ix;
127  coefficients[1]+= ix * iy;
128  coefficients[2]+= iy * iy;
129  }
130 }
131 
132 
133 template <typename PointInT, typename PointOutT, typename IntensityT> bool
135 {
137  {
138  PCL_ERROR ("[pcl::%s::initCompute] init failed.!\n", name_.c_str ());
139  return (false);
140  }
141 
142  if (!input_->isOrganized ())
143  {
144  PCL_ERROR ("[pcl::%s::initCompute] %s doesn't support non organized clouds!\n", name_.c_str ());
145  return (false);
146  }
147 
148  if (indices_->size () != input_->size ())
149  {
150  PCL_ERROR ("[pcl::%s::initCompute] %s doesn't support setting indices!\n", name_.c_str ());
151  return (false);
152  }
153 
154  if ((window_height_%2) == 0)
155  {
156  PCL_ERROR ("[pcl::%s::initCompute] Window height must be odd!\n", name_.c_str ());
157  return (false);
158  }
159 
160  if ((window_width_%2) == 0)
161  {
162  PCL_ERROR ("[pcl::%s::initCompute] Window width must be odd!\n", name_.c_str ());
163  return (false);
164  }
165 
166  if (window_height_ < 3 || window_width_ < 3)
167  {
168  PCL_ERROR ("[pcl::%s::initCompute] Window size must be >= 3x3!\n", name_.c_str ());
169  return (false);
170  }
171 
172  half_window_width_ = window_width_ / 2;
173  half_window_height_ = window_height_ / 2;
174 
175  return (true);
176 }
177 
178 
179 template <typename PointInT, typename PointOutT, typename IntensityT> void
181 {
182  derivatives_cols_.resize (input_->width, input_->height);
183  derivatives_rows_.resize (input_->width, input_->height);
184  //Compute cloud intensities first derivatives along columns and rows
185  //!!! nsallem 20120220 : we don't test here for density so if one term is nan the result is nan
186  int w = static_cast<int> (input_->width) - 1;
187  int h = static_cast<int> (input_->height) - 1;
188  // j = 0 --> j-1 out of range ; use 0
189  // i = 0 --> i-1 out of range ; use 0
190  derivatives_cols_(0,0) = (intensity_ ((*input_) (0,1)) - intensity_ ((*input_) (0,0))) * 0.5;
191  derivatives_rows_(0,0) = (intensity_ ((*input_) (1,0)) - intensity_ ((*input_) (0,0))) * 0.5;
192 
193  for(int i = 1; i < w; ++i)
194  {
195  derivatives_cols_(i,0) = (intensity_ ((*input_) (i,1)) - intensity_ ((*input_) (i,0))) * 0.5;
196  }
197 
198  derivatives_rows_(w,0) = (intensity_ ((*input_) (w,0)) - intensity_ ((*input_) (w-1,0))) * 0.5;
199  derivatives_cols_(w,0) = (intensity_ ((*input_) (w,1)) - intensity_ ((*input_) (w,0))) * 0.5;
200 
201  for(int j = 1; j < h; ++j)
202  {
203  // i = 0 --> i-1 out of range ; use 0
204  derivatives_rows_(0,j) = (intensity_ ((*input_) (1,j)) - intensity_ ((*input_) (0,j))) * 0.5;
205  for(int i = 1; i < w; ++i)
206  {
207  // derivative with respect to rows
208  derivatives_rows_(i,j) = (intensity_ ((*input_) (i+1,j)) - intensity_ ((*input_) (i-1,j))) * 0.5;
209 
210  // derivative with respect to cols
211  derivatives_cols_(i,j) = (intensity_ ((*input_) (i,j+1)) - intensity_ ((*input_) (i,j-1))) * 0.5;
212  }
213  // i = w --> w+1 out of range ; use w
214  derivatives_rows_(w,j) = (intensity_ ((*input_) (w,j)) - intensity_ ((*input_) (w-1,j))) * 0.5;
215  }
216 
217  // j = h --> j+1 out of range use h
218  derivatives_cols_(0,h) = (intensity_ ((*input_) (0,h)) - intensity_ ((*input_) (0,h-1))) * 0.5;
219  derivatives_rows_(0,h) = (intensity_ ((*input_) (1,h)) - intensity_ ((*input_) (0,h))) * 0.5;
220 
221  for(int i = 1; i < w; ++i)
222  {
223  derivatives_cols_(i,h) = (intensity_ ((*input_) (i,h)) - intensity_ ((*input_) (i,h-1))) * 0.5;
224  }
225  derivatives_rows_(w,h) = (intensity_ ((*input_) (w,h)) - intensity_ ((*input_) (w-1,h))) * 0.5;
226  derivatives_cols_(w,h) = (intensity_ ((*input_) (w,h)) - intensity_ ((*input_) (w,h-1))) * 0.5;
227 
228  switch (method_)
229  {
230  case HARRIS:
231  responseHarris(*response_);
232  break;
233  case NOBLE:
234  responseNoble(*response_);
235  break;
236  case LOWE:
237  responseLowe(*response_);
238  break;
239  case TOMASI:
240  responseTomasi(*response_);
241  break;
242  }
243 
244  if (!nonmax_)
245  {
246  output = *response_;
247  for (std::size_t i = 0; i < response_->size (); ++i)
248  keypoints_indices_->indices.push_back (i);
249  }
250  else
251  {
252  std::sort (indices_->begin (), indices_->end (), [this] (int p1, int p2) { return greaterIntensityAtIndices (p1, p2); });
253  const float threshold = threshold_ * (*response_)[indices_->front ()].intensity;
254  output.clear ();
255  output.reserve (response_->size());
256  std::vector<bool> occupency_map (response_->size (), false);
257  int width (response_->width);
258  int height (response_->height);
259  const int occupency_map_size (occupency_map.size ());
260 
261 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
262 #pragma omp parallel for \
263  default(none) \
264  shared(occupency_map, output) \
265  firstprivate(width, height) \
266  num_threads(threads_)
267 #else
268 #pragma omp parallel for \
269  default(none) \
270  shared(occupency_map, occupency_map_size, output, threshold) \
271  firstprivate(width, height) \
272  num_threads(threads_)
273 #endif
274  for (int i = 0; i < occupency_map_size; ++i)
275  {
276  int idx = indices_->at (i);
277  const PointOutT& point_out = response_->points [idx];
278  if (occupency_map[idx] || point_out.intensity < threshold || !isXYZFinite (point_out))
279  continue;
280 
281 #pragma omp critical
282  {
283  output.push_back (point_out);
284  keypoints_indices_->indices.push_back (idx);
285  }
286 
287  int u_end = std::min (width, idx % width + min_distance_);
288  int v_end = std::min (height, idx / width + min_distance_);
289  for(int u = std::max (0, idx % width - min_distance_); u < u_end; ++u)
290  for(int v = std::max (0, idx / width - min_distance_); v < v_end; ++v)
291  occupency_map[v*input_->width+u] = true;
292  }
293 
294  // if (refine_)
295  // refineCorners (output);
296 
297  output.height = 1;
298  output.width = output.size();
299  }
300 
301  // we don not change the denseness
302  output.is_dense = input_->is_dense;
303 }
304 
305 
306 template <typename PointInT, typename PointOutT, typename IntensityT> void
308 {
309  PCL_ALIGN (16) float covar [3];
310  output.clear ();
311  output.resize (input_->size ());
312  const int output_size (output.size ());
313 
314 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
315 #pragma omp parallel for \
316  default(none) \
317  shared(output) \
318  firstprivate(covar) \
319  num_threads(threads_)
320 #else
321 #pragma omp parallel for \
322  default(none) \
323  shared(output, output_size) \
324  firstprivate(covar) \
325  num_threads(threads_)
326 #endif
327  for (int index = 0; index < output_size; ++index)
328  {
329  PointOutT& out_point = output.points [index];
330  const PointInT &in_point = (*input_).points [index];
331  out_point.intensity = 0;
332  out_point.x = in_point.x;
333  out_point.y = in_point.y;
334  out_point.z = in_point.z;
335  if (isXYZFinite (in_point))
336  {
337  computeSecondMomentMatrix (index, covar);
338  float trace = covar [0] + covar [2];
339  if (trace != 0.f)
340  {
341  float det = covar[0] * covar[2] - covar[1] * covar[1];
342  out_point.intensity = 0.04f + det - 0.04f * trace * trace;
343  }
344  }
345  }
346 
347  output.height = input_->height;
348  output.width = input_->width;
349 }
350 
351 
352 template <typename PointInT, typename PointOutT, typename IntensityT> void
354 {
355  PCL_ALIGN (16) float covar [3];
356  output.clear ();
357  output.resize (input_->size ());
358  const int output_size (output.size ());
359 
360 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
361 #pragma omp parallel for \
362  default(none) \
363  shared(output) \
364  firstprivate(covar) \
365  num_threads(threads_)
366 #else
367 #pragma omp parallel for \
368  default(none) \
369  shared(output, output_size) \
370  firstprivate(covar) \
371  num_threads(threads_)
372 #endif
373  for (int index = 0; index < output_size; ++index)
374  {
375  PointOutT &out_point = output.points [index];
376  const PointInT &in_point = input_->points [index];
377  out_point.x = in_point.x;
378  out_point.y = in_point.y;
379  out_point.z = in_point.z;
380  out_point.intensity = 0;
381  if (isXYZFinite (in_point))
382  {
383  computeSecondMomentMatrix (index, covar);
384  float trace = covar [0] + covar [2];
385  if (trace != 0)
386  {
387  float det = covar[0] * covar[2] - covar[1] * covar[1];
388  out_point.intensity = det / trace;
389  }
390  }
391  }
392 
393  output.height = input_->height;
394  output.width = input_->width;
395 }
396 
397 
398 template <typename PointInT, typename PointOutT, typename IntensityT> void
400 {
401  PCL_ALIGN (16) float covar [3];
402  output.clear ();
403  output.resize (input_->size ());
404  const int output_size (output.size ());
405 
406 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
407 #pragma omp parallel for \
408  default(none) \
409  shared(output) \
410  firstprivate(covar) \
411  num_threads(threads_)
412 #else
413 #pragma omp parallel for \
414  default(none) \
415  shared(output, output_size) \
416  firstprivate(covar) \
417  num_threads(threads_)
418 #endif
419  for (int index = 0; index < output_size; ++index)
420  {
421  PointOutT &out_point = output.points [index];
422  const PointInT &in_point = input_->points [index];
423  out_point.x = in_point.x;
424  out_point.y = in_point.y;
425  out_point.z = in_point.z;
426  out_point.intensity = 0;
427  if (isXYZFinite (in_point))
428  {
429  computeSecondMomentMatrix (index, covar);
430  float trace = covar [0] + covar [2];
431  if (trace != 0)
432  {
433  float det = covar[0] * covar[2] - covar[1] * covar[1];
434  out_point.intensity = det / (trace * trace);
435  }
436  }
437  }
438 
439  output.height = input_->height;
440  output.width = input_->width;
441 }
442 
443 
444 template <typename PointInT, typename PointOutT, typename IntensityT> void
446 {
447  PCL_ALIGN (16) float covar [3];
448  output.clear ();
449  output.resize (input_->size ());
450  const int output_size (output.size ());
451 
452 #if OPENMP_LEGACY_CONST_DATA_SHARING_RULE
453 #pragma omp parallel for \
454  default(none) \
455  shared(output) \
456  firstprivate(covar) \
457  num_threads(threads_)
458 #else
459 #pragma omp parallel for \
460  default(none) \
461  shared(output, output_size) \
462  firstprivate(covar) \
463  num_threads(threads_)
464 #endif
465  for (int index = 0; index < output_size; ++index)
466  {
467  PointOutT &out_point = output.points [index];
468  const PointInT &in_point = input_->points [index];
469  out_point.x = in_point.x;
470  out_point.y = in_point.y;
471  out_point.z = in_point.z;
472  out_point.intensity = 0;
473  if (isXYZFinite (in_point))
474  {
475  computeSecondMomentMatrix (index, covar);
476  // min egenvalue
477  out_point.intensity = ((covar[0] + covar[2] - std::sqrt((covar[0] - covar[2])*(covar[0] - covar[2]) + 4 * covar[1] * covar[1])) /2.0f);
478  }
479  }
480 
481  output.height = input_->height;
482  output.width = input_->width;
483 }
484 
485 } // namespace pcl
486 
487 #define PCL_INSTANTIATE_HarrisKeypoint2D(T,U,I) template class PCL_EXPORTS pcl::HarrisKeypoint2D<T,U,I>;
488 
489 #endif // #ifndef PCL_HARRIS_KEYPOINT_2D_IMPL_H_
490 
void setNonMaxSupression(bool=false)
whether non maxima suppression should be applied or the response for each point should be returned
Definition: harris_2d.hpp:73
void setSkippedPixels(int skipped_pixels)
Set number of pixels to skip.
Definition: harris_2d.hpp:94
void responseTomasi(PointCloudOut &output) const
Definition: harris_2d.hpp:445
void responseLowe(PointCloudOut &output) const
Definition: harris_2d.hpp:399
void setRefine(bool do_refine)
whether the detected key points should be refined or not.
Definition: harris_2d.hpp:66
void detectKeypoints(PointCloudOut &output) override
Definition: harris_2d.hpp:180
void responseNoble(PointCloudOut &output) const
Definition: harris_2d.hpp:353
void setMinimalDistance(int min_distance)
Set minimal distance between candidate keypoints.
Definition: harris_2d.hpp:101
void setMethod(ResponseMethod type)
set the method of the response to be calculated.
Definition: harris_2d.hpp:52
void computeSecondMomentMatrix(std::size_t pos, float *coefficients) const
calculates the upper triangular part of unnormalized covariance matrix over intensities given by the ...
Definition: harris_2d.hpp:108
void setWindowHeight(int window_height)
Set window height.
Definition: harris_2d.hpp:87
void responseHarris(PointCloudOut &output) const
gets the corner response for valid input points
Definition: harris_2d.hpp:307
typename Keypoint< PointInT, PointOutT >::PointCloudOut PointCloudOut
Definition: harris_2d.h:60
bool initCompute() override
Definition: harris_2d.hpp:134
void setThreshold(float threshold)
set the threshold value for detecting corners.
Definition: harris_2d.hpp:59
void setWindowWidth(int window_width)
Set window width.
Definition: harris_2d.hpp:80
Keypoint represents the base class for key points.
Definition: keypoint.h:49
constexpr bool isXYZFinite(const PointT &) noexcept
Definition: point_tests.h:126