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
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 cornersKnown_(false),
513 orientation_(1, 0),
514 moduleSize_(length / Scalar(7))
515{
516 ocean_assert(centerIntensity_ <= 255u);
517 ocean_assert(grayThreshold_ <= 255u);
518
519 corners_[0] = Vector2(-1, -1);
520 corners_[1] = Vector2(-1, -1);
521 corners_[2] = Vector2(-1, -1);
522 corners_[3] = Vector2(-1, -1);
523}
524
525inline 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) :
526 position_(position),
527 length_(length),
528 centerIntensity_(centerIntensity),
529 grayThreshold_(grayThreshold),
530 symmetryScore_(symmetryScore),
531 cornersKnown_(true),
532 orientation_(orientation),
533 moduleSize_(moduleSize)
534{
535 ocean_assert(centerIntensity_ <= 255u);
536 ocean_assert(grayThreshold_ <= 255u);
537
538 ocean_assert(corners != nullptr);
539
540 // Expect a counter-clockwise order for the corners
541
542 ocean_assert((corners[1] - corners[0]).cross(corners[3] - corners[0]) <= 0);
543 ocean_assert((corners[2] - corners[1]).cross(corners[0] - corners[1]) <= 0);
544 ocean_assert((corners[3] - corners[2]).cross(corners[1] - corners[2]) <= 0);
545 ocean_assert((corners[0] - corners[3]).cross(corners[2] - corners[3]) <= 0);
546
547 corners_[0] = corners[0];
548 corners_[1] = corners[1];
549 corners_[2] = corners[2];
550 corners_[3] = corners[3];
551}
552
553inline const Vector2& FinderPattern::position() const
554{
555 return position_;
556}
557
559{
560 return length_;
561}
562
563inline unsigned int FinderPattern::centerIntensity() const
564{
565 return centerIntensity_;
566}
567
568inline unsigned int FinderPattern::grayThreshold() const
569{
570 return grayThreshold_;
571}
572
574{
575 return moduleSize_;
576}
577
579{
580 return symmetryScore_;
581}
582
584{
585 return cornersKnown_;
586}
587
588inline const Vector2* FinderPattern::corners() const
589{
590 // Expect a counter-clockwise order for the corners, if the corners are known
591
592 ocean_assert(cornersKnown() == false || (corners_[1] - corners_[0]).cross(corners_[3] - corners_[0]) <= 0);
593 ocean_assert(cornersKnown() == false || (corners_[2] - corners_[1]).cross(corners_[0] - corners_[1]) <= 0);
594 ocean_assert(cornersKnown() == false || (corners_[3] - corners_[2]).cross(corners_[1] - corners_[2]) <= 0);
595 ocean_assert(cornersKnown() == false || (corners_[0] - corners_[3]).cross(corners_[2] - corners_[3]) <= 0);
596
597 return corners_;
598}
599
601{
602 ocean_assert(Numeric::isEqualEps(orientation_.length() - Scalar(1)));
603 return orientation_;
604}
605
610
611inline bool FinderPattern::comesBefore(const FinderPattern& first, const FinderPattern& second)
612{
613 return first.position().y() > second.position().y() || (first.position().y() == second.position().y() && first.position().x() > second.position().x());
614};
615
617 : deltas_{ 0, 0, 0, 0, 0 }
618{
619 // Nothing else to do.
620}
621
623{
624 return deltas_[0];
625}
626
628{
629 return deltas_[0] + deltas_[1];
630}
631
633{
634 return deltas_[0] + deltas_[1] + deltas_[2];
635}
636
638{
639 return deltas_[0] + deltas_[1] + deltas_[2] + deltas_[3];
640}
641
643{
644 return deltas_[0] + deltas_[1] + deltas_[2] + deltas_[3] + deltas_[4];
645}
646
648{
649 deltas_[4] = deltas_[3];
650 deltas_[3] = deltas_[2];
651 deltas_[2] = deltas_[1];
652 deltas_[1] = deltas_[0];
653 deltas_[0] = newDelta;
654}
655
657{
658 deltas_[0] = 0;
659 deltas_[1] = 0;
660 deltas_[2] = 0;
661 deltas_[3] = 0;
662 deltas_[4] = 0;
663}
664
665inline bool FinderPatternDetector::isTransitionToBlack(const uint8_t* pixel, TransitionHistory& history)
666{
667 const int currentDelta = int(*(pixel + 0) - *(pixel - 1));
668
669 bool result = false;
670
671 if (currentDelta < -deltaThreshold)
672 {
673 result = true;
674 }
675 else if ((currentDelta + history.history1() < -deltaThreshold)
676 || (currentDelta + history.history2() < -(deltaThreshold * 5 / 4))
677 || (currentDelta + history.history3() < -(deltaThreshold * 6 / 4))
678 || (currentDelta + history.history4() < -(deltaThreshold * 7 / 4))
679 || (currentDelta + history.history5() < -(deltaThreshold * 8 / 4)))
680 {
681 result = true;
682 }
683
684 history.push(currentDelta);
685
686 return result;
687}
688
689inline bool FinderPatternDetector::isTransitionToWhite(const uint8_t* pixel, TransitionHistory& history)
690{
691 const int currentDelta = int(*(pixel + 0) - *(pixel - 1));
692
693 bool result = false;
694
695 if (currentDelta > deltaThreshold)
696 {
697 result = true;
698 }
699 else if ((currentDelta + history.history1() > deltaThreshold)
700 || (currentDelta + history.history2() > (deltaThreshold * 5 / 4))
701 || (currentDelta + history.history3() > (deltaThreshold * 6 / 4))
702 || (currentDelta + history.history4() > (deltaThreshold * 7 / 4))
703 || (currentDelta + history.history5() > (deltaThreshold * 8 / 4)))
704 {
705 result = true;
706 }
707
708 history.push(currentDelta);
709
710 return result;
711}
712
713inline 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)
714{
715 unsigned int sumForeground = 0u;
716 unsigned int sumBackground = 0u;
717
718 sumBackground += *(yPosition - 1);
719
720 for (unsigned int n = 0u; n < segmentSize1; ++n)
721 {
722 sumForeground += *yPosition++;
723 }
724
725 for (unsigned int n = 0u; n < segmentSize2; ++n)
726 {
727 sumBackground += *yPosition++;
728 }
729
730 for (unsigned int n = 0u; n < segmentSize3; ++n)
731 {
732 sumForeground += *yPosition++;
733 }
734
735 for (unsigned int n = 0u; n < segmentSize4; ++n)
736 {
737 sumBackground += *yPosition++;
738 }
739
740 for (unsigned int n = 0u; n < segmentSize5; ++n)
741 {
742 sumForeground += *yPosition++;
743 }
744
745 sumBackground += *yPosition;
746
747 const unsigned int averageForeground = sumForeground / (segmentSize1 + segmentSize3 + segmentSize5);
748 const unsigned int averageBackground = sumBackground / (segmentSize2 + segmentSize4 + 2u);
749 const unsigned int averageBlack = isNormalReflectance ? averageForeground : averageBackground;
750 const unsigned int averageWhite = isNormalReflectance ? averageBackground : averageForeground;
751
752 if (averageBlack + 2u >= averageWhite)
753 {
754 // the separate between bright and dark pixels is not strong enough
755 return (unsigned int)(-1);
756 }
757
758 return (averageBlack + averageWhite + 1u) / 2u;
759}
760
761inline bool FinderPatternDetector::isParallel(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar distanceTolerance)
762{
763 ocean_assert(finderPatternA.cornersKnown() && finderPatternB.cornersKnown());
764 ocean_assert(finderPatternB.corners() != nullptr && finderPatternA.corners() != nullptr);
765 ocean_assert(distanceTolerance >= 0);
766
767 const Line2 linesB[4] =
768 {
769 Line2(finderPatternB.corners()[1], (finderPatternB.corners()[0] - finderPatternB.corners()[1]).normalized()),
770 Line2(finderPatternB.corners()[2], (finderPatternB.corners()[1] - finderPatternB.corners()[2]).normalized()),
771 Line2(finderPatternB.corners()[3], (finderPatternB.corners()[2] - finderPatternB.corners()[3]).normalized()),
772 Line2(finderPatternB.corners()[0], (finderPatternB.corners()[3] - finderPatternB.corners()[0]).normalized())
773 };
774
775 const Vector2 lineAB = finderPatternB.position() - finderPatternA.position();
776 const Vector2 directionAB = lineAB.normalizedOrZero();
777
778 const Scalar squareDistanceThreshold = (lineAB.length() * distanceTolerance) * (lineAB.length() * distanceTolerance);
779
780 for (unsigned int n = 0u; n < 4u; ++n)
781 {
782 // Reject pairs of lines diverge too much
783 if (Numeric::abs(directionAB * linesB[n].direction()) <= Numeric::cos(Numeric::deg2rad(35)))
784 {
785 continue;
786 }
787
788 // Check if:
789 //
790 // * 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.
791 // * 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.
792 //
793 // If both is true, finder patterns a and b are considered parallel.
794
795 const Scalar sqrDistanceCornerA0 = linesB[n].sqrDistance(finderPatternA.corners()[0]);
796 const Scalar sqrDistanceCornerA1 = linesB[n].sqrDistance(finderPatternA.corners()[1]);
797
798 if (sqrDistanceCornerA0 < squareDistanceThreshold && sqrDistanceCornerA1 < squareDistanceThreshold)
799 {
800 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
801 {
802 return true;
803 }
804 }
805
806 const Scalar sqrDistanceCornerA2 = linesB[n].sqrDistance(finderPatternA.corners()[2]);
807
808 if (sqrDistanceCornerA1 < squareDistanceThreshold && sqrDistanceCornerA2 < squareDistanceThreshold)
809 {
810 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
811 {
812 return true;
813 }
814 }
815
816 const Scalar sqrDistanceCornerA3 = linesB[n].sqrDistance(finderPatternA.corners()[3]);
817
818 if (sqrDistanceCornerA2 < squareDistanceThreshold && sqrDistanceCornerA3 < squareDistanceThreshold)
819 {
820 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
821 {
822 return true;
823 }
824 }
825
826 if (sqrDistanceCornerA3 < squareDistanceThreshold && sqrDistanceCornerA0 < squareDistanceThreshold)
827 {
828 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
829 {
830 return true;
831 }
832 }
833 }
834
835 return false;
836}
837
838inline bool FinderPatternDetector::isDiagonal(const FinderPattern& finderPatternA, const FinderPattern& finderPatternB, const Scalar angleTolerance)
839{
840 ocean_assert(finderPatternA.cornersKnown() && finderPatternB.cornersKnown());
841 ocean_assert(finderPatternB.corners() != nullptr && finderPatternA.corners() != nullptr);
842 ocean_assert(angleTolerance >= 0 && angleTolerance < Numeric::deg2rad(90));
843
844 const Vector2 directionAB = (finderPatternB.position() - finderPatternA.position()).normalizedOrZero();
845 const Scalar angleThreshold = Numeric::abs(Numeric::cos(angleTolerance));
846
847 const Vector2 diagonalsA[2] =
848 {
849 (finderPatternA.corners()[2] - finderPatternA.corners()[0]).normalizedOrZero(),
850 (finderPatternA.corners()[3] - finderPatternA.corners()[1]).normalizedOrZero()
851 };
852
853 unsigned int diagonalEdgeA = (unsigned int)(-1);
854 unsigned int diagonalEdgeB = (unsigned int)(-1);
855
856 if (Numeric::abs(diagonalsA[0] * directionAB) >= angleThreshold)
857 {
858 diagonalEdgeA = 0u;
859 }
860 else if (Numeric::abs(diagonalsA[1] * directionAB) >= angleThreshold)
861 {
862 diagonalEdgeA = 1u;
863 }
864
865 if (diagonalEdgeA >= 2u)
866 {
867 return false;
868 }
869
870 const Vector2 diagonalsB[2] =
871 {
872 (finderPatternB.corners()[2] - finderPatternB.corners()[0]).normalizedOrZero(),
873 (finderPatternB.corners()[3] - finderPatternB.corners()[1]).normalizedOrZero()
874 };
875
876 if (Numeric::abs(diagonalsB[0] * directionAB) >= angleThreshold)
877 {
878 diagonalEdgeB = 0u;
879 }
880 else if (Numeric::abs(diagonalsB[1] * directionAB) >= angleThreshold)
881 {
882 diagonalEdgeB = 1u;
883 }
884
885 return diagonalEdgeA < 2u && diagonalEdgeB < 2u;
886}
887
888} // namespace QRCodes
889
890} // namespace Detector
891
892} // namespace CV
893
894} // 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:627
int history3()
Returns the history with window size N.
Definition FinderPatternDetector.h:632
void push(const int newDelta)
Adds a new delta object as most recent history.
Definition FinderPatternDetector.h:647
void reset()
Resets the history object.
Definition FinderPatternDetector.h:656
int history5()
Returns the history with window size N.
Definition FinderPatternDetector.h:642
TransitionHistory()
Creates a new history object.
Definition FinderPatternDetector.h:616
int history4()
Returns the history with window size N.
Definition FinderPatternDetector.h:637
int history1()
Returns the history with window size N.
Definition FinderPatternDetector.h:622
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:838
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:665
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:761
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:713
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:689
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:588
Scalar symmetryScore() const
Returns the symmetry score that was determined when this finder pattern was detected.
Definition FinderPatternDetector.h:578
const Vector2 & orientation() const
Returns the dominant orientation of this finder pattern.
Definition FinderPatternDetector.h:600
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:558
bool cornersKnown() const
Returns true if the four corners of this finder pattern are known, otherwise false.
Definition FinderPatternDetector.h:583
const Vector2 & position() const
Returns the (center) position of the finder pattern.
Definition FinderPatternDetector.h:553
unsigned int grayThreshold() const
Returns the threshold that was used for the detection of this finder pattern.
Definition FinderPatternDetector.h:568
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:606
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:611
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:573
unsigned int centerIntensity() const
Returns the intensity value that was measured in the center of the finder pattern.
Definition FinderPatternDetector.h:563
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