Ocean
Loading...
Searching...
No Matches
FinderPatternDetector.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#pragma once
9
14
15#include "ocean/base/Frame.h"
16#include "ocean/base/Memory.h"
17
18#include "ocean/cv/Bresenham.h"
19
21
22#include "ocean/math/Box2.h"
24#include "ocean/math/Vector2.h"
25
26#include <array>
27#include <cstdint>
28
29namespace Ocean
30{
31
32namespace CV
33{
34
35namespace Detector
36{
37
38namespace QRCodes
39{
40
41/**
42 * Definition of a triplet of indices
43 * @ingroup cvdetectorqrcodes
44 */
45using IndexTriplet = std::array<unsigned int, 3>;
46
47/**
48 * Definition of a vector index triplets
49 * @ingroup cvdetectorqrcodes
50 */
51using IndexTriplets = std::vector<IndexTriplet>;
52
53/**
54 * Definition of a class for finder patterns of QR codes (squares in the top-left, top-right and bottom-left corners)
55 * @ingroup cvdetectorqrcodes
56 */
58{
59 public:
60
61 /**
62 * Creates an invalid finder pattern object.
63 */
64 inline FinderPattern();
65
66 /**
67 * Creates a new finder pattern object by a given position and edge length.
68 * @param position The (center) position of the finder pattern within the camera frame
69 * @param length The edge length of the finder pattern in pixels, with range (0, infinity)
70 * @param centerIntensity The intensity that has been measured in the center of the finder pattern, range: [0, 255]
71 * @param grayThreshold Threshold that was used during the detection, range [0, 255]
72 * @param symmetryScore Symmetry score of this finder pattern, range: [0, infinity) (lower value = higher symmetry)
73 */
74 inline FinderPattern(const Vector2& position, const Scalar length, const unsigned int centerIntensity, const unsigned int grayThreshold, const Scalar symmetryScore);
75
76 /**
77 * Creates a new finder pattern object by a given position and edge length.
78 * @param position The (center) position of the finder pattern within the camera frame
79 * @param length The edge length of the finder pattern in pixels, with range (0, infinity)
80 * @param centerIntensity The intensity that has been measured in the center of the finder pattern, range: [0, 255]
81 * @param grayThreshold Threshold that was used during the detection, range [0, 255]
82 * @param symmetryScore Symmetry score of this finder pattern, range: [0, infinity) (lower value = higher symmetry)
83 * @param corners The locations of the four corners of this finder pattern, must be valid and have 4 elements
84 * @param orientation Dominant orientation of the finder pattern
85 * @param moduleSize The size of modules (=bits) in pixels
86 */
87 inline FinderPattern(const Vector2& position, const Scalar length, const unsigned int centerIntensity, const unsigned int grayThreshold, const Scalar symmetryScore, const Vector2* corners, const Vector2& orientation, const Scalar moduleSize);
88
89 /**
90 * Returns the (center) position of the finder pattern.
91 * @return The finder pattern's position within the camera frame
92 */
93 inline const Vector2& position() const;
94
95 /**
96 * Returns the radius of the finder pattern.
97 * @return The finder pattern's radius, with range (0, infinity), 0 for an invalid object
98 */
99 inline Scalar length() const;
100
101 /**
102 * Returns the intensity value that was measured in the center of the finder pattern
103 * @return The intensity value, range: [0, 255]
104 */
105 inline unsigned int centerIntensity() const;
106
107 /**
108 * Returns the threshold that was used for the detection of this finder pattern
109 * @return The threshold value, range: [0, 255]
110 */
111 inline unsigned int grayThreshold() const;
112
113 /**
114 * Returns the width of a module (= bit) in pixels
115 * @return The module width
116 */
117 inline Scalar moduleSize() const;
118
119 /**
120 * Returns the symmetry score that was determined when this finder pattern was detected
121 * @return The symmetry score of this finder pattern
122 */
123 inline Scalar symmetryScore() const;
124
125 /**
126 * Returns true if the four corners of this finder pattern are known, otherwise false
127 * @return True, if the four corners are known, otherwise false
128 */
129 inline bool cornersKnown() const;
130
131 /**
132 * Returns a pointer to the four corners of this finder pattern.
133 * @return A constant pointer to the four corners of this finder pattern. These values are undefined if `cornersKnown()` returns false.
134 */
135 inline const Vector2* corners() const;
136
137 /**
138 * Returns the dominant orientation of this finder pattern
139 * @return The vector defining the orientation (will be (1, 0) by default, i.e. if it's not set)
140 */
141 inline const Vector2& orientation() const;
142
143 /**
144 * Returns whether this finder pattern is of normal reflectance
145 * @return True if so, otherwise false
146 */
147 inline bool isNormalReflectance() const;
148
149 /**
150 * Comparator to sort finder patterns based on their location in an image
151 * Pattern `a` comes before pattern `b` if (pseudo-code) `a.y * imageWidth + a.x < b.y * imageWidth + b.x`
152 * @param first The first finder pattern to compare
153 * @param second The second finder pattern to compare
154 * @return True if the first pattern comes before the second pattern, otherwise false
155 */
156 static inline bool comesBefore(const FinderPattern& first, const FinderPattern& second);
157
158 protected:
159
160 /// The (center) position of the finder pattern within the camera frame.
162
163 /// The edge length of the finder pattern in pixels, range: (0, infinity).
165
166 /// The intensity value that has been measured in the center of the finder pattern
167 unsigned int centerIntensity_;
168
169 /// The threshold that was used during the detection of this finder pattern.
170 unsigned int grayThreshold_;
171
172 /// The symmetry score of this finder pattern, range: [0, infinity) (lower score = higher symmetry)
174
175 /// True if the four corners of this finder pattern are known, otherwise false
176 bool cornersKnown_ = false;
177
178 /// The four corners of this finder pattern; points are stored in counter-clockwise order but no guarantee on which corner is the first; if `cornersDetected_` is false these values will be undefined
180
181 /// Dominant orientation of this finder pattern
183
184 /// Module width (bit width) in pixels
186};
187
188/**
189 * Definition of a vector holding finder pattern.
190 * @ingroup cvdetectorqrcodes
191 */
192using FinderPatterns = std::vector<FinderPattern>;
193
194/**
195 * Definition of a 3-tuple of finder patterns
196 * @ingroup cvdetectorqrcodes
197 */
198using FinderPatternTriplet = std::array<FinderPattern, 3>;
199
200/**
201 * This class implements a detector for finder patterns which are part of QR Codes.
202 * @ingroup cvdetectorqrcodes
203 */
204class OCEAN_CV_DETECTOR_QRCODES_EXPORT FinderPatternDetector
205{
206 protected:
207
208 /// The intensity threshold between two successive pixels to count as a transition from dark to light (or vice versa).
209 static constexpr int deltaThreshold = 30;
210
211 /**
212 * This class implements a simple history for previous pixel transitions (a sliding window of pixel transitions).
213 */
215 {
216 public:
217
218 /**
219 * Creates a new history object.
220 */
221 inline TransitionHistory();
222
223 /**
224 * Returns the history with window size N.
225 * @return The sum of the most recent delta
226 */
227 inline int history1();
228
229 /**
230 * Returns the history with window size N.
231 * @return The sum of the most recent delta
232 */
233 inline int history2();
234
235 /**
236 * Returns the history with window size N.
237 * @return The sum of the most recent delta
238 */
239 inline int history3();
240
241 /**
242 * Returns the history with window size N.
243 * @return The sum of the most recent delta
244 */
245 inline int history4();
246
247 /**
248 * Returns the history with window size N.
249 * @return The sum of the most recent delta
250 */
251 inline int history5();
252
253 /**
254 * Adds a new delta object as most recent history.
255 * Existing history objects will be moved by one pixel.
256 * @param newDelta The new delta object to be added
257 */
258 inline void push(const int newDelta);
259
260 /**
261 * Resets the history object.
262 */
263 inline void reset();
264
265 protected:
266
267 /// The most recent deltas.
268 int deltas_[5] = { 0, 0, 0, 0, 0 };
269 };
270
271 public:
272
273 /**
274 * Detects finder patterns of a QR code in a 8 bit grayscale image.
275 * @param yFrame The 8 bit grayscale frame in which the finder patterns will be detected, must be valid
276 * @param width The width of the given grayscale frame in pixel, with range [15, infinity)
277 * @param height The height of the given grayscale frame in pixel, with range [15, infinity)
278 * @param minimumDistance The minimum distance in pixels that is enforced between any pair of finder patterns, range: [0, infinity), default: 10
279 * @param paddingElements Optional number of padding elements at the end of each image row, in elements, with range [0, infinity), default: 0
280 * @param worker Optional worker to distribute the computation
281 * @param detectInvertedReflectance True to additionally detect bright finder patterns on a dark background
282 * @return The detected finder patterns
283 */
284 static FinderPatterns detectFinderPatterns(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int minimumDistance = 10u, const unsigned int paddingElements = 0u, Worker* worker = nullptr, const bool detectInvertedReflectance = false);
285
286 /**
287 * Extract 3-tuples of finder patterns that form good (plausible) candidates for QR code symbols
288 * @param finderPatterns The list finder patterns in which 3-tuples forming potential QR code symbols are sought, must be valid, minimum size: 3
289 * @param distanceScaleTolerance Scale factor that define how much corners of one finder pattern may deviate from the parallel lines of another finder pattern, range: [0, infinity), default: 0.05
290 * @param moduleSizeScaleTolerance Defines the maximum difference scale of the module size between pairs of finder patterns in order to be considered a match, range: [0, 1], default: 0.35
291 * @param angleTolerance Defines the maximum difference of the dominant orientation of pairs of finder patterns in order to be considered a match, measured in radian, range: [0, PI/4), default: deg2rad(9)
292 * @return A list of 3-tuples of finder patterns, will be empty on failure (or if nothing was found)
293 */
294 static IndexTriplets extractIndexTriplets(const FinderPatterns& finderPatterns, const Scalar distanceScaleTolerance = Scalar(0.175), const Scalar moduleSizeScaleTolerance = Scalar(0.35), const Scalar angleTolerance = Numeric::deg2rad(Scalar(9)));
295
296 protected:
297
298 /**
299 * Detects finder patterns of QR codes in subregion of a given 8 bit grayscale image.
300 * @param yFrame The 8 bit grayscale frame in which the finder patterns will be detected, must be valid
301 * @param width The width of the given grayscale frame in pixel, with range [15, infinity)
302 * @param height The height of the given grayscale frame in pixel, with range [15, infinity)
303 * @param finderPatterns The resulting finderPatterns, will be added to the end of the vector
304 * @param multiThreadLock Lock object in case this function is executed in multiple threads concurrently, otherwise nullptr
305 * @param paddingElements Optional number of padding elements at the end of each image row, in elements, with range [0, infinity)
306 * @param firstRow The first row to be handled, with range [7, height - 7)
307 * @param numberRows The number of rows to be handled, with range [1, height - 7 - firstRow]
308 * @param detectInvertedReflectance True to additionally detect bright finder patterns on a dark background
309 */
310 static void detectFinderPatternsSubset(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, FinderPatterns* finderPatterns, Lock* multiThreadLock, const unsigned int paddingElements, const unsigned int firstRow, const unsigned int numberRows, const bool detectInvertedReflectance);
311
312 /**
313 * Detects finder patterns of QR codes in a single row of an grayscale image.
314 * @param yFrame The 8 bit grayscale frame in which the finder patterns will be detected, must be valid
315 * @param width The width of the given grayscale frame in pixel, with range [15, infinity)
316 * @param height The height of the given grayscale frame in pixel, with range [15, infinity)
317 * @param y The index of the row in which the finder patterns will be detected, with range [7, height - 8]
318 * @param finderPatterns The resulting detected finder patterns, will be added to the end of the vector
319 * @param paddingElements Optional number of padding elements at the end of each image row, in elements, with range [0, infinity)
320 * @param isNormalReflectance True to detect dark finder patterns on a bright background, false for bright finder patterns on a dark background
321 */
322 static void detectFinderPatternInRow(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int y, FinderPatterns& finderPatterns, const unsigned int paddingElements, const bool isNormalReflectance);
323
324 /**
325 * Finds the next transition in a row.
326 * @param yRow The current row, must be valid
327 * @param width The row width in pixels, range: [1, infinity)
328 * @param x The search position, will be advanced to the transition or to width
329 * @param transitionDetector The transition detector to use, must be valid
330 * @return True if a transition was found, otherwise false
331 */
332 static bool findNextTransitionInRow(const uint8_t* const yRow, const unsigned int width, unsigned int& x, bool (*transitionDetector)(const uint8_t*, TransitionHistory&));
333
334 /**
335 * Validates and adds a finder pattern candidate from a 1D row match.
336 * @param yFrame The 8 bit grayscale frame in which the finder patterns will be detected, must be valid
337 * @param yRow The row containing the 1D match, must be valid
338 * @param width The width of the given grayscale frame in pixel, with range [15, infinity)
339 * @param height The height of the given grayscale frame in pixel, with range [15, infinity)
340 * @param y The index of the row in which the finder patterns will be detected, with range [7, height - 8]
341 * @param paddingElements Optional number of padding elements at the end of each image row, in elements, with range [0, infinity)
342 * @param segment1StartForeground The start of the first foreground segment
343 * @param segment3StartForeground The start of the center foreground segment
344 * @param segment4StartBackground The start of the second background segment
345 * @param segment1Size The size of the first foreground segment
346 * @param segment2Size The size of the first background segment
347 * @param segment3Size The size of the center foreground segment
348 * @param segment4Size The size of the second background segment
349 * @param segment5Size The size of the third foreground segment
350 * @param foregroundSquareSegmentMin Minimum diameter of the outer foreground square in pixels
351 * @param foregroundSquareSegmentMax Maximum diameter of the outer foreground square in pixels
352 * @param backgroundSquareSegmentMin Minimum diameter of the inner background square in pixels
353 * @param backgroundSquareSegmentMax Maximum diameter of the inner background square in pixels
354 * @param centerSegmentMin Minimum diameter of the center foreground square in pixels
355 * @param centerSegmentMax Maximum diameter of the center foreground square in pixels
356 * @param isNormalReflectance True to detect dark foreground on bright background, false for bright foreground on dark background
357 * @param finderPatterns The resulting detected finder patterns, will be added to the end of the vector
358 */
359 static void addFinderPatternCandidateInRow(const uint8_t* const yFrame, const uint8_t* const yRow, const unsigned int width, const unsigned int height, const unsigned int y, const unsigned int paddingElements, const unsigned int segment1StartForeground, const unsigned int segment3StartForeground, const unsigned int segment4StartBackground, const unsigned int segment1Size, const unsigned int segment2Size, const unsigned int segment3Size, const unsigned int segment4Size, const unsigned int segment5Size, const unsigned int foregroundSquareSegmentMin, const unsigned int foregroundSquareSegmentMax, const unsigned int backgroundSquareSegmentMin, const unsigned int backgroundSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, FinderPatterns& finderPatterns);
360
361 /**
362 * Estimates the locations of the corners of finder pattern and computes the dominant orientation of the finder pattern from those corners
363 * @param xCenter The pixel-accurate x-coordinate of the candidate location
364 * @param yCenter The pixel-accurate y-coordinate of the candidate location
365 * @param edgePoints The edge points which will be used to determine the corners of the finder pattern, must be valid and have `edgePointsSize` elements
366 * @param edgePointsSize Number of edge points that are available, range: [2, infinity) must be even
367 * @param location The resulting center location of the finder pattern that is determined from the four corners that will be determined by this function
368 * @param corners The resulting four corners of the finder pattern that will be determined, must be valid, in counter-clockwise order, and must have size of at least 4 elements
369 * @param orientation The resulting main orientation of the finder pattern that will be determined
370 * @param moduleSize The resulting size of the modules in this finder pattern candidate
371 * @param edgePointDistanceTolerance The factor that defines the maximum deviation from the distance between the center and the edge point closest to the center, range: [0, infinity)
372 * @param maxEdgeLineDistance The maximum distance (in pixel) that new edge points may have in order to be accepted as "on the edge line", range: [0, infinity)
373 * @return True on success, otherwise false
374 */
375 static bool estimateFinderPatternCorners(const unsigned int xCenter, const unsigned int yCenter, const Vector2* edgePoints, const unsigned int edgePointsSize, Vector2& location, Vector2* corners, Vector2& orientation, Scalar& moduleSize, const Scalar edgePointDistanceTolerance = 2.25, const Scalar maxEdgeLineDistance = 1.5);
376
377 /**
378 * Refine the location and corners of a finder pattern
379 * @param yFrame Pointer to the input grayscale image, must be valid
380 * @param width The width of the input grayscale image, range: [1, infinity)
381 * @param height The height of the input grayscale image, range:[1, infinity)
382 * @param finderPattern The resulting finder pattern of which its position and corners will be refined
383 * @param yFramePaddingElements The number of padding elements of the input grayscale image, range: [0, infinity)
384 * @return True if the refinement was successful, otherwise false
385 * @sa estimateFinderPatternCorners()
386 */
387 static bool refineFinderPatternLocation(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, FinderPattern& finderPattern, const unsigned int yFramePaddingElements = 0u);
388
389 /**
390 * Finds a foreground/background edge transition used to refine finder-pattern edges.
391 */
392 static bool findRefinementEdgeTransition(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const FinderPattern& finderPattern, const Vector2& point, const Vector2& perpendicularOut, const unsigned int maxPerpendicularSearchDistance, VectorT2<unsigned int>& pixelLocationIn, VectorT2<unsigned int>& pixelLocationOut);
393
394 /**
395 * Performs a check around a given candidate location looking for a correct configuration of light and dark pixels (testing 8 angles each yielding 2 edge points)
396 * @param yFrame The 8 bit grayscale frame in which the finder pattern candidate will be tested, must be valid
397 * @param width The width of the given grayscale frame in pixels, range: [15, infinity)
398 * @param height The height of the given grayscale frame in pixels, range: [15, infinity)
399 * @param paddingElements The number of padding elements in the given image with range [0, infinity)
400 * @param xCenter The horizontal location within the frame at which the existence of the finder pattern will be checked, in pixels, with range [0, width - 1]
401 * @param yCenter The vertical location within the frame at which the existence of the finder pattern will be checked, in pixels, with range [0, height - 1]
402 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
403 * @param blackSquareSegmentMin Minimum diameter of the outer foreground square in pixels, range: [1, infinity)
404 * @param blackSquareSegmentMax Maximum diameter of the outer foreground square in pixels, range: [blackSquareSegmentMin, infinity)
405 * @param whiteSquareSegmentMin Minimum diameter of the inner background square in pixels, range: [1, infinity)
406 * @param whiteSquareSegmentMax Maximum diameter of the inner background square in pixels, range: [whiteSquareSegmentMin, infinity)
407 * @param centerSegmentMin Minimum diameter of the center foreground square in pixels, range: [1, infinity)
408 * @param centerSegmentMax Maximum diameter of the center foreground square in pixels, range: [centerSegmentMin, infinity)
409 * @param isNormalReflectance True for dark foreground on bright background, false for bright foreground on dark background
410 * @param symmetryScore The resulting symmetry score that is computed for the current candidate location `(xCenter, yCenter)`; this score is based on distances so the lower the score, the better. Range: [0, infinity)
411 * @param edgePoints If specified, will hold the resulting points detected during the directional checks on the outside border of the finder pattern candidate. Must be valid, expected size: `2 * angles`
412 * @return True if all edge points of the finder pattern are found in all scanline directions, otherwise false
413 */
414 static bool checkFinderPatternInNeighborhood(const uint8_t* const yFrame, const unsigned width, const unsigned height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int blackSquareSegmentMin, const unsigned int blackSquareSegmentMax, const unsigned int whiteSquareSegmentMin, const unsigned int whiteSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, Scalar& symmetryScore, Vector2* edgePoints);
415
416 /**
417 * Performs a check for a given candidate location in a specified direction (yielding 2 edge points)
418 * @param yFrame The 8 bit grayscale frame in which the finder pattern candidate will be tested, must be valid
419 * @param width The width of the given grayscale frame in pixels, range: [15, infinity)
420 * @param height The height of the given grayscale frame in pixels, range: [15, infinity)
421 * @param paddingElements The number of padding elements in the given image with range [0, infinity)
422 * @param xCenter The horizontal location within the frame at which the existence of the finder pattern will be checked, in pixels, with range [0, width - 1]
423 * @param yCenter The vertical location within the frame at which the existence of the finder pattern will be checked, in pixels, with range [0, height - 1]
424 * @param angle The angle in Radian defining the directions in which edge points will be searched, range: [0, pi)
425 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
426 * @param blackSquareSegmentMin Minimum diameter of the outer foreground square in pixels, range: [1, infinity)
427 * @param blackSquareSegmentMax Maximum diameter of the outer foreground square in pixels, range: [blackSquareSegmentMin, infinity)
428 * @param whiteSquareSegmentMin Minimum diameter of the inner background square in pixels, range: [1, infinity)
429 * @param whiteSquareSegmentMax Maximum diameter of the inner background square in pixels, range: [whiteSquareSegmentMin, infinity)
430 * @param centerSegmentMin Minimum diameter of the center foreground square in pixels, range: [1, infinity)
431 * @param centerSegmentMax Maximum diameter of the center foreground square in pixels, range: [centerSegmentMin, infinity)
432 * @param isNormalReflectance True for dark foreground on bright background, false for bright foreground on dark background
433 * @param topBorder The resulting location of the last pixel on the current finder pattern in the specified direction of the scanline
434 * @param bottomBorder The resulting location of the last pixel on the current finder pattern in the opposite direction (`angle + pi`) of the specified direction of the scanline
435 * @return True if the two edge points of the finder pattern are found in the specified scanline direction, otherwise false
436 */
437 static bool checkFinderPatternDirectional(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const Scalar angle, const unsigned int threshold, const unsigned int blackSquareSegmentMin, const unsigned int blackSquareSegmentMax, const unsigned int whiteSquareSegmentMin, const unsigned int whiteSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, Vector2& topBorder, Vector2& bottomBorder);
438
439 /**
440 * Checks the center foreground segment in both scanline directions.
441 */
442 static bool checkCenterSegmentDirectional(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, TransitionDetector::FindNextPixelFunc findNextBackgroundPixel, Bresenham& bresenhamTop, Bresenham& bresenhamBottom, unsigned int& topColumns, unsigned int& topRows, unsigned int& bottomColumns, unsigned int& bottomRows, VectorT2<unsigned int>& topIn, VectorT2<unsigned int>& topOut, VectorT2<unsigned int>& bottomIn, VectorT2<unsigned int>& bottomOut);
443
444 /**
445 * Checks a non-center finder-pattern segment in both scanline directions.
446 */
447 static bool checkSegmentDirectional(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int threshold, const unsigned int segmentMin, const unsigned int segmentMax, TransitionDetector::FindNextPixelFunc findNextPixel, Bresenham& bresenhamTop, Bresenham& bresenhamBottom, unsigned int& topColumns, unsigned int& topRows, unsigned int& bottomColumns, unsigned int& bottomRows, VectorT2<unsigned int>& topIn, VectorT2<unsigned int>& topOut, VectorT2<unsigned int>& bottomIn, VectorT2<unsigned int>& bottomOut);
448
449 /**
450 * Checks whether the given pixel is a transition-to-black pixel (whether the direct left neighbor is a bright pixel).
451 * @param pixel The pixel to be checked, must be valid
452 * @param history The history object containing information about previous pixels
453 * @return True, if so
454 */
455 static inline bool isTransitionToBlack(const uint8_t* pixel, TransitionHistory& history);
456
457 /**
458 * Checks whether the given pixel is a transition-to-white pixel (whether the direct left neighbor is a dark pixel).
459 * @param pixel The pixel to be checked, must be valid
460 * @param history The history object containing information about previous pixels
461 * @return True, if so
462 */
463 static inline bool isTransitionToWhite(const uint8_t* pixel, TransitionHistory& history);
464
465 /**
466 * Determines the gray threshold separating bright pixels form dark pixels.
467 * The threshold is based on already actual pixel values for which the association is known already.<br>
468 * The provided start position is a pointer to any pixel within the image, with horizontal range [1, width - segmentSize1 - segmentSize2 - segmentSize3 - segmentSize4 - segmentSize5 - 2].
469 * In addition to the pixels covered by the five segments, the fist pixel left of the segments and the last pixel right of the segments are also used for estimation of the threshold.
470 * @param yPosition The first pixel within an 8 bit grayscale image for which 5 connected segments are known with foreground, background, foreground, background, and foreground pixels, must be valid
471 * @param segmentSize1 The number of pixels covering foreground pixels, with range [1, width - ...)
472 * @param segmentSize2 The number of pixels covering background pixels, with range [1, width - ...)
473 * @param segmentSize3 The number of pixels covering foreground pixels, with range [1, width - ...)
474 * @param segmentSize4 The number of pixels covering background pixels, with range [1, width - ...)
475 * @param segmentSize5 The number of pixels covering foreground pixels, with range [1, width - segmentSize1 - segmentSize2 - segmentSize3 - segmentSize4 - 2]
476 * @param isNormalReflectance True when foreground pixels are dark, false when foreground pixels are bright
477 * @return The threshold separating bright pixels from dark pixels, with range [0, 255], -1 if no valid threshold could be determined
478 */
479 static inline unsigned int determineThreshold(const uint8_t* yPosition, const unsigned int segmentSize1, const unsigned int segmentSize2, const unsigned int segmentSize3, const unsigned int segmentSize4, const unsigned int segmentSize5, const bool isNormalReflectance);
480
481 /**
482 * Returns true if a pair of finder patterns is in parallel configuration, i.e., if one is above/below/left of/right of the other (and vice versa)
483 * @param finderPatternA The first finder pattern that will be used
484 * @param finderPatternB The second finder pattern that will be used
485 * @param distanceTolerance A scaling factor that defines how much the configuration may deviate from perfect parallelism, range: [0, infinity), default: 0.05
486 * @return True if the two finder patterns are in a parallel configuration, otherwise false
487 */
488 static inline bool isParallel(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar distanceTolerance = Scalar(0.05));
489
490 /**
491 * Returns true if a pair of finder patterns is in a diagonal configuration, i.e. the center of one pattern lies on one of the two diagonal (infinite) lines of the other finder pattern (and vice versa)
492 * @param finderPatternA The first finder pattern that will be used
493 * @param finderPatternB The second finder pattern that will be used
494 * @param angleTolerance Defines the angle that the centers of the finder pattern may deviate from the actual diagonal infinite lines (in radian), range: [0, PI/2), default: deg2rad(9)
495 * @return True if the two finder patterns are in a diagonal configuration, otherwise false
496 */
497 static inline bool isDiagonal(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar angleTolerance = Numeric::deg2rad(9));
498};
499
501 FinderPattern::FinderPattern(Vector2(-1, -1), Scalar(0), 0u, 0u, Numeric::maxValue())
502{
503 // nothing to do here
504}
505
506inline FinderPattern::FinderPattern(const Vector2& position, const Scalar length, const unsigned int centerIntensity, const unsigned int grayThreshold, const Scalar symmetryScore) :
507 position_(position),
508 length_(length),
509 centerIntensity_(centerIntensity),
510 grayThreshold_(grayThreshold),
511 symmetryScore_(symmetryScore),
512 orientation_(1, 0),
513 moduleSize_(length / Scalar(7))
514{
515 ocean_assert(centerIntensity_ <= 255u);
516 ocean_assert(grayThreshold_ <= 255u);
517
518 corners_[0] = Vector2(-1, -1);
519 corners_[1] = Vector2(-1, -1);
520 corners_[2] = Vector2(-1, -1);
521 corners_[3] = Vector2(-1, -1);
522}
523
524inline FinderPattern::FinderPattern(const Vector2& position, const Scalar length, const unsigned int centerIntensity, const unsigned int grayThreshold, const Scalar symmetryScore, const Vector2* corners, const Vector2& orientation, const Scalar moduleSize) :
525 position_(position),
526 length_(length),
527 centerIntensity_(centerIntensity),
528 grayThreshold_(grayThreshold),
529 symmetryScore_(symmetryScore),
530 cornersKnown_(true),
531 orientation_(orientation),
532 moduleSize_(moduleSize)
533{
534 ocean_assert(centerIntensity_ <= 255u);
535 ocean_assert(grayThreshold_ <= 255u);
536
537 ocean_assert(corners != nullptr);
538
539 // Expect a counter-clockwise order for the corners
540
541 ocean_assert((corners[1] - corners[0]).cross(corners[3] - corners[0]) <= 0);
542 ocean_assert((corners[2] - corners[1]).cross(corners[0] - corners[1]) <= 0);
543 ocean_assert((corners[3] - corners[2]).cross(corners[1] - corners[2]) <= 0);
544 ocean_assert((corners[0] - corners[3]).cross(corners[2] - corners[3]) <= 0);
545
546 corners_[0] = corners[0];
547 corners_[1] = corners[1];
548 corners_[2] = corners[2];
549 corners_[3] = corners[3];
550}
551
552inline const Vector2& FinderPattern::position() const
553{
554 return position_;
555}
556
558{
559 return length_;
560}
561
562inline unsigned int FinderPattern::centerIntensity() const
563{
564 return centerIntensity_;
565}
566
567inline unsigned int FinderPattern::grayThreshold() const
568{
569 return grayThreshold_;
570}
571
573{
574 return moduleSize_;
575}
576
578{
579 return symmetryScore_;
580}
581
583{
584 return cornersKnown_;
585}
586
587inline const Vector2* FinderPattern::corners() const
588{
589 // Expect a counter-clockwise order for the corners, if the corners are known
590
591 ocean_assert(cornersKnown() == false || (corners_[1] - corners_[0]).cross(corners_[3] - corners_[0]) <= 0);
592 ocean_assert(cornersKnown() == false || (corners_[2] - corners_[1]).cross(corners_[0] - corners_[1]) <= 0);
593 ocean_assert(cornersKnown() == false || (corners_[3] - corners_[2]).cross(corners_[1] - corners_[2]) <= 0);
594 ocean_assert(cornersKnown() == false || (corners_[0] - corners_[3]).cross(corners_[2] - corners_[3]) <= 0);
595
596 return corners_;
597}
598
600{
601 ocean_assert(Numeric::isEqualEps(orientation_.length() - Scalar(1)));
602 return orientation_;
603}
604
609
610inline bool FinderPattern::comesBefore(const FinderPattern& first, const FinderPattern& second)
611{
612 return first.position().y() > second.position().y() || (first.position().y() == second.position().y() && first.position().x() > second.position().x());
613};
614
616 : deltas_{ 0, 0, 0, 0, 0 }
617{
618 // Nothing else to do.
619}
620
622{
623 return deltas_[0];
624}
625
627{
628 return deltas_[0] + deltas_[1];
629}
630
632{
633 return deltas_[0] + deltas_[1] + deltas_[2];
634}
635
637{
638 return deltas_[0] + deltas_[1] + deltas_[2] + deltas_[3];
639}
640
642{
643 return deltas_[0] + deltas_[1] + deltas_[2] + deltas_[3] + deltas_[4];
644}
645
647{
648 deltas_[4] = deltas_[3];
649 deltas_[3] = deltas_[2];
650 deltas_[2] = deltas_[1];
651 deltas_[1] = deltas_[0];
652 deltas_[0] = newDelta;
653}
654
656{
657 deltas_[0] = 0;
658 deltas_[1] = 0;
659 deltas_[2] = 0;
660 deltas_[3] = 0;
661 deltas_[4] = 0;
662}
663
664inline bool FinderPatternDetector::isTransitionToBlack(const uint8_t* pixel, TransitionHistory& history)
665{
666 const int currentDelta = int(*(pixel + 0) - *(pixel - 1));
667
668 bool result = false;
669
670 if (currentDelta < -deltaThreshold)
671 {
672 result = true;
673 }
674 else if ((currentDelta + history.history1() < -deltaThreshold)
675 || (currentDelta + history.history2() < -(deltaThreshold * 5 / 4))
676 || (currentDelta + history.history3() < -(deltaThreshold * 6 / 4))
677 || (currentDelta + history.history4() < -(deltaThreshold * 7 / 4))
678 || (currentDelta + history.history5() < -(deltaThreshold * 8 / 4)))
679 {
680 result = true;
681 }
682
683 history.push(currentDelta);
684
685 return result;
686}
687
688inline bool FinderPatternDetector::isTransitionToWhite(const uint8_t* pixel, TransitionHistory& history)
689{
690 const int currentDelta = int(*(pixel + 0) - *(pixel - 1));
691
692 bool result = false;
693
694 if (currentDelta > deltaThreshold)
695 {
696 result = true;
697 }
698 else if ((currentDelta + history.history1() > deltaThreshold)
699 || (currentDelta + history.history2() > (deltaThreshold * 5 / 4))
700 || (currentDelta + history.history3() > (deltaThreshold * 6 / 4))
701 || (currentDelta + history.history4() > (deltaThreshold * 7 / 4))
702 || (currentDelta + history.history5() > (deltaThreshold * 8 / 4)))
703 {
704 result = true;
705 }
706
707 history.push(currentDelta);
708
709 return result;
710}
711
712inline unsigned int FinderPatternDetector::determineThreshold(const uint8_t* yPosition, const unsigned int segmentSize1, const unsigned int segmentSize2, const unsigned int segmentSize3, const unsigned int segmentSize4, const unsigned int segmentSize5, const bool isNormalReflectance)
713{
714 unsigned int sumForeground = 0u;
715 unsigned int sumBackground = 0u;
716
717 sumBackground += *(yPosition - 1);
718
719 for (unsigned int n = 0u; n < segmentSize1; ++n)
720 {
721 sumForeground += *yPosition++;
722 }
723
724 for (unsigned int n = 0u; n < segmentSize2; ++n)
725 {
726 sumBackground += *yPosition++;
727 }
728
729 for (unsigned int n = 0u; n < segmentSize3; ++n)
730 {
731 sumForeground += *yPosition++;
732 }
733
734 for (unsigned int n = 0u; n < segmentSize4; ++n)
735 {
736 sumBackground += *yPosition++;
737 }
738
739 for (unsigned int n = 0u; n < segmentSize5; ++n)
740 {
741 sumForeground += *yPosition++;
742 }
743
744 sumBackground += *yPosition;
745
746 const unsigned int averageForeground = sumForeground / (segmentSize1 + segmentSize3 + segmentSize5);
747 const unsigned int averageBackground = sumBackground / (segmentSize2 + segmentSize4 + 2u);
748 const unsigned int averageBlack = isNormalReflectance ? averageForeground : averageBackground;
749 const unsigned int averageWhite = isNormalReflectance ? averageBackground : averageForeground;
750
751 if (averageBlack + 2u >= averageWhite)
752 {
753 // the separate between bright and dark pixels is not strong enough
754 return (unsigned int)(-1);
755 }
756
757 return (averageBlack + averageWhite + 1u) / 2u;
758}
759
760inline bool FinderPatternDetector::isParallel(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar distanceTolerance)
761{
762 ocean_assert(finderPatternA.cornersKnown() && finderPatternB.cornersKnown());
763 ocean_assert(finderPatternB.corners() != nullptr && finderPatternA.corners() != nullptr);
764 ocean_assert(distanceTolerance >= 0);
765
766 const Line2 linesB[4] =
767 {
768 Line2(finderPatternB.corners()[1], (finderPatternB.corners()[0] - finderPatternB.corners()[1]).normalized()),
769 Line2(finderPatternB.corners()[2], (finderPatternB.corners()[1] - finderPatternB.corners()[2]).normalized()),
770 Line2(finderPatternB.corners()[3], (finderPatternB.corners()[2] - finderPatternB.corners()[3]).normalized()),
771 Line2(finderPatternB.corners()[0], (finderPatternB.corners()[3] - finderPatternB.corners()[0]).normalized())
772 };
773
774 const Vector2 lineAB = finderPatternB.position() - finderPatternA.position();
775 const Vector2 directionAB = lineAB.normalizedOrZero();
776
777 const Scalar squareDistanceThreshold = (lineAB.length() * distanceTolerance) * (lineAB.length() * distanceTolerance);
778
779 for (unsigned int n = 0u; n < 4u; ++n)
780 {
781 // Reject pairs of lines diverge too much
782 if (Numeric::abs(directionAB * linesB[n].direction()) <= Numeric::cos(Numeric::deg2rad(35)))
783 {
784 continue;
785 }
786
787 // Check if:
788 //
789 // * the corners `i` and `(i+1)` of finder pattern a are both "close enough" to the n-th line of finder pattern b, i.e., is the line between corners `i` and `(i+1)` roughly parallel to the n-th line of finder pattern b.
790 // * the opposite corners in finder pattern a, `(i+2) % 4` and `(i+3) % 4`, and line opposite to the n-th line in finder pattern b (n + 2 % 4) are roughly parallel as well.
791 //
792 // If both is true, finder patterns a and b are considered parallel.
793
794 const Scalar sqrDistanceCornerA0 = linesB[n].sqrDistance(finderPatternA.corners()[0]);
795 const Scalar sqrDistanceCornerA1 = linesB[n].sqrDistance(finderPatternA.corners()[1]);
796
797 if (sqrDistanceCornerA0 < squareDistanceThreshold && sqrDistanceCornerA1 < squareDistanceThreshold)
798 {
799 if (linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[2]) < squareDistanceThreshold && linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[3]) < squareDistanceThreshold) // (n + 2u) & 0b0011u == (n + 2u) % 4
800 {
801 return true;
802 }
803 }
804
805 const Scalar sqrDistanceCornerA2 = linesB[n].sqrDistance(finderPatternA.corners()[2]);
806
807 if (sqrDistanceCornerA1 < squareDistanceThreshold && sqrDistanceCornerA2 < squareDistanceThreshold)
808 {
809 if (linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[3]) < squareDistanceThreshold && linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[0]) < squareDistanceThreshold) // (n + 2u) & 0b0011u == (n + 2u) % 4
810 {
811 return true;
812 }
813 }
814
815 const Scalar sqrDistanceCornerA3 = linesB[n].sqrDistance(finderPatternA.corners()[3]);
816
817 if (sqrDistanceCornerA2 < squareDistanceThreshold && sqrDistanceCornerA3 < squareDistanceThreshold)
818 {
819 if (linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[0]) < squareDistanceThreshold && linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[1]) < squareDistanceThreshold) // (n + 2u) & 0b0011u == (n + 2u) % 4
820 {
821 return true;
822 }
823 }
824
825 if (sqrDistanceCornerA3 < squareDistanceThreshold && sqrDistanceCornerA0 < squareDistanceThreshold)
826 {
827 if (linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[1]) < squareDistanceThreshold && linesB[(n + 2u) & 0b0011u].sqrDistance(finderPatternA.corners()[2]) < squareDistanceThreshold) // (n + 2u) & 0b0011u == (n + 2u) % 4
828 {
829 return true;
830 }
831 }
832 }
833
834 return false;
835}
836
837inline bool FinderPatternDetector::isDiagonal(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar angleTolerance)
838{
839 ocean_assert(finderPatternA.cornersKnown() && finderPatternB.cornersKnown());
840 ocean_assert(finderPatternB.corners() != nullptr && finderPatternA.corners() != nullptr);
841 ocean_assert(angleTolerance >= 0 && angleTolerance < Numeric::deg2rad(90));
842
843 const Vector2 directionAB = (finderPatternB.position() - finderPatternA.position()).normalizedOrZero();
844 const Scalar angleThreshold = Numeric::abs(Numeric::cos(angleTolerance));
845
846 const Vector2 diagonalsA[2] =
847 {
848 (finderPatternA.corners()[2] - finderPatternA.corners()[0]).normalizedOrZero(),
849 (finderPatternA.corners()[3] - finderPatternA.corners()[1]).normalizedOrZero()
850 };
851
852 unsigned int diagonalEdgeA = (unsigned int)(-1);
853 unsigned int diagonalEdgeB = (unsigned int)(-1);
854
855 if (Numeric::abs(diagonalsA[0] * directionAB) >= angleThreshold)
856 {
857 diagonalEdgeA = 0u;
858 }
859 else if (Numeric::abs(diagonalsA[1] * directionAB) >= angleThreshold)
860 {
861 diagonalEdgeA = 1u;
862 }
863
864 if (diagonalEdgeA >= 2u)
865 {
866 return false;
867 }
868
869 const Vector2 diagonalsB[2] =
870 {
871 (finderPatternB.corners()[2] - finderPatternB.corners()[0]).normalizedOrZero(),
872 (finderPatternB.corners()[3] - finderPatternB.corners()[1]).normalizedOrZero()
873 };
874
875 if (Numeric::abs(diagonalsB[0] * directionAB) >= angleThreshold)
876 {
877 diagonalEdgeB = 0u;
878 }
879 else if (Numeric::abs(diagonalsB[1] * directionAB) >= angleThreshold)
880 {
881 diagonalEdgeB = 1u;
882 }
883
884 return diagonalEdgeA < 2u && diagonalEdgeB < 2u;
885}
886
887} // namespace QRCodes
888
889} // namespace Detector
890
891} // namespace CV
892
893} // namespace Ocean
This class implements Bresenham's line algorithms.
Definition Bresenham.h:27
This class implements a simple history for previous pixel transitions (a sliding window of pixel tran...
Definition FinderPatternDetector.h:215
int history2()
Returns the history with window size N.
Definition FinderPatternDetector.h:626
int history3()
Returns the history with window size N.
Definition FinderPatternDetector.h:631
void push(const int newDelta)
Adds a new delta object as most recent history.
Definition FinderPatternDetector.h:646
void reset()
Resets the history object.
Definition FinderPatternDetector.h:655
int history5()
Returns the history with window size N.
Definition FinderPatternDetector.h:641
TransitionHistory()
Creates a new history object.
Definition FinderPatternDetector.h:615
int history4()
Returns the history with window size N.
Definition FinderPatternDetector.h:636
int history1()
Returns the history with window size N.
Definition FinderPatternDetector.h:621
This class implements a detector for finder patterns which are part of QR Codes.
Definition FinderPatternDetector.h:205
static bool isDiagonal(const FinderPattern &finderPatternA, const FinderPattern &finderPatternB, const Scalar angleTolerance=Numeric::deg2rad(9))
Returns true if a pair of finder patterns is in a diagonal configuration, i.e.
Definition FinderPatternDetector.h:837
static constexpr int deltaThreshold
The intensity threshold between two successive pixels to count as a transition from dark to light (or...
Definition FinderPatternDetector.h:209
static bool checkFinderPatternInNeighborhood(const uint8_t *const yFrame, const unsigned width, const unsigned height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int blackSquareSegmentMin, const unsigned int blackSquareSegmentMax, const unsigned int whiteSquareSegmentMin, const unsigned int whiteSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, Scalar &symmetryScore, Vector2 *edgePoints)
Performs a check around a given candidate location looking for a correct configuration of light and d...
static bool findRefinementEdgeTransition(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const FinderPattern &finderPattern, const Vector2 &point, const Vector2 &perpendicularOut, const unsigned int maxPerpendicularSearchDistance, VectorT2< unsigned int > &pixelLocationIn, VectorT2< unsigned int > &pixelLocationOut)
Finds a foreground/background edge transition used to refine finder-pattern edges.
static void addFinderPatternCandidateInRow(const uint8_t *const yFrame, const uint8_t *const yRow, const unsigned int width, const unsigned int height, const unsigned int y, const unsigned int paddingElements, const unsigned int segment1StartForeground, const unsigned int segment3StartForeground, const unsigned int segment4StartBackground, const unsigned int segment1Size, const unsigned int segment2Size, const unsigned int segment3Size, const unsigned int segment4Size, const unsigned int segment5Size, const unsigned int foregroundSquareSegmentMin, const unsigned int foregroundSquareSegmentMax, const unsigned int backgroundSquareSegmentMin, const unsigned int backgroundSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, FinderPatterns &finderPatterns)
Validates and adds a finder pattern candidate from a 1D row match.
static bool refineFinderPatternLocation(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, FinderPattern &finderPattern, const unsigned int yFramePaddingElements=0u)
Refine the location and corners of a finder pattern.
static bool checkSegmentDirectional(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int threshold, const unsigned int segmentMin, const unsigned int segmentMax, TransitionDetector::FindNextPixelFunc findNextPixel, Bresenham &bresenhamTop, Bresenham &bresenhamBottom, unsigned int &topColumns, unsigned int &topRows, unsigned int &bottomColumns, unsigned int &bottomRows, VectorT2< unsigned int > &topIn, VectorT2< unsigned int > &topOut, VectorT2< unsigned int > &bottomIn, VectorT2< unsigned int > &bottomOut)
Checks a non-center finder-pattern segment in both scanline directions.
static IndexTriplets extractIndexTriplets(const FinderPatterns &finderPatterns, const Scalar distanceScaleTolerance=Scalar(0.175), const Scalar moduleSizeScaleTolerance=Scalar(0.35), const Scalar angleTolerance=Numeric::deg2rad(Scalar(9)))
Extract 3-tuples of finder patterns that form good (plausible) candidates for QR code symbols.
static bool isTransitionToBlack(const uint8_t *pixel, TransitionHistory &history)
Checks whether the given pixel is a transition-to-black pixel (whether the direct left neighbor is a ...
Definition FinderPatternDetector.h:664
static void detectFinderPatternsSubset(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, FinderPatterns *finderPatterns, Lock *multiThreadLock, const unsigned int paddingElements, const unsigned int firstRow, const unsigned int numberRows, const bool detectInvertedReflectance)
Detects finder patterns of QR codes in subregion of a given 8 bit grayscale image.
static bool checkFinderPatternDirectional(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const Scalar angle, const unsigned int threshold, const unsigned int blackSquareSegmentMin, const unsigned int blackSquareSegmentMax, const unsigned int whiteSquareSegmentMin, const unsigned int whiteSquareSegmentMax, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, const bool isNormalReflectance, Vector2 &topBorder, Vector2 &bottomBorder)
Performs a check for a given candidate location in a specified direction (yielding 2 edge points)
static bool findNextTransitionInRow(const uint8_t *const yRow, const unsigned int width, unsigned int &x, bool(*transitionDetector)(const uint8_t *, TransitionHistory &))
Finds the next transition in a row.
static FinderPatterns detectFinderPatterns(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int minimumDistance=10u, const unsigned int paddingElements=0u, Worker *worker=nullptr, const bool detectInvertedReflectance=false)
Detects finder patterns of a QR code in a 8 bit grayscale image.
static bool estimateFinderPatternCorners(const unsigned int xCenter, const unsigned int yCenter, const Vector2 *edgePoints, const unsigned int edgePointsSize, Vector2 &location, Vector2 *corners, Vector2 &orientation, Scalar &moduleSize, const Scalar edgePointDistanceTolerance=2.25, const Scalar maxEdgeLineDistance=1.5)
Estimates the locations of the corners of finder pattern and computes the dominant orientation of the...
static bool isParallel(const FinderPattern &finderPatternA, const FinderPattern &finderPatternB, const Scalar distanceTolerance=Scalar(0.05))
Returns true if a pair of finder patterns is in parallel configuration, i.e., if one is above/below/l...
Definition FinderPatternDetector.h:760
static unsigned int determineThreshold(const uint8_t *yPosition, const unsigned int segmentSize1, const unsigned int segmentSize2, const unsigned int segmentSize3, const unsigned int segmentSize4, const unsigned int segmentSize5, const bool isNormalReflectance)
Determines the gray threshold separating bright pixels form dark pixels.
Definition FinderPatternDetector.h:712
static bool checkCenterSegmentDirectional(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int centerSegmentMin, const unsigned int centerSegmentMax, TransitionDetector::FindNextPixelFunc findNextBackgroundPixel, Bresenham &bresenhamTop, Bresenham &bresenhamBottom, unsigned int &topColumns, unsigned int &topRows, unsigned int &bottomColumns, unsigned int &bottomRows, VectorT2< unsigned int > &topIn, VectorT2< unsigned int > &topOut, VectorT2< unsigned int > &bottomIn, VectorT2< unsigned int > &bottomOut)
Checks the center foreground segment in both scanline directions.
static void detectFinderPatternInRow(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int y, FinderPatterns &finderPatterns, const unsigned int paddingElements, const bool isNormalReflectance)
Detects finder patterns of QR codes in a single row of an grayscale image.
static bool isTransitionToWhite(const uint8_t *pixel, TransitionHistory &history)
Checks whether the given pixel is a transition-to-white pixel (whether the direct left neighbor is a ...
Definition FinderPatternDetector.h:688
Definition of a class for finder patterns of QR codes (squares in the top-left, top-right and bottom-...
Definition FinderPatternDetector.h:58
const Vector2 * corners() const
Returns a pointer to the four corners of this finder pattern.
Definition FinderPatternDetector.h:587
Scalar symmetryScore() const
Returns the symmetry score that was determined when this finder pattern was detected.
Definition FinderPatternDetector.h:577
const Vector2 & orientation() const
Returns the dominant orientation of this finder pattern.
Definition FinderPatternDetector.h:599
Vector2 corners_[4]
The four corners of this finder pattern; points are stored in counter-clockwise order but no guarante...
Definition FinderPatternDetector.h:179
bool cornersKnown_
True if the four corners of this finder pattern are known, otherwise false.
Definition FinderPatternDetector.h:176
Scalar length() const
Returns the radius of the finder pattern.
Definition FinderPatternDetector.h:557
bool cornersKnown() const
Returns true if the four corners of this finder pattern are known, otherwise false.
Definition FinderPatternDetector.h:582
const Vector2 & position() const
Returns the (center) position of the finder pattern.
Definition FinderPatternDetector.h:552
unsigned int grayThreshold() const
Returns the threshold that was used for the detection of this finder pattern.
Definition FinderPatternDetector.h:567
Vector2 orientation_
Dominant orientation of this finder pattern.
Definition FinderPatternDetector.h:182
bool isNormalReflectance() const
Returns whether this finder pattern is of normal reflectance.
Definition FinderPatternDetector.h:605
static bool comesBefore(const FinderPattern &first, const FinderPattern &second)
Comparator to sort finder patterns based on their location in an image Pattern a comes before pattern...
Definition FinderPatternDetector.h:610
Scalar symmetryScore_
The symmetry score of this finder pattern, range: [0, infinity) (lower score = higher symmetry)
Definition FinderPatternDetector.h:173
Vector2 position_
The (center) position of the finder pattern within the camera frame.
Definition FinderPatternDetector.h:161
Scalar moduleSize_
Module width (bit width) in pixels.
Definition FinderPatternDetector.h:185
FinderPattern()
Creates an invalid finder pattern object.
Definition FinderPatternDetector.h:500
Scalar length_
The edge length of the finder pattern in pixels, range: (0, infinity).
Definition FinderPatternDetector.h:164
unsigned int grayThreshold_
The threshold that was used during the detection of this finder pattern.
Definition FinderPatternDetector.h:170
unsigned int centerIntensity_
The intensity value that has been measured in the center of the finder pattern.
Definition FinderPatternDetector.h:167
Scalar moduleSize() const
Returns the width of a module (= bit) in pixels.
Definition FinderPatternDetector.h:572
unsigned int centerIntensity() const
Returns the intensity value that was measured in the center of the finder pattern.
Definition FinderPatternDetector.h:562
bool(*)(const uint8_t *const, const unsigned int, const unsigned int, const unsigned int, const unsigned int, const unsigned int, CV::Bresenham &, const unsigned int, const unsigned int, unsigned int &, unsigned int &, VectorT2< unsigned int > &, VectorT2< unsigned int > &) FindNextPixelFunc
Function pointer to functions that detect a transition.
Definition TransitionDetector.h:42
static bool isBlack(const T &intensityValue, const T &threshold)
Determines whether an intensity value is black according to threshold value.
Definition TransitionDetector.h:181
This class implements an infinite line in 2D space.
Definition Line2.h:83
T sqrDistance(const VectorT2< T > &point) const
Returns the square distance between the line and a given point.
Definition Line2.h:498
This class implements a recursive lock object.
Definition Lock.h:31
This class provides basic numeric functionalities.
Definition Numeric.h:57
static constexpr T deg2rad(const T deg)
Converts deg to rad.
Definition Numeric.h:3241
static T abs(const T value)
Returns the absolute value of a given value.
Definition Numeric.h:1220
static constexpr bool isEqualEps(const T value)
Returns whether a value is smaller than or equal to a small epsilon.
Definition Numeric.h:2096
static T cos(const T value)
Returns the cosine of a given value.
Definition Numeric.h:1588
const T & x() const noexcept
Returns the x value.
Definition Vector2.h:703
const T & y() const noexcept
Returns the y value.
Definition Vector2.h:715
VectorT2< T > normalized() const
Returns the normalized vector.
Definition Vector2.h:563
VectorT2< T > normalizedOrZero() const
Returns the normalized vector.
Definition Vector2.h:577
T length() const
Returns the length of the vector.
Definition Vector2.h:620
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
unsigned int sqrDistance(const char first, const char second)
Returns the square distance between two values.
Definition base/Utilities.h:1159
std::vector< FinderPattern > FinderPatterns
Definition of a vector holding finder pattern.
Definition FinderPatternDetector.h:192
std::vector< IndexTriplet > IndexTriplets
Definition of a vector index triplets.
Definition FinderPatternDetector.h:51
std::array< FinderPattern, 3 > FinderPatternTriplet
Definition of a 3-tuple of finder patterns.
Definition FinderPatternDetector.h:198
std::array< unsigned int, 3 > IndexTriplet
Definition of a triplet of indices.
Definition FinderPatternDetector.h:45
LineT2< Scalar > Line2
Definition of the Line2 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with single o...
Definition Line2.h:28
float Scalar
Definition of a scalar type.
Definition Math.h:129
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition Vector2.h:28
std::vector< QRCode > QRCodes
Definition of a vector of QR codes.
Definition QRCode.h:28
The namespace covering the entire Ocean framework.
Definition Accessor.h:15