Ocean
HarrisCornerDetector.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_CV_DETECTOR_HARRIS_CORNER_DETECTOR_H
9 #define META_OCEAN_CV_DETECTOR_HARRIS_CORNER_DETECTOR_H
10 
14 
15 #include "ocean/base/Frame.h"
16 #include "ocean/base/Worker.h"
17 
19 #include "ocean/cv/NEON.h"
21 
22 #include "ocean/math/Numeric.h"
23 #include "ocean/math/Vector2.h"
24 
25 namespace Ocean
26 {
27 
28 namespace CV
29 {
30 
31 namespace Detector
32 {
33 
34 /**
35  * This class implements the Harris corner detector.
36  * @ingroup cvdetector
37  */
38 class OCEAN_CV_DETECTOR_EXPORT HarrisCornerDetector
39 {
40  public:
41 
42  /**
43  * Definition of a boolean enum for frame un-/distortion properties (to improve code readability).
44  */
46  {
47  /// The provided frame is distorted so that all resulting feature locations are distorted.
48  FD_FRAME_IS_DISTORTED = false,
49  /// The provided frame is undistorted so that all resulting feature locations are also undistorted.
50  FD_FRAME_IS_UNDISTORTED = true,
51  };
52 
53  /**
54  * Definition of a boolean enum for precision properties (to improve code readability).
55  */
57  {
58  /// The resulting position of the feature point will have a precision with pixel accuracy.
59  PP_PIXEL_ACCURACY = false,
60  /// The resulting position of the feature point will have a precision with sub-pixel accuracy.
61  PP_SUBPIXEL_ACCURACY = true
62  };
63 
64  private:
65 
66  /**
67  * Definition of a maximum suppression object holding integer strength parameters.
68  */
70 
71  /**
72  * This class implements a helper object allowing to determine the precise 2D position of Harris corners.
73  */
75  {
76  public:
77 
78  /**
79  * Creates a new object.
80  * @param frame The 8 bit frame on which the Harris corners are detected, must be valid
81  * @param width The width of the given frame in pixel, with range [7, infinity)
82  * @param height The height of the given frame in pixel, with range [7, infinity)
83  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
84  */
85  inline PreciseCornerPosition(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements);
86 
87  /**
88  * Determines the precise position of a given (rough) Harris corner.
89  * @param x Horizontal position of the Harris corner, with range [3, frameWidth - 4]
90  * @param y Vertical position of the Harris corner, with range [3, frameHeight - 4]
91  * @param strength The strength value of the Harris corner
92  * @param preciseX The resulting horizontal position of the Harris corner with sub-pixel accuracy, with range [0, frameWidth_)
93  * @param preciseY The resulting vertical position of the Harris corner with sub-pixel accuracy, with range [0, frameHeight_)
94  * @param preciseStrength The resulting strength value of the precise Harris corner
95  * @return True, if succeeded
96  */
97  bool precisePosition(const unsigned int x, const unsigned int y, const int32_t strength, Scalar& preciseX, Scalar& preciseY, int32_t& preciseStrength);
98 
99  protected:
100 
101  /// The frame in which the Harris corners are detected.
102  const uint8_t* const frameData_;
103 
104  /// The frame width in pixel, with range [7, infinity)
105  const unsigned int frameWidth_;
106 
107  /// The frame height in pixel, with range [7, infinity)
108  const unsigned int frameHeight_;
109 
110  /// The optional number of padding elements at the end of each row, with range [0, infinity)
111  const unsigned int framePaddingElements_;
112  };
113 
114  public:
115 
116  /**
117  * Detects Harris corners inside a given 8 bit grayscale image.
118  * @param yFrame The 8 bit grayscale frame in which the Harris corners will be detected, must be valid
119  * @param width The width of the frame in pixel, with range [10, infinity)
120  * @param height The height of the frame in pixel, with range [7, infinity)
121  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
122  * @param threshold Minimal strength value all detected corners must exceed to count as corner, with range [0, 512]
123  * @param frameIsUndistorted True, if the original input frame is undistorted and thus the 2D feature position will be undistorted too
124  * @param corners Resulting Harris corners detected inside the given frame
125  * @param determineExactPosition True, to force the subpixel interpolation to determine the exact corner position
126  * @param worker Optional worker object to distribute the computational load to several CPU cores
127  * @return True, if succeeded
128  */
129  static inline bool detectCorners(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition = false, Worker* worker = nullptr);
130 
131  /**
132  * Detects Harris corners inside a sub-frame of a given 8 bit grayscale image.
133  * @param yFrame 8 bit grayscale frame to be used for corner detection with pixel origin in the upper left corner
134  * @param width The width of the frame in pixel, with range [10, infinity)
135  * @param height The height of the frame in pixel, with range [7, infinity)
136  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
137  * @param subFrameLeft Left position of the sub frame defined in the original image in pixel, with range [0, width - 7]
138  * @param subFrameTop Top position of the sub frame defined in the original image in pixel, with range [0, height - 7]
139  * @param subFrameWidth Width of the sub frame in pixel, with range [7, width - subFrameLeft]
140  * @param subFrameHeight Height of the sub frame in pixel, with range [7, height - subFrameTop]
141  * @param threshold Minimal strength value all detected corners must exceed to count as corner, with range [0, 512]
142  * @param frameIsUndistorted True, if the original input frame is undistorted and thus the 2D feature position will be undistorted too
143  * @param corners Resulting Harris corners detected inside the given frame
144  * @param determineExactPosition True, to force the subpixel interpolation to determine the exact corner position
145  * @param worker Optional worker object to distribute the computational load to several CPU cores
146  * @return True, if succeeded
147  */
148  static bool detectCorners(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int subFrameLeft, const unsigned int subFrameTop, const unsigned int subFrameWidth, const unsigned int subFrameHeight, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition = false, Worker* worker = nullptr);
149 
150  /**
151  * Detects Harris corners inside a given frame.
152  * If the given frame is not an 8 bit grayscale frame with pixel origin in the upper left corner, the frame will be converted internally.
153  * @param frame The frame to be used for corner detection, with resolution [10, infinity)x[7, infinity), must be valid
154  * @param threshold Minimal strength value all detected corners must exceed to count as corner, with range [0, 512]
155  * @param frameIsUndistorted True, if the original input frame is undistorted and thus the 2D feature position will be undistorted too
156  * @param corners Resulting Harris corners detected inside the given frame
157  * @param determineExactPosition True, to force the subpixel interpolation to determine the exact corner position
158  * @param worker Optional worker object to distribute the computational load to several CPU cores
159  * @return True, if succeeded
160  */
161  static inline bool detectCorners(const Frame& frame, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition = false, Worker* worker = nullptr);
162 
163  /**
164  * Detects Harris corners inside a sub-region of a given frame.
165  * If the given frame is not an 8 bit grayscale frame with pixel origin in the upper left corner, the frame will be converted internally.
166  * @param frame The frame to be used for corner detection, with resolution [10, infinity)x[7, infinity), must be valid
167  * @param subFrameLeft Left position of the sub frame defined in the original image in pixel, with range [0, frame.width() - 7]
168  * @param subFrameTop Top position of the sub frame defined in the original image in pixel, with range [0, frame.height() - 7]
169  * @param subFrameWidth Width of the sub frame in pixel, with range [10, frame.width() - subFrameLeft]
170  * @param subFrameHeight Height of the sub frame in pixel, with range [7, frame.height() - subFrameTop]
171  * @param threshold Minimal strength value all detected corners must exceed to count as corner, with range [0, 512]
172  * @param frameIsUndistorted True, if the original input frame is undistorted and thus the 2D feature position will be undistorted too
173  * @param corners Resulting Harris corners detected inside the given frame
174  * @param determineExactPosition True, to force the subpixel interpolation to determine the exact corner position
175  * @param worker Optional worker object to distribute the computational load to several CPU cores
176  * @return True, if succeeded
177  */
178  static inline bool detectCorners(const Frame& frame, const unsigned int subFrameLeft, const unsigned int subFrameTop, const unsigned int subFrameWidth, const unsigned int subFrameHeight, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition = false, Worker* worker = nullptr);
179 
180  /**
181  * Creates the Harris corner votes for an entire frame (and therefore for each pixel) without applying a maximum suppression.
182  * The resulting votes may have an invalid 2 pixel wide frame border (depending on 'setBorderPixels').
183  * @param yFrame The 8 bit (grayscale) frame to be used for Harris application, with minimal size 7x7
184  * @param width The width of the given frame in pixel, with range [10, infinity)
185  * @param height The height of the given frame in pixel, with range [7, infinity)
186  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
187  * @param votes Resulting Harris votes values, make sure that the buffer is large enough
188  * @param votesPaddingElements The number of padding elements at the end of each votes row, in elements, with range [0, infinity)
189  * @param worker Optional worker object to distribute the computational load to several CPU cores
190  * @param setBorderPixels True, to set the border pixels to a neutral value; False, to keep random memory values
191  */
192  static void harrisVotesFrame(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, int32_t* votes, const unsigned int votesPaddingElements, Worker* worker = nullptr, const bool setBorderPixels = false);
193 
194  /**
195  * Creates the Harris corner votes for the horizontal and vertical sobel responses for an entire frame (and therefore for each pixel of the original frame) without applying a maximum suppression.
196  * The resulting votes may have an invalid 2 pixel wide frame border (depending on 'setBorderPixels').
197  * @param sobelResponse 16 bit sobel filter responses (8 bit for the horizontal response and 8 bit for the vertical response) to be used for Harris application, with minimal size 5x5
198  * @param width The width of the original frame in pixel, with range [5, infinity)
199  * @param height The height of the original frame in pixel, with range [5, infinity)
200  * @param sobelResponsePaddingElements The number of padding elements at the end of each sobel response row, in elements, with range [0, infinity)
201  * @param votes Resulting Harris votes values, make sure that the buffer is large enough
202  * @param votesPaddingElements Optional padding at the end of each votes row in elements, with range [0, infinity)
203  * @param worker Optional worker object to distribute the computational load to several CPU cores
204  * @param setBorderPixels True, to set the border pixels to a neutral value; False, to keep random memory values
205  */
206  static void harrisVotesFrameSobelResponse(const int8_t* sobelResponse, const unsigned int width, const unsigned int height, const unsigned int sobelResponsePaddingElements, int32_t* votes, const unsigned int votesPaddingElements, Worker* worker = nullptr, const bool setBorderPixels = false);
207 
208  /**
209  * Calculates the Harris corner votes for several given positions in a frame only.
210  * @param yFrame The 8 bit (grayscale) frame to be used for Harris application, with minimal size 5x5
211  * @param width The width of the given frame in pixel, with range [10, infinity)
212  * @param height The height of the given frame in pixel, with range [7, infinity)
213  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
214  * @param positions Pixel positions inside the given frame to determine the responses for
215  * @param numberPositions Number of given pixel positions
216  * @param votes Resulting Harris votes values, one for each given position in the same order, make sure that enough buffer is available
217  * @param worker Optional worker object to distribute the computational load to several CPU cores
218  */
219  static void harrisVotes(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const PixelPosition* positions, const size_t numberPositions, int32_t* votes, Worker* worker = nullptr);
220 
221  /**
222  * Calculates the Harris corner vote for one specific pixel from an 8 bit grayscale frame.
223  * @param yFrame The 8 bit grayscale frame that is used to determine the vote, must be valid
224  * @param width The width of the given frame in pixel, with range [10, infinity)
225  * @param x Horizontal position in pixel, with range [2, width - 2)
226  * @param y Vertical position in pixel, with range [2, height - 2)
227  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
228  * @return Resulting Harris vote
229  */
230  static int32_t harrisVotePixel(const uint8_t* yFrame, const unsigned int width, const unsigned int x, const unsigned int y, const unsigned int yFramePaddingElements);
231 
232  /**
233  * Calculates the Harris corner vote for one specific sub-pixel position from an 8 bit grayscale frame.
234  * @param yFrame The 8 bit grayscale frame that is used to determine the vote, must be valid
235  * @param width The width of the given frame in pixel, with range [10, infinity)
236  * @param x Horizontal position in pixel, with range [3, width - 3)
237  * @param y Vertical position in pixel, with range [3, height - 3)
238  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
239  * @return Resulting Harris vote
240  */
241  static int32_t harrisVoteSubPixel(const uint8_t* yFrame, const unsigned int width, const Scalar x, const Scalar y, const unsigned int yFramePaddingElements);
242 
243  /**
244  * Calculates the Harris corner votes for specified sub-pixel positions from an 8 bit grayscale frame.
245  * @param yFrame The 8 bit grayscale frame that is used to determine the vote
246  * @param width The width of the given frame in pixel, with range [10, infinity)
247  * @param positions The sub-pixel positions for which the Harris votes will be determined
248  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
249  * @param worker Optional worker object to distribute the computation
250  * @return The resulting Harris votes, one vote for each position
251  */
252  static std::vector<int32_t> harrisVotesSubPixel(const uint8_t* yFrame, const unsigned int width, const Vectors2& positions, const unsigned int yFramePaddingElements, Worker* worker = nullptr);
253 
254  /**
255  * Calculates one Harris Corner vote for one specific pixel from a frame storing sobel responses (Sx, Sy).
256  * @param sobelResponses The 2 x 8bit sobel filter responses (8 bit for the horizontal response and 8 bit for the vertical response) to be used for Harris application pointing to the pixel of interest
257  * @param width The width of the given response frame in pixel, with range [3, infinity)
258  * @param sobelResponsesPaddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
259  * @return Resulting Harris vote
260  */
261  static inline int32_t harrisVotePixel(const int8_t* sobelResponses, const unsigned int width, const unsigned int sobelResponsesPaddingElements);
262 
263  /**
264  * Calculates one Harris Corner vote for one specific pixel for a 3x3 region from a buffer storing interleaved squared sobel responses (Ixx, Iyy, Ixy).
265  * @param squaredSobelResponses 3x32 bit sobel filter responses (32 bit for the squared horizontal response, 32 bit for the square vertical response and 32 bit for the product of horizontal and vertical response) to be used for Harris application pointing to the pixel of interest
266  * @param width The width of the given response frame in pixel, with range [3, infinity)
267  * @param squaredSobelResponsesPaddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
268  * @return Resulting Harris vote
269  */
270  static inline int32_t harrisVotePixel(const int32_t* squaredSobelResponses, const unsigned int width, const unsigned int squaredSobelResponsesPaddingElements);
271 
272  /**
273  * Calculates one Harris Corner vote for a 3x3 region from three buffers storing Sobel responses products Ixx, Iyy, and Ixy.
274  * @param responsesXX0 The first row of squared horizontal Sobel responses (Ixx), at least three, must be valid
275  * @param responsesXX1 The second row of squared horizontal Sobel responses (Ixx), at least three, must be valid
276  * @param responsesXX2 The third row of squared horizontal Sobel responses (Ixx), at least three, must be valid
277  * @param responsesYY0 The first row of squared vertical Sobel responses (Iyy), at least three, must be valid
278  * @param responsesYY1 The second row of squared vertical Sobel responses (Iyy), at least three, must be valid
279  * @param responsesYY2 The third row of squared vertical Sobel responses (Iyy), at least three, must be valid
280  * @param responsesXY0 The first row of products of horizontal and vertical Sobel responses (Ixy), at least three, must be valid
281  * @param responsesXY1 The second row of products of horizontal and vertical Sobel responses (Ixy), at least three, must be valid
282  * @param responsesXY2 The third row of products of horizontal and vertical Sobel responses (Ixy), at least three, must be valid
283  * @return Resulting Harris vote
284  */
285  static inline int32_t harrisVote(const int16_t* const responsesXX0, const int16_t* const responsesXX1, const int16_t* const responsesXX2, const int16_t* const responsesYY0, const int16_t* const responsesYY1, const int16_t* const responsesYY2, const int16_t* const responsesXY0, const int16_t* const responsesXY1, const int16_t* const responsesXY2);
286 
287  /**
288  * Returns the threshold used internally for a given threshold.
289  * Due to internal optimizations, we used an adjusted threshold internally.<br>
290  * <pre>
291  * internalThreshold = ((threshold ^ 2) / 8) ^ 2
292  * </pre>
293  * @param threshold The (external) threshold for which the internal threshold will be returned, with range [0, 512]
294  * @return The corresponding threshold which is used internally when comparing the Harris votes, with range [0, infinity)
295  * @see determineThreshold().
296  */
297  static constexpr int32_t determineInternalThreshold(const unsigned int threshold);
298 
299  /**
300  * Determines the (external) threshold corresponding to an (internal) Harris vote.
301  * This function mainly determines the reverse of determineInternalThreshold().
302  * @param vote The (internal) Harris vote for which the corresponding threshold will be returned, with range (-infinity, infinity)
303  * @return The resulting threshold, with range [0, infinity)
304  * @tparam T The data type of the vote
305  * @see determineInternalThreshold().
306  */
307  template <typename T>
308  static inline T determineThreshold(const T vote);
309 
310  private:
311 
312  /**
313  * Determines Harris votes inside a sub-frame of a given buffer holding the filter responses.
314  * @param response Buffer holding the normalized 8 bit horizontal and vertical filter responses
315  * @param width The width of the source frame in pixel, with range [10, infinity)
316  * @param height The height of the source frame in pixel, with range [7, infinity)
317  * @param responsePaddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
318  * @param votes Buffer receiving the resulting corner votes
319  * @param votesPaddingElements The number of padding elements at the end of each votes row, in elements, with range [0, infinity)
320  * @param firstRow First row to be handled, with range [0, height - 1]
321  * @param numberRows Number of rows to be handled, with range [1u, height - firstRow]
322  */
323  static void harrisVotesByResponseSubset(const int8_t* response, const unsigned int width, const unsigned int height, const unsigned int responsePaddingElements, int32_t* votes, const unsigned int votesPaddingElements, const unsigned int firstRow, const unsigned int numberRows);
324 
325  /**
326  * Creates the Harris corner votes for a subset of specified sub-pixel positions from an 8 bit grayscale frame.
327  * @param yFrame The 8 bit grayscale frame that is used to determine the vote
328  * @param width The width of the given frame in pixel, with range [10, infinity)
329  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
330  * @param positions The sub-pixel positions for which the Harris votes will be determined
331  * @param votes The resulting votes, one vote for each position
332  * @param firstPosition The first position to handle
333  * @param numberPositions The number of positions to handle
334  */
335  static void harrisVotesSubPixelSubset(const uint8_t* yFrame, const unsigned int width, const unsigned int yFramePaddingElements, const Vector2* positions, int32_t* votes, const unsigned int firstPosition, const unsigned int numberPositions);
336 
337  /**
338  * Detects Harris corners inside a sub-frame of a given frame.
339  * @param yFrame Grayscale 8 bit frame, must be valid
340  * @param width The width of the source frame in pixel, with range [10, infinity)
341  * @param height The height of the source frame in pixel, with range [7, infinity)
342  * @param yFramePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
343  * @param internalThreshold Minimal threshold a Harris corner must exceed, with range (-infinity, infinity)
344  * @param nonMaximumSuppression Non maximum suppression buffer holding all votes stronger than the specified threshold
345  * @param firstColumn First column to be handled
346  * @param numberColumns Number o f columns to be handled
347  * @param firstRow First row to be handled
348  * @param numberRows Number of rows to be handled
349  */
350  static void detectCornerCandidatesSubset(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const int32_t internalThreshold, NonMaximumSuppressionVote* nonMaximumSuppression, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows);
351 
352 #if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
353 
354  /**
355  * Calculates four Harris Corner votes for 3x3 regions from sums of (squared) sobel responses.
356  * @param Ixx_s_32x4 The four individual sums of squared horizontal Sobel responses (Ixx)
357  * @param Iyy_s_32x4 The four individual sums of squared vertical Sobel responses (Iyy)
358  * @param Ixy_s_32x4 The four individual sums of products of horizontal and vertical Sobel responses (Ixy)
359  * @param votes The resulting four individual Harris corner votes, must be valid
360  */
361  static void determine4VotesNEON(const int32x4_t& Ixx_s_32x4, const int32x4_t& Iyy_s_32x4, const int32x4_t& Ixy_s_32x4, int32_t* votes);
362 
363 #endif // OCEAN_HARDWARE_NEON_VERSION >= 10
364 
365  /**
366  * Returns the square value.
367  * @param value The value to be squared, with range [-65535, 65535]
368  * @return Square value
369  */
370  static constexpr uint32_t sqr(const int32_t value);
371 
372  /**
373  * Returns the square value.
374  * @param value The value to be squared, with range [0, 65535]
375  * @return Square value
376  */
377  static constexpr uint32_t sqr(const uint32_t value);
378 
379  /**
380  * Returns the square value.
381  * @param value The value to be squared, with range [-4294967295, 4294967295]
382  * @return Square value
383  */
384  static constexpr uint64_t sqr(const int64_t value);
385 };
386 
387 inline HarrisCornerDetector::PreciseCornerPosition::PreciseCornerPosition(const uint8_t* frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements) :
388  frameData_(frame),
389  frameWidth_(width),
390  frameHeight_(height),
391  framePaddingElements_(framePaddingElements)
392 {
393  ocean_assert(frameData_ != nullptr);
394  ocean_assert(frameWidth_ >= 7u && frameHeight_ >= 7u);
395 }
396 
397 inline bool HarrisCornerDetector::detectCorners(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition, Worker* worker)
398 {
399  ocean_assert(yFrame != nullptr);
400  ocean_assert(width >= 10u && height >= 7u);
401 
402  return detectCorners(yFrame, width, height, yFramePaddingElements, 0u, 0u, width, height, threshold, frameIsUndistorted, corners, determineExactPosition, worker);
403 }
404 
405 inline bool HarrisCornerDetector::detectCorners(const Frame& frame, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition, Worker* worker)
406 {
407  ocean_assert(frame.isValid());
408 
409  Frame yFrame;
411  {
412  return false;
413  }
414 
415  return detectCorners(yFrame.constdata<uint8_t>(), yFrame.width(), yFrame.height(), yFrame.paddingElements(), threshold, frameIsUndistorted, corners, determineExactPosition, worker);
416 }
417 
418 inline bool HarrisCornerDetector::detectCorners(const Frame& frame, const unsigned int subFrameLeft, const unsigned int subFrameTop, const unsigned int subFrameWidth, const unsigned int subFrameHeight, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners& corners, const bool determineExactPosition, Worker* worker)
419 {
420  ocean_assert(frame.isValid());
421 
422  Frame yFrame;
424  {
425  return false;
426  }
427 
428  return detectCorners(yFrame.constdata<uint8_t>(), yFrame.width(), yFrame.height(), yFrame.paddingElements(), subFrameLeft, subFrameTop, subFrameWidth, subFrameHeight, threshold, frameIsUndistorted, corners, determineExactPosition, worker);
429 }
430 
431 inline int32_t HarrisCornerDetector::harrisVotePixel(const int8_t* sobelResponse, const unsigned int width, const unsigned int sobelResponsesPaddingElements)
432 {
433  ocean_assert(sobelResponse != nullptr);
434  ocean_assert(width >= 3u);
435 
436  const unsigned int sobelResponsesStrideElements = width * 2u + sobelResponsesPaddingElements;
437 
438  const int8_t* const response0 = sobelResponse - sobelResponsesStrideElements;
439  const int8_t* const response1 = sobelResponse;
440  const int8_t* const response2 = sobelResponse + sobelResponsesStrideElements;
441 
442  const uint32_t Ixx = sqr(*(response0 - 2)) + sqr(*(response0 + 0)) + sqr(*(response0 + 2))
443  + sqr(*(response1 - 2)) + sqr(*(response1 + 0)) + sqr(*(response1 + 2))
444  + sqr(*(response2 - 2)) + sqr(*(response2 + 0)) + sqr(*(response2 + 2));
445 
446  const uint32_t Iyy = sqr(*(response0 - 1)) + sqr(*(response0 + 1)) + sqr(*(response0 + 3))
447  + sqr(*(response1 - 1)) + sqr(*(response1 + 1)) + sqr(*(response1 + 3))
448  + sqr(*(response2 - 1)) + sqr(*(response2 + 1)) + sqr(*(response2 + 3));
449 
450  const int32_t Ixy = *(response0 - 2) * *(response0 - 1) + *(response0 + 0) * *(response0 + 1) + *(response0 + 2) * *(response0 + 3)
451  + *(response1 - 2) * *(response1 - 1) + *(response1 + 0) * *(response1 + 1) + *(response1 + 2) * *(response1 + 3)
452  + *(response2 - 2) * *(response2 - 1) + *(response2 + 0) * *(response2 + 1) + *(response2 + 2) * *(response2 + 3);
453 
454  const int32_t determinant = int32_t((Ixx / 8u) * (Iyy / 8u)) - int32_t(sqr((Ixy / 8)));
455  const uint32_t sqrTrace = sqr((Ixx + Iyy) / 8u);
456 
457  ocean_assert(NumericT<int32_t>::isInsideValueRange(int64_t(sqrTrace) * 3ll));
458 
459  return determinant - int32_t((sqrTrace * 3u) / 64u);
460 }
461 
462 inline int32_t HarrisCornerDetector::harrisVotePixel(const int32_t* squaredSobelResponses, const unsigned int width, const unsigned int squaredSobelResponsesPaddingElements)
463 {
464  ocean_assert(squaredSobelResponses != nullptr);
465  ocean_assert(width >= 3u);
466 
467  const unsigned int squaredSobelResponsesStrideElements = width * 3u + squaredSobelResponsesPaddingElements;
468 
469  const int32_t* const response0 = squaredSobelResponses - squaredSobelResponsesStrideElements;
470  const int32_t* const response1 = squaredSobelResponses;
471  const int32_t* const response2 = squaredSobelResponses + squaredSobelResponsesStrideElements;
472 
473  const uint32_t Ixx = uint32_t(*(response0 - 3) + *(response0 + 0) + *(response0 + 3)
474  + *(response1 - 3) + *(response1 + 0) + *(response1 + 3)
475  + *(response2 - 3) + *(response2 + 0) + *(response2 + 3));
476 
477  const uint32_t Iyy = uint32_t(*(response0 - 2) + *(response0 + 1) + *(response0 + 4)
478  + *(response1 - 2) + *(response1 + 1) + *(response1 + 4)
479  + *(response2 - 2) + *(response2 + 1) + *(response2 + 4));
480 
481  const int32_t Ixy = *(response0 - 1) + *(response0 + 2) + *(response0 + 5)
482  + *(response1 - 1) + *(response1 + 2) + *(response1 + 5)
483  + *(response2 - 1) + *(response2 + 2) + *(response2 + 5);
484 
485  const int32_t determinant = int32_t((Ixx / 8u) * (Iyy / 8u)) - int32_t(sqr((Ixy / 8)));
486  const uint32_t sqrTrace = sqr((Ixx + Iyy) / 8u);
487 
488  ocean_assert(NumericT<int32_t>::isInsideValueRange(int64_t(sqrTrace) * 3ll));
489 
490  return determinant - int32_t((sqrTrace * 3u) / 64u);
491 }
492 
493 inline int32_t HarrisCornerDetector::harrisVote(const int16_t* const responsesXX0, const int16_t* const responsesXX1, const int16_t* const responsesXX2, const int16_t* const responsesYY0, const int16_t* const responsesYY1, const int16_t* const responsesYY2, const int16_t* const responsesXY0, const int16_t* const responsesXY1, const int16_t* const responsesXY2)
494 {
495  ocean_assert(responsesXX0 != nullptr && responsesXX1 != nullptr && responsesXX2 != nullptr);
496  ocean_assert(responsesYY0 != nullptr && responsesYY1 != nullptr && responsesYY2 != nullptr);
497  ocean_assert(responsesXY0 != nullptr && responsesXY1 != nullptr && responsesXY2 != nullptr);
498 
499  ocean_assert(responsesXX0[0] >= 0 && responsesXX0[1] >= 0 && responsesXX0[2] >= 0);
500  ocean_assert(responsesXX1[0] >= 0 && responsesXX1[1] >= 0 && responsesXX1[2] >= 0);
501  ocean_assert(responsesXX2[0] >= 0 && responsesXX2[1] >= 0 && responsesXX2[2] >= 0);
502 
503  ocean_assert(responsesYY0[0] >= 0 && responsesYY0[1] >= 0 && responsesYY0[2] >= 0);
504  ocean_assert(responsesYY1[0] >= 0 && responsesYY1[1] >= 0 && responsesYY1[2] >= 0);
505  ocean_assert(responsesYY2[0] >= 0 && responsesYY2[1] >= 0 && responsesYY2[2] >= 0);
506 
507  const uint32_t Ixx = uint32_t(responsesXX0[0]) + uint32_t(responsesXX0[1]) + uint32_t(responsesXX0[2])
508  + uint32_t(responsesXX1[0]) + uint32_t(responsesXX1[1]) + uint32_t(responsesXX1[2])
509  + uint32_t(responsesXX2[0]) + uint32_t(responsesXX2[1]) + uint32_t(responsesXX2[2]);
510 
511  const uint32_t Iyy = uint32_t(responsesYY0[0]) + uint32_t(responsesYY0[1]) + uint32_t(responsesYY0[2])
512  + uint32_t(responsesYY1[0]) + uint32_t(responsesYY1[1]) + uint32_t(responsesYY1[2])
513  + uint32_t(responsesYY2[0]) + uint32_t(responsesYY2[1]) + uint32_t(responsesYY2[2]);
514 
515  const int32_t Ixy = int32_t(responsesXY0[0]) + int32_t(responsesXY0[1]) + int32_t(responsesXY0[2])
516  + int32_t(responsesXY1[0]) + int32_t(responsesXY1[1]) + int32_t(responsesXY1[2])
517  + int32_t(responsesXY2[0]) + int32_t(responsesXY2[1]) + int32_t(responsesXY2[2]);
518 
519  const int32_t determinant = int32_t((Ixx / 8u) * (Iyy / 8u)) - int32_t(sqr((Ixy / 8)));
520  const uint32_t sqrTrace = sqr((Ixx + Iyy) / 8u);
521 
522  ocean_assert(NumericT<int32_t>::isInsideValueRange(int64_t(sqrTrace) * 3ll));
523 
524  return determinant - int32_t((sqrTrace * 3u) / 64u);
525 }
526 
527 constexpr int32_t HarrisCornerDetector::determineInternalThreshold(const unsigned int threshold)
528 {
529  ocean_assert(threshold <= 512u);
530 
531  return int32_t(sqr(threshold * threshold / 8u));
532 }
533 
534 template <>
535 inline float HarrisCornerDetector::determineThreshold(const float vote)
536 {
537  return NumericF::pow(NumericF::abs(float(vote)) * 64.0f, 0.25f);
538 }
539 
540 template <>
541 inline double HarrisCornerDetector::determineThreshold(const double vote)
542 {
543  return NumericD::pow(NumericD::abs(double(vote)) * 64.0, 0.25);
544 }
545 
546 template <typename T>
548 {
549  static_assert(!std::is_floating_point<T>::value, "Invalid data type!");
550 
551  const double result = determineThreshold<double>(double(vote));
552  ocean_assert(result <= double(NumericT<T>::maxValue()));
553 
554  return T(result);
555 }
556 
557 constexpr uint32_t HarrisCornerDetector::sqr(const int32_t value)
558 {
559  ocean_assert(value >= -65535 && value <= 65535);
560 
561  return uint32_t(value * value);
562 }
563 
564 constexpr uint32_t HarrisCornerDetector::sqr(const uint32_t value)
565 {
566  ocean_assert(value <= 65535u);
567 
568  return value * value;
569 }
570 
571 constexpr uint64_t HarrisCornerDetector::sqr(const int64_t value)
572 {
573  ocean_assert(value >= -4294967295ll && value <= 4294967295ll);
574 
575  return value * value;
576 }
577 
578 }
579 
580 }
581 
582 }
583 
584 #endif // META_OCEAN_CV_DETECTOR_HARRIS_CORNER_DETECTOR_H
This class implements a helper object allowing to determine the precise 2D position of Harris corners...
Definition: HarrisCornerDetector.h:75
bool precisePosition(const unsigned int x, const unsigned int y, const int32_t strength, Scalar &preciseX, Scalar &preciseY, int32_t &preciseStrength)
Determines the precise position of a given (rough) Harris corner.
PreciseCornerPosition(const uint8_t *frame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements)
Creates a new object.
Definition: HarrisCornerDetector.h:387
const unsigned int framePaddingElements_
The optional number of padding elements at the end of each row, with range [0, infinity)
Definition: HarrisCornerDetector.h:111
const unsigned int frameWidth_
The frame width in pixel, with range [7, infinity)
Definition: HarrisCornerDetector.h:105
const uint8_t *const frameData_
The frame in which the Harris corners are detected.
Definition: HarrisCornerDetector.h:102
const unsigned int frameHeight_
The frame height in pixel, with range [7, infinity)
Definition: HarrisCornerDetector.h:108
This class implements the Harris corner detector.
Definition: HarrisCornerDetector.h:39
static constexpr uint32_t sqr(const int32_t value)
Returns the square value.
Definition: HarrisCornerDetector.h:557
static void harrisVotesSubPixelSubset(const uint8_t *yFrame, const unsigned int width, const unsigned int yFramePaddingElements, const Vector2 *positions, int32_t *votes, const unsigned int firstPosition, const unsigned int numberPositions)
Creates the Harris corner votes for a subset of specified sub-pixel positions from an 8 bit grayscale...
static void harrisVotes(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const PixelPosition *positions, const size_t numberPositions, int32_t *votes, Worker *worker=nullptr)
Calculates the Harris corner votes for several given positions in a frame only.
static void harrisVotesFrameSobelResponse(const int8_t *sobelResponse, const unsigned int width, const unsigned int height, const unsigned int sobelResponsePaddingElements, int32_t *votes, const unsigned int votesPaddingElements, Worker *worker=nullptr, const bool setBorderPixels=false)
Creates the Harris corner votes for the horizontal and vertical sobel responses for an entire frame (...
static std::vector< int32_t > harrisVotesSubPixel(const uint8_t *yFrame, const unsigned int width, const Vectors2 &positions, const unsigned int yFramePaddingElements, Worker *worker=nullptr)
Calculates the Harris corner votes for specified sub-pixel positions from an 8 bit grayscale frame.
PositionPrecision
Definition of a boolean enum for precision properties (to improve code readability).
Definition: HarrisCornerDetector.h:57
static void detectCornerCandidatesSubset(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const int32_t internalThreshold, NonMaximumSuppressionVote *nonMaximumSuppression, const unsigned int firstColumn, const unsigned int numberColumns, const unsigned int firstRow, const unsigned int numberRows)
Detects Harris corners inside a sub-frame of a given frame.
static void determine4VotesNEON(const int32x4_t &Ixx_s_32x4, const int32x4_t &Iyy_s_32x4, const int32x4_t &Ixy_s_32x4, int32_t *votes)
Calculates four Harris Corner votes for 3x3 regions from sums of (squared) sobel responses.
static void harrisVotesByResponseSubset(const int8_t *response, const unsigned int width, const unsigned int height, const unsigned int responsePaddingElements, int32_t *votes, const unsigned int votesPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Determines Harris votes inside a sub-frame of a given buffer holding the filter responses.
static T determineThreshold(const T vote)
Determines the (external) threshold corresponding to an (internal) Harris vote.
Definition: HarrisCornerDetector.h:547
NonMaximumSuppression< int32_t > NonMaximumSuppressionVote
Definition of a maximum suppression object holding integer strength parameters.
Definition: HarrisCornerDetector.h:69
static constexpr int32_t determineInternalThreshold(const unsigned int threshold)
Returns the threshold used internally for a given threshold.
Definition: HarrisCornerDetector.h:527
static int32_t harrisVoteSubPixel(const uint8_t *yFrame, const unsigned int width, const Scalar x, const Scalar y, const unsigned int yFramePaddingElements)
Calculates the Harris corner vote for one specific sub-pixel position from an 8 bit grayscale frame.
static bool detectCorners(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int subFrameLeft, const unsigned int subFrameTop, const unsigned int subFrameWidth, const unsigned int subFrameHeight, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners &corners, const bool determineExactPosition=false, Worker *worker=nullptr)
Detects Harris corners inside a sub-frame of a given 8 bit grayscale image.
static bool detectCorners(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const unsigned int threshold, const bool frameIsUndistorted, HarrisCorners &corners, const bool determineExactPosition=false, Worker *worker=nullptr)
Detects Harris corners inside a given 8 bit grayscale image.
Definition: HarrisCornerDetector.h:397
static int32_t harrisVote(const int16_t *const responsesXX0, const int16_t *const responsesXX1, const int16_t *const responsesXX2, const int16_t *const responsesYY0, const int16_t *const responsesYY1, const int16_t *const responsesYY2, const int16_t *const responsesXY0, const int16_t *const responsesXY1, const int16_t *const responsesXY2)
Calculates one Harris Corner vote for a 3x3 region from three buffers storing Sobel responses product...
Definition: HarrisCornerDetector.h:493
FrameDistortion
Definition of a boolean enum for frame un-/distortion properties (to improve code readability).
Definition: HarrisCornerDetector.h:46
static int32_t harrisVotePixel(const uint8_t *yFrame, const unsigned int width, const unsigned int x, const unsigned int y, const unsigned int yFramePaddingElements)
Calculates the Harris corner vote for one specific pixel from an 8 bit grayscale frame.
static void harrisVotesFrame(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, int32_t *votes, const unsigned int votesPaddingElements, Worker *worker=nullptr, const bool setBorderPixels=false)
Creates the Harris corner votes for an entire frame (and therefore for each pixel) without applying a...
static bool convert(const Frame &source, const FrameType::PixelFormat targetPixelFormat, const FrameType::PixelOrigin targetPixelOrigin, Frame &target, const bool forceCopy=true, Worker *worker=nullptr, const Options &options=Options())
Converts a frame with arbitrary dimension, pixel format and pixel origin into a frame with the same d...
@ CP_AVOID_COPY_IF_POSSIBLE
Tries to avoid copying the frame data whenever possible.
Definition: FrameConverter.h:96
This class implements the possibility to find local maximum in a 2D array by applying a non-maximum-s...
Definition: NonMaximumSuppression.h:41
This class implements Ocean's image class.
Definition: Frame.h:1760
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition: Frame.h:4136
bool isValid() const
Returns whether this frame is valid.
Definition: Frame.h:4416
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition: Frame.h:4010
@ FORMAT_Y8
Pixel format for grayscale images with byte order Y and 8 bits per pixel.
Definition: Frame.h:594
unsigned int width() const
Returns the width of the frame format in pixel.
Definition: Frame.h:3111
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition: Frame.h:1018
unsigned int height() const
Returns the height of the frame in pixel.
Definition: Frame.h:3116
This class provides basic numeric functionalities.
Definition: Numeric.h:57
static T pow(const T x, const T y)
Returns x raised to the power of y.
Definition: Numeric.h:1860
static T abs(const T value)
Returns the absolute value of a given value.
Definition: Numeric.h:1220
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition: base/Utilities.h:1029
std::vector< HarrisCorner > HarrisCorners
Definition of a vector holding Harris corners.
Definition: HarrisCorner.h:24
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::vector< Vector2 > Vectors2
Definition of a vector holding Vector2 objects.
Definition: Vector2.h:64
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15