Ocean
Loading...
Searching...
No Matches
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
25namespace Ocean
26{
27
28namespace CV
29{
30
31namespace Detector
32{
33
34/**
35 * This class implements the Harris corner detector.
36 * @ingroup cvdetector
37 */
38class 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
387inline 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
397inline 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
405inline 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
418inline 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
431inline 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
462inline 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
493inline 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
527constexpr 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
534template <>
535inline float HarrisCornerDetector::determineThreshold(const float vote)
536{
537 return NumericF::pow(NumericF::abs(float(vote)) * 64.0f, 0.25f);
538}
539
540template <>
541inline double HarrisCornerDetector::determineThreshold(const double vote)
542{
543 return NumericD::pow(NumericD::abs(double(vote)) * 64.0, 0.25);
544}
545
546template <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
557constexpr 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
564constexpr uint32_t HarrisCornerDetector::sqr(const uint32_t value)
565{
566 ocean_assert(value <= 65535u);
567
568 return value * value;
569}
570
571constexpr 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 (...
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
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.
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:1808
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:4248
bool isValid() const
Returns whether this frame is valid.
Definition Frame.h:4528
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:4122
@ 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:3170
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition Frame.h:1050
unsigned int height() const
Returns the height of the frame in pixel.
Definition Frame.h:3175
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:30
float Scalar
Definition of a scalar type.
Definition Math.h:129
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