Ocean
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 
18 namespace Ocean
19 {
20 
21 namespace CV
22 {
23 
24 namespace Detector
25 {
26 
27 namespace QRCodes
28 {
29 
30 /**
31  * Definition of functions related to the detection of pixel transitions
32  * @ingroup cvdetectorqrcodes
33  */
34 class 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 
180 template<typename T>
181 inline 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 
189 template<typename T>
190 inline 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 
198 inline bool TransitionDetector::isBlackPixel(const uint8_t* yFramePixel, uint8_t threshold)
199 {
200  ocean_assert(yFramePixel != nullptr);
201 
202  return isBlack(*yFramePixel, threshold);
203 }
204 
205 inline bool TransitionDetector::isWhitePixel(const uint8_t* yFramePixel, uint8_t threshold)
206 {
207  ocean_assert(yFramePixel != nullptr);
208 
209  return isWhite(*yFramePixel, threshold);
210 }
211 
212 inline 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
This class provides basic numeric functionalities.
Definition: Numeric.h:57
This class implements a vector with two elements.
Definition: Vector2.h:96
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::vector< QRCode > QRCodes
Definition of a vector of QR codes.
Definition: QRCode.h:25
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15