Ocean
Loading...
Searching...
No Matches
MonoBullseyeDetector.h
Go to the documentation of this file.
1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8#ifndef OCEAN_CV_DETECTOR_BULLSEYES_MONOBULLSEYEDETECTOR_H
9#define OCEAN_CV_DETECTOR_BULLSEYES_MONOBULLSEYEDETECTOR_H
10
12
15
16#include "ocean/base/Frame.h"
17#include "ocean/base/Lock.h"
18#include "ocean/base/Worker.h"
19
21
22namespace Ocean
23{
24
25namespace CV
26{
27
28namespace Detector
29{
30
31namespace Bullseyes
32{
33
34/**
35 * Implementation of a monocular detector for the bullseye pattern.
36 * @ingroup cvdetectorbullseyes
37 */
39{
40 public:
41
42 /**
43 * This class holds the most important parameters for the detector.
44 */
46 {
47 public:
48
49 /**
50 * Creates a new valid parameter object.
51 */
52 Parameters() = default;
53
54 /**
55 * Returns whether the parameters are valid.
56 * @return True if the parameters are valid
57 */
58 bool isValid() const noexcept;
59
60 /**
61 * Returns the pixel threshold for frame pyramid creation.
62 * @return The pixel threshold value, with range [0, infinity)
63 */
64 unsigned int framePyramidPixelThreshold() const noexcept;
65
66 /**
67 * Returns the number of layers for the frame pyramid.
68 * @return The number of pyramid layers, with range [1, infinity)
69 */
70 unsigned int framePyramidLayers() const noexcept;
71
72 /**
73 * Returns whether adaptive row spacing is enabled during bullseye detection.
74 * @return True if adaptive row spacing is used (performance optimization), false if every row is scanned (higher accuracy)
75 */
76 bool useAdaptiveRowSpacing() const noexcept;
77
78 /**
79 * Sets whether adaptive row spacing should be used during bullseye detection.
80 * When enabled (true), the detector uses adaptive row spacing based on frame height for better performance.
81 * When disabled (false), every row is scanned for higher accuracy but slower performance.
82 * @param useAdaptiveRowSpacing True to enable adaptive spacing, false to scan every row
83 */
85
86 /**
87 * Returns the default parameters for the detector.
88 * @return The default parameters
89 */
90 static Parameters defaultParameters() noexcept;
91
92 protected:
93
94 /// The pixel threshold for frame pyramid creation, with range [0, infinity)
95 unsigned int framePyramidPixelThreshold_ = 640u * 480u;
96
97 /// The number of layers for the frame pyramid, with range [1, infinity)
98 unsigned int framePyramidLayers_ = 3u;
99
100 /// Determines whether adaptive row spacing is used (true) or every row is scanned (false) during bullseye detection
102 };
103
104 public:
105
106 /**
107 * Detects bullseyes in a given 8-bit grayscale image.
108 * @param camera The camera profile that was used to capture the given frame, must be valid
109 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, with origin in the upper left corner, must be valid
110 * @param bullseyes The resulting detected bullseyes, will be appended to the end of the vector
111 * @param parameters The parameters for the detector, must be valid
112 * @param worker Optional worker to distribute the computation
113 * @return True, if succeeded
114 */
115 static bool detectBullseyes(const AnyCamera& camera, const Frame& yFrame, Bullseyes& bullseyes, const Parameters& parameters = Parameters::defaultParameters(), Worker* worker = nullptr);
116
117 protected:
118
119 /**
120 * Detects bullseyes in a subset of a given 8-bit grayscale image.
121 * @param camera The camera profile that was used to capture the given frame, must be valid
122 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
123 * @param bullseyes The resulting bullseyes, will be added to the end of the vector
124 * @param multiThreadLock Lock object in case this function is executed in multiple threads concurrently, otherwise nullptr
125 * @param useAdaptiveRowSpacing True to use adaptive row spacing, false to scan every row
126 * @param firstRow The first row to be handled, with range [0, yFrame.height())
127 * @param numberRows The number of rows to be handled, with range [1, yFrame.height() - firstRow]
128 */
129 static void detectBullseyesSubset(const AnyCamera* camera, const Frame* yFrame, Bullseyes* bullseyes, Lock* multiThreadLock, const bool useAdaptiveRowSpacing, const unsigned int firstRow, const unsigned int numberRows);
130
131 /**
132 * Detects bullseyes in a row of a grayscale image.
133 * @param camera The camera profile that was used to capture the given frame, must be valid
134 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
135 * @param y The index of the row in which the bullseyes will be detected, with range [0, yFrame.height())
136 * @param bullseyes The resulting detected bullseyes, will be added to the end of the vector
137 */
138 static void detectBullseyesInRow(const AnyCamera& camera, const Frame& yFrame, const unsigned int y, Bullseyes& bullseyes);
139
140 /**
141 * Checks whether the given pixel is a transition-to-black pixel (whether the direct left neighbor is a bright pixel).
142 * @param pixel The pixel to be checked, must be valid
143 * @param history The history object containing information about previous pixels
144 * @return True, if so
145 */
146 static bool isTransitionToBlack(const uint8_t* pixel, TransitionHistory& history);
147
148 /**
149 * Checks whether the given pixel is a transition-to-white pixel (whether the direct left neighbor is a dark pixel).
150 * @param pixel The pixel to be checked, must be valid
151 * @param history The history object containing information about previous pixels
152 * @return True, if so
153 */
154 static bool isTransitionToWhite(const uint8_t* pixel, TransitionHistory& history);
155
156 /**
157 * Finds either the next black or the next white pixel towards negative y direction (upwards in an image).
158 * @param yFrame The 8-bit grayscale frame in which the pixel will be searched, must be valid
159 * @param x The horizontal location within the frame at which the search will be performed, in pixels, with range [0, yFrame.width())
160 * @param y The current vertical location within the image, with range [0, yFrame.height())
161 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, y]
162 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
163 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
164 * @return True, if the black or white pixel has been found within the specified range of [1, maximalRows]
165 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
166 */
167 template <bool tFindBlackPixel>
168 static bool findNextUpperPixel(const Frame& yFrame, const unsigned int x, const unsigned int y, const unsigned int maximalRows, const unsigned int threshold, unsigned int& rows);
169
170 /**
171 * Finds either the next black or the next white pixel towards positive y direction (downwards in an image).
172 * @param yFrame The 8-bit grayscale frame in which the pixel will be searched, must be valid
173 * @param x The horizontal location within the frame at which the search will be performed, in pixels, with range [0, yFrame.width())
174 * @param y The current vertical location within the image, with range [0, yFrame.height())
175 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, yFrame.height() - y]
176 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
177 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
178 * @return True, if the black or white pixel has been found within the specified range of [1, maximalRows]
179 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
180 */
181 template <bool tFindBlackPixel>
182 static bool findNextLowerPixel(const Frame& yFrame, const unsigned int x, const unsigned int y, const unsigned int maximalRows, const unsigned int threshold, unsigned int& rows);
183
184 /**
185 * Determines the gray threshold separating bright pixels from dark pixels.
186 * The threshold is based on actual pixel values for which the association is known already.
187 * The provided position is a pointer to any pixel within the image frame.
188 * In addition to the pixels covered by the five segments, pixels neighboring the segments are also used for estimation of the threshold.
189 * @param yPosition The first pixel within an 8-bit grayscale image for which 5 connected segments are known with black, white, black, white, and black pixels, must be valid
190 * @param segmentSize1 The number of pixels covering dark pixels, with range [1, infinity)
191 * @param segmentSize2 The number of pixels covering bright pixels, with range [1, infinity)
192 * @param segmentSize3 The number of pixels covering dark pixels, with range [1, infinity)
193 * @param segmentSize4 The number of pixels covering bright pixels, with range [1, infinity)
194 * @param segmentSize5 The number of pixels covering dark pixels, with range [1, infinity)
195 * @return The threshold separating bright pixels from dark pixels, with range [0, 255], -1 if no valid threshold could be determined
196 */
197 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);
198
199 /**
200 * Checks whether a column contains a bullseye at a specified location.
201 * This function is simply checking for the same bullseye pattern in vertical direction (within a small window).
202 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
203 * @param xCenter The horizontal location within the frame at which the existence of the bullseye will be checked, in pixels, with range [0, yFrame.width())
204 * @param yCenter The vertical location within the frame at which the existence of the bullseye will be checked, in pixels, with range [0, yFrame.height())
205 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
206 * @param blackRingSegmentMin The minimal size (thickness) of the black ring, in pixels, with range [1, infinity)
207 * @param blackRingSegmentMax The maximal size (thickness) of the black ring, in pixels, with range [blackRingSegmentMin, infinity)
208 * @param whiteRingSegmentMin The minimal size (thickness) of the white ring, in pixels, with range [1, infinity)
209 * @param whiteRingSegmentMax The maximal size (thickness) of the white ring, in pixels, with range [whiteRingSegmentMin, infinity)
210 * @param dotSegmentMin The minimal size (thickness) of the black dot, in pixels, with range [1, infinity)
211 * @param dotSegmentMax The maximal size (thickness) of the black dot, in pixels, with range [dotSegmentMin, infinity)
212 * @return True, if the column contains a bullseye at the specified location
213 */
214 static bool checkBullseyeInColumn(const Frame& yFrame, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int blackRingSegmentMin, const unsigned int blackRingSegmentMax, const unsigned int whiteRingSegmentMin, const unsigned int whiteRingSegmentMax, const unsigned int dotSegmentMin, const unsigned int dotSegmentMax);
215
216 /**
217 * Checks whether the direct neighborhood contains a bullseye at a specified location.
218 * This function actually samples the neighborhood at sparse locations only instead of applying a dense check for the bullseye pattern.
219 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
220 * @param xCenter The horizontal location within the frame at which the existence of the bullseye will be checked, in pixels, with range [0, yFrame.width())
221 * @param yCenter The vertical location within the frame at which the existence of the bullseye will be checked, in pixels, with range [0, yFrame.height())
222 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
223 * @param whiteRingRadius The radius of the white ring (the center of this ring), in pixels, with range [1, infinity)
224 * @param blackRingRadius The radius of the black ring (the center of this ring), in pixels, with range [whiteRingRadius + 1, infinity)
225 * @param whiteBorderRadius The radius of the white border (the outer area around the black ring), in pixels, with range [blackRingRadius + 1, infinity)
226 * @return True, if the neighborhood contains a bullseye at the specified location
227 */
228 static bool checkBullseyeInNeighborhood(const Frame& yFrame, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const float whiteRingRadius, const float blackRingRadius, const float whiteBorderRadius);
229
230 /**
231 * Determines the sub-pixel location of the center dot of a known bullseye.
232 * @param yFrame The 8-bit grayscale frame in which the bullseye is located, must be valid
233 * @param xBullseye The horizontal location of the bullseye (the center location), the pixel must be black, with range [0, yFrame.width())
234 * @param yBullseye The vertical location of the bullseye (the center location), the pixel must be black, with range [0, yFrame.height())
235 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
236 * @param location The resulting sub-pixel location of the center of the bullseye
237 * @return True, if the sub-pixel location could be determined
238 */
239 static bool determineAccurateBullseyeLocation(const Frame& yFrame, const unsigned int xBullseye, const unsigned int yBullseye, const unsigned int threshold, Vector2& location);
240
241 protected:
242
243 /// The intensity threshold between two successive pixels to count as a transition from black to white (or vice versa).
244 static constexpr int deltaThreshold_ = 20;
245};
246
247} // namespace Bullseyes
248
249} // namespace Detector
250
251} // namespace CV
252
253} // namespace Ocean
254
255#endif // OCEAN_CV_DETECTOR_BULLSEYES_MONOBULLSEYEDETECTOR_H
This class implements the abstract base class for all AnyCamera objects.
Definition AnyCamera.h:130
This class holds the most important parameters for the detector.
Definition MonoBullseyeDetector.h:46
bool useAdaptiveRowSpacing_
Determines whether adaptive row spacing is used (true) or every row is scanned (false) during bullsey...
Definition MonoBullseyeDetector.h:101
bool isValid() const noexcept
Returns whether the parameters are valid.
Parameters()=default
Creates a new valid parameter object.
unsigned int framePyramidLayers_
The number of layers for the frame pyramid, with range [1, infinity)
Definition MonoBullseyeDetector.h:98
unsigned int framePyramidLayers() const noexcept
Returns the number of layers for the frame pyramid.
bool useAdaptiveRowSpacing() const noexcept
Returns whether adaptive row spacing is enabled during bullseye detection.
unsigned int framePyramidPixelThreshold() const noexcept
Returns the pixel threshold for frame pyramid creation.
unsigned int framePyramidPixelThreshold_
The pixel threshold for frame pyramid creation, with range [0, infinity)
Definition MonoBullseyeDetector.h:95
static Parameters defaultParameters() noexcept
Returns the default parameters for the detector.
void setUseAdaptiveRowSpacing(bool useAdaptiveRowSpacing) noexcept
Sets whether adaptive row spacing should be used during bullseye detection.
Implementation of a monocular detector for the bullseye pattern.
Definition MonoBullseyeDetector.h:39
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 ...
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 ...
static bool checkBullseyeInNeighborhood(const Frame &yFrame, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const float whiteRingRadius, const float blackRingRadius, const float whiteBorderRadius)
Checks whether the direct neighborhood contains a bullseye at a specified location.
static void detectBullseyesSubset(const AnyCamera *camera, const Frame *yFrame, Bullseyes *bullseyes, Lock *multiThreadLock, const bool useAdaptiveRowSpacing, const unsigned int firstRow, const unsigned int numberRows)
Detects bullseyes in a subset of a given 8-bit grayscale image.
static bool findNextLowerPixel(const Frame &yFrame, const unsigned int x, const unsigned int y, const unsigned int maximalRows, const unsigned int threshold, unsigned int &rows)
Finds either the next black or the next white pixel towards positive y direction (downwards in an ima...
static constexpr int deltaThreshold_
The intensity threshold between two successive pixels to count as a transition from black to white (o...
Definition MonoBullseyeDetector.h:244
static bool detectBullseyes(const AnyCamera &camera, const Frame &yFrame, Bullseyes &bullseyes, const Parameters &parameters=Parameters::defaultParameters(), Worker *worker=nullptr)
Detects bullseyes in a given 8-bit grayscale image.
static bool findNextUpperPixel(const Frame &yFrame, const unsigned int x, const unsigned int y, const unsigned int maximalRows, const unsigned int threshold, unsigned int &rows)
Finds either the next black or the next white pixel towards negative y direction (upwards in an image...
static bool checkBullseyeInColumn(const Frame &yFrame, const unsigned int xCenter, const unsigned int yCenter, const unsigned int threshold, const unsigned int blackRingSegmentMin, const unsigned int blackRingSegmentMax, const unsigned int whiteRingSegmentMin, const unsigned int whiteRingSegmentMax, const unsigned int dotSegmentMin, const unsigned int dotSegmentMax)
Checks whether a column contains a bullseye at a specified location.
static void detectBullseyesInRow(const AnyCamera &camera, const Frame &yFrame, const unsigned int y, Bullseyes &bullseyes)
Detects bullseyes in a row of a grayscale image.
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)
Determines the gray threshold separating bright pixels from dark pixels.
static bool determineAccurateBullseyeLocation(const Frame &yFrame, const unsigned int xBullseye, const unsigned int yBullseye, const unsigned int threshold, Vector2 &location)
Determines the sub-pixel location of the center dot of a known bullseye.
This class implements a simple history for previous pixel transitions (a sliding window of pixel tran...
Definition TransitionHistory.h:30
This class implements Ocean's image class.
Definition Frame.h:1808
This class implements a recursive lock object.
Definition Lock.h:31
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
std::vector< Bullseye > Bullseyes
Definition of a vector holding bullseyes.
Definition Bullseye.h:103
The namespace covering the entire Ocean framework.
Definition Accessor.h:15