Ocean
Loading...
Searching...
No Matches
TransitionDetector.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
11
12#include "ocean/cv/Bresenham.h"
13
14#include "ocean/math/Vector2.h"
15
16#include <type_traits>
17
18namespace Ocean
19{
20
21namespace CV
22{
23
24namespace Detector
25{
26
27namespace QRCodes
28{
29
30/**
31 * Definition of functions related to the detection of pixel transitions
32 * @ingroup cvdetectorqrcodes
33 */
34class OCEAN_CV_DETECTOR_QRCODES_EXPORT TransitionDetector
35{
36 public:
37
38 /**
39 * Function pointer to functions that detect a transition
40 * @sa TransitionDetector::findNextPixel<bool>()
41 */
42 using FindNextPixelFunc = 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>&);
43
44 /**
45 * Function pointer for applying a binary threshold to a pixel to determine whether it is black or white
46 * @sa TransitionDetector::isBlackPixel(), TransitionDetector::isWhitePixel()
47 */
48 using PixelBinaryThresholdFunc = bool(*)(const uint8_t*, const uint8_t);
49
50 public:
51
52 /**
53 * Finds a the next dark or the next light pixel in a specified direction.
54 * @param yPointer The pointer to the location within the image at which the search will start, must be valid
55 * @param x Horizontal location within the image as input, with range [1, width - 1]
56 * @param y Vertical location within the image as input, with range [1, height - 1]
57 * @param width The width of the input image, range: [1, infinity)
58 * @param height The height of the input image, range: [1, infinity)
59 * @param yPointerPaddingElements Number of padding elements in the input image. If no stride if used, this should be 0, range: [0, infinity)
60 * @param bresenham Bresenham object that defines a scanline direction, must be valid
61 * @param maximumDistance The maximum number of rows (or columns) to travel (Manhattan distance), range: [1, infinity)
62 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
63 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
64 * @param columns The resulting number of columns that have been traveled until the black or white pixel has been found
65 * @param lastPointInside The resulting coordinates of the last point *before* the intensity switch
66 * @param firstPointOutside The resulting coordinates of the last point *after* the intensity switch
67 * @return True, if the black or white pixel have been found within the specified range of [1, maximalManhattanDistance]
68 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
69 */
70 template <bool tFindBlackPixel>
71 static bool findNextPixel(const uint8_t* const yPointer, const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height, const unsigned int yPointerPaddingElements, CV::Bresenham& bresenham, const unsigned int maximumDistance, const unsigned int threshold, unsigned int& columns, unsigned int& rows, VectorT2<unsigned int>& lastPointInside, VectorT2<unsigned int>& firstPointOutside);
72
73 /**
74 * Finds either the next black or the next white pixel towards negative y direction (upwards in an image).
75 * @param yPointer The pointer to the location within the image at which the search will start, must be valid
76 * @param y The current vertical location within the image, with range [1, height - 1]
77 * @param height The height of the frame in pixel, with range [1, infinity)
78 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, height - y]
79 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
80 * @param frameStrideElements The number of horizontal stride elements in the image, which is width + paddingElements, with range [width, infinity)
81 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
82 * @return True, if the black or white pixel have been found within the specified range of [1, maximalRows]
83 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
84 */
85 template <bool tFindBlackPixel>
86 static bool findNextUpperPixel(const uint8_t* yPointer, unsigned int y, const unsigned int height, const unsigned int maximalRows, const unsigned int threshold, const unsigned int frameStrideElements, unsigned int& rows);
87
88 /**
89 * Finds either the next black or the next white pixel towards positive y direction (downwards in an image).
90 * @param yPointer The pointer to the location within the image at which the search will start, must be valid
91 * @param y The current vertical location within the image, with range [1, height - 1]
92 * @param height The height of the frame in pixel, with range [1, infinity)
93 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, height - y]
94 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
95 * @param frameStrideElements The number of horizontal stride elements in the image, which is width + paddingElements, with range [width, infinity)
96 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
97 * @return True, if the black or white pixel have been found within the specified range of [1, maximalRows]
98 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
99 */
100 template <bool tFindBlackPixel>
101 static bool findNextLowerPixel(const uint8_t* yPointer, unsigned int y, const unsigned int height, const unsigned int maximalRows, const unsigned int threshold, const unsigned int frameStrideElements, unsigned int& rows);
102
103 /**
104 * Determines the sub-pixel location of a fiducial marker given its approximate location
105 * @param yFrame The 8-bit grayscale frame in which the alignment patterns were detected, must be valid
106 * @param width The width of the input frame in pixels, with range [21, infinity)
107 * @param height The height of the given frame in pixel, with range [21, infinity)
108 * @param framePaddingElements Optional number of padding elements at the end of each image row, in elements, with range [0, infinity)
109 * @param xCenter The horizontal location of the center of the fiducial, with range [0, width - 1]
110 * @param yCenter The vertical location of the center of the fiducial, with range [0, height - 1]
111 * @param isNormalReflectance The reflectance of the fiducial, which indicates whether the center location is dark (normal reflectance) or light (inverted reflectance)
112 * @param grayThreshold The threshold separating a foreground and background pixels, with range [0, 255]
113 * @param location The resulting sub-pixel location of the center of the fiducial
114 * @return True, if the sub-pixel location could be determined
115 */
116 static bool determineSubPixelLocation(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int xCenter, const unsigned int yCenter, const bool isNormalReflectance, const unsigned int grayThreshold, Vector2& location);
117
118 /**
119 * Computes the intensity transition point with sub-pixel accuracy given the two image points around a transition point (before and after)
120 * @param yFrame Pointer to a grayscale image of size `width x height` pixels, must be valid
121 * @param width The width of the input frame, range: [1, infinity)
122 * @param height The height of the input frame, range: [1, infinity)
123 * @param yFramePaddingElements Number of padding elements of this frame, range: [0, infinity)
124 * @param pointInside The point before the intensity transition, range: x,y in [0, infinity)
125 * @param pointOutside The point after the intensity transition, range: x,y in [0, infinity)
126 * @param grayThreshold The threshold that is used to compute the location of the transition with sub-pixel accuracy, range: [0, 255]
127 * @param transitionPoint Resulting sub-pixel position of the transition point
128 * @return True if sub-pixel position can be computed (i.e. transition across `grayThreshold` exists between pixels at `pointInside` and `pointOutside`), otherwise false
129 */
130 static bool computeTransitionPointSubpixelAccuracy(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const VectorT2<unsigned int>& pointInside, const VectorT2<unsigned int>& pointOutside, const unsigned int grayThreshold, Vector2& transitionPoint);
131
132 /**
133 * Determines whether an intensity value is black according to threshold value
134 * @param intensityValue Intensity value in a grayscale image
135 * @param threshold The threshold that is used for the comparison, range: [0, 255]
136 * @return True if the intensity value is black relative to threshold value (i.e. less or equal to a threshold), false otherwise
137 * @tparam T The data type of the intensity value, `T` can be an arithmetic type (integral or floating point type) able to represent values ranging from 0 to 255
138 */
139 template<typename T>
140 static inline bool isBlack(const T& intensityValue, const T& threshold);
141
142 /**
143 * Determines whether an intensity value is white according to threshold value
144 * @param intensityValue Intensity value in a grayscale image
145 * @param threshold The threshold that is used for the comparison, range: [0, 255]
146 * @return True if the intensity value is white relative to threshold value (i.e. is greater than a threshold), false otherwise
147 * @tparam T The data type of the intensity value, `T` can be an arithmetic type (integer or floating point type) able to represent values ranging from 0 to 255
148 */
149 template<typename T>
150 static inline bool isWhite(const T& intensityValue, const T& threshold);
151
152 /**
153 * Determines whether a pixel is black according to threshold value
154 * @param yFramePixel Pointer to a pixel in an 8-bit grayscale image, must be valid
155 * @param threshold The threshold that is used for the comparison, range: [0, 255]
156 * @return True if the pixel value is black relative to threshold value (i.e. less or equal to a threshold), false otherwise
157 */
158 static inline bool isBlackPixel(const uint8_t* yFramePixel, uint8_t threshold);
159
160 /**
161 * Determines whether a pixel is white according to threshold value
162 * @param yFramePixel Pointer to a pixel in an 8-bit grayscale image, must be valid
163 * @param threshold The threshold that is used for the comparison, range: [0, 255]
164 * @return True if the pixel value is white relative to threshold value (i.e. is greater than a threshold), false otherwise
165 */
166 static inline bool isWhitePixel(const uint8_t* yFramePixel, uint8_t threshold);
167
168 /**
169 * Determines whether a transition occurred between pixel values of two neighboring pixels in a row and, if so, calculates the sub-pixel horizontal position of transition point
170 * @param yRow Pointer to a row in a grayscale image `width` pixels wide, must be valid
171 * @param width The width of the input frame, range: [1, infinity)
172 * @param xPointLeft Horizontal position of the left pixel, range: [0, width - 2]
173 * @param grayThreshold Threshold value that is used to check whether a transition occurred between the two neighboring pixels
174 * @param xTransitionPoint Resulting sub-pixel horizontal position of the transition point
175 * @return True if sub-pixel position can be computed (i.e. if transition across `grayThreshold` exists between left and right pixel), otherwise false
176 */
177 static inline bool computeHorizontalTransitionPointSubpixelAccuracy(const std::uint8_t* yRow, const unsigned int width, const unsigned int xPointLeft, const std::uint8_t grayThreshold, Scalar& xTransitionPoint);
178};
179
180template<typename T>
181inline bool TransitionDetector::isBlack(const T& intensityValue, const T& threshold)
182{
183 static_assert(std::is_arithmetic_v<T> && NumericT<T>::maxValue() >= 255, "`T` must be an arithmetic type able to hold values up to 255!");
184 ocean_assert (threshold >= T(0) && threshold <= T(255));
185
186 return intensityValue <= threshold;
187}
188
189template<typename T>
190inline bool TransitionDetector::isWhite(const T& intensityValue, const T& threshold)
191{
192 static_assert(std::is_arithmetic_v<T> && NumericT<T>::maxValue() >= 255, "`T` must be an arithmetic type able to hold values up to 255!");
193 ocean_assert (threshold >= T(0) && threshold <= T(255));
194
195 return intensityValue > threshold;
196}
197
198inline bool TransitionDetector::isBlackPixel(const uint8_t* yFramePixel, uint8_t threshold)
199{
200 ocean_assert(yFramePixel != nullptr);
201
202 return isBlack(*yFramePixel, threshold);
203}
204
205inline bool TransitionDetector::isWhitePixel(const uint8_t* yFramePixel, uint8_t threshold)
206{
207 ocean_assert(yFramePixel != nullptr);
208
209 return isWhite(*yFramePixel, threshold);
210}
211
212inline bool TransitionDetector::computeHorizontalTransitionPointSubpixelAccuracy(const std::uint8_t* yRow, const unsigned int width, const unsigned int xPointLeft, const std::uint8_t grayThreshold, Scalar& xTransitionPoint)
213{
214 ocean_assert(yRow != nullptr);
215 ocean_assert_and_suppress_unused(xPointLeft <= width - 2u, width);
216
217 const std::uint8_t leftPixelValue = yRow[xPointLeft];
218 const std::uint8_t rightPixelValue = yRow[xPointLeft + 1u];
219
220 if (leftPixelValue <= grayThreshold == rightPixelValue <= grayThreshold)
221 {
222 return false;
223 }
224
225 xTransitionPoint = xPointLeft + Scalar((int)leftPixelValue - (int)grayThreshold) / ((int)leftPixelValue - (int)rightPixelValue);
226
227 return true;
228}
229
230} // namespace QRCodes
231
232} // namespace Detector
233
234} // namespace CV
235
236} // namespace Ocean
This class implements bresenham line algorithms.
Definition Bresenham.h:27
Definition of functions related to the detection of pixel transitions.
Definition TransitionDetector.h:35
static bool computeHorizontalTransitionPointSubpixelAccuracy(const std::uint8_t *yRow, const unsigned int width, const unsigned int xPointLeft, const std::uint8_t grayThreshold, Scalar &xTransitionPoint)
Determines whether a transition occurred between pixel values of two neighboring pixels in a row and,...
Definition TransitionDetector.h:212
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
static bool findNextUpperPixel(const uint8_t *yPointer, unsigned int y, const unsigned int height, const unsigned int maximalRows, const unsigned int threshold, const unsigned int frameStrideElements, unsigned int &rows)
Finds either the next black or the next white pixel towards negative y direction (upwards in an image...
static bool isBlackPixel(const uint8_t *yFramePixel, uint8_t threshold)
Determines whether a pixel is black according to threshold value.
Definition TransitionDetector.h:198
static bool determineSubPixelLocation(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const unsigned int xCenter, const unsigned int yCenter, const bool isNormalReflectance, const unsigned int grayThreshold, Vector2 &location)
Determines the sub-pixel location of a fiducial marker given its approximate location.
static bool findNextPixel(const uint8_t *const yPointer, const unsigned int x, const unsigned int y, const unsigned int width, const unsigned int height, const unsigned int yPointerPaddingElements, CV::Bresenham &bresenham, const unsigned int maximumDistance, const unsigned int threshold, unsigned int &columns, unsigned int &rows, VectorT2< unsigned int > &lastPointInside, VectorT2< unsigned int > &firstPointOutside)
Finds a the next dark or the next light pixel in a specified direction.
static bool findNextLowerPixel(const uint8_t *yPointer, unsigned int y, const unsigned int height, const unsigned int maximalRows, const unsigned int threshold, const unsigned int frameStrideElements, unsigned int &rows)
Finds either the next black or the next white pixel towards positive y direction (downwards in an ima...
static bool computeTransitionPointSubpixelAccuracy(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, const VectorT2< unsigned int > &pointInside, const VectorT2< unsigned int > &pointOutside, const unsigned int grayThreshold, Vector2 &transitionPoint)
Computes the intensity transition point with sub-pixel accuracy given the two image points around a t...
static bool isWhitePixel(const uint8_t *yFramePixel, uint8_t threshold)
Determines whether a pixel is white according to threshold value.
Definition TransitionDetector.h:205
static bool isWhite(const T &intensityValue, const T &threshold)
Determines whether an intensity value is white according to threshold value.
Definition TransitionDetector.h:190
bool(*)(const uint8_t *, const uint8_t) PixelBinaryThresholdFunc
Function pointer for applying a binary threshold to a pixel to determine whether it is black or white...
Definition TransitionDetector.h:48
static constexpr T maxValue()
Returns the max scalar value.
Definition Numeric.h:3244
This class implements a vector with two elements.
Definition Vector2.h:96
float Scalar
Definition of a scalar type.
Definition Math.h:129
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