Ocean
Loading...
Searching...
No Matches
BullseyeDetectorMono.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_BULLSEYEDETECTORMONO_H
9#define OCEAN_CV_DETECTOR_BULLSEYES_BULLSEYEDETECTORMONO_H
10
12
15
16#include "ocean/base/Frame.h"
17#include "ocean/base/Lock.h"
18#include "ocean/base/Worker.h"
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26namespace Detector
27{
28
29namespace Bullseyes
30{
31
32/**
33 * Implementation of a monocular detector for the bullseye pattern.
34 * @ingroup cvdetectorbullseyes
35 */
37{
38 public:
39
40 /**
41 * This class holds the most important parameters for the detector.
42 *
43 * Parameter Guide:
44 *
45 * framePyramidPixelThreshold:
46 * Controls when to use multi-scale detection via image pyramids.
47 * - Default: 640 * 480 = 307200 pixels (VGA resolution)
48 * - For images larger than this threshold, pyramid layers are used to detect bullseyes at multiple scales
49 * - Smaller values enable pyramid processing for smaller images (more thorough but slower)
50 * - Larger values disable pyramid processing for more images (faster but may miss small bullseyes)
51 *
52 * framePyramidLayers:
53 * Number of pyramid layers to use for multi-scale detection.
54 * - Default: 3 layers
55 * - More layers detect smaller bullseyes but increase computation time
56 * - Typical range: 2-4 layers
57 *
58 * useAdaptiveRowSpacing:
59 * Whether to skip rows during detection for better performance.
60 * - Default: true (enabled)
61 * - When enabled: Rows are skipped based on image height (height/150)
62 * - When disabled: Every row is scanned (slower but more accurate)
63 * - Recommended: true for real-time applications, false for offline/accuracy-critical applications
64 */
66 {
67 public:
68
69 /**
70 * Creates a new valid parameter object.
71 */
72 Parameters() = default;
73
74 /**
75 * Returns whether the parameters are valid.
76 * @return True if the parameters are valid
77 */
78 bool isValid() const noexcept;
79
80 /**
81 * Returns the pixel threshold for frame pyramid creation.
82 * @return The pixel threshold value, with range [0, infinity)
83 */
84 unsigned int framePyramidPixelThreshold() const noexcept;
85
86 /**
87 * Sets the pixel threshold for frame pyramid creation.
88 * @param framePyramidPixelThreshold The pixel threshold value, with range [0, infinity)
89 */
91
92 /**
93 * Returns the number of layers for the frame pyramid.
94 * @return The number of pyramid layers, with range [1, infinity)
95 */
96 unsigned int framePyramidLayers() const noexcept;
97
98 /**
99 * Sets the number of layers for the frame pyramid.
100 * @param framePyramidLayers The number of pyramid layers, with range [1, infinity)
101 */
102 void setFramePyramidLayers(unsigned int framePyramidLayers) noexcept;
103
104 /**
105 * Returns whether adaptive row spacing is enabled during bullseye detection.
106 * @return True if adaptive row spacing is used (performance optimization), false if every row is scanned (higher accuracy)
107 */
108 bool useAdaptiveRowSpacing() const noexcept;
109
110 /**
111 * Sets whether adaptive row spacing should be used during bullseye detection.
112 * When enabled (true), the detector uses adaptive row spacing based on frame height for better performance.
113 * When disabled (false), every row is scanned for higher accuracy but slower performance.
114 * @param useAdaptiveRowSpacing True to enable adaptive spacing, false to scan every row
115 */
117
118 /**
119 * Returns the default parameters for the detector.
120 * @return The default parameters
121 */
122 static Parameters defaultParameters() noexcept;
123
124 protected:
125
126 /// The pixel threshold for frame pyramid creation, with range [0, infinity)
127 unsigned int framePyramidPixelThreshold_ = 640u * 480u;
128
129 /// The number of layers for the frame pyramid, with range [1, infinity)
130 unsigned int framePyramidLayers_ = 3u;
131
132 /// Determines whether adaptive row spacing is used (true) or every row is scanned (false) during bullseye detection
134 };
135
136 public:
137
138 /**
139 * Detects bullseyes in a given 8-bit grayscale image.
140 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, with origin in the upper left corner, must be valid
141 * @param bullseyes The resulting detected bullseyes, will be appended to the end of the vector
142 * @param parameters The parameters for the detector, must be valid
143 * @param worker Optional worker to distribute the computation
144 * @return True, if succeeded
145 */
146 static bool detectBullseyes(const Frame& yFrame, Bullseyes& bullseyes, const Parameters& parameters = Parameters::defaultParameters(), Worker* worker = nullptr);
147
148 protected:
149
150 /**
151 * Detects bullseyes in a subset of a given 8-bit grayscale image.
152 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
153 * @param bullseyes The resulting bullseyes, will be added to the end of the vector
154 * @param multiThreadLock Lock object in case this function is executed in multiple threads concurrently, otherwise nullptr
155 * @param useAdaptiveRowSpacing True to use adaptive row spacing, false to scan every row
156 * @param firstRow The first row to be handled, with range [0, yFrame.height())
157 * @param numberRows The number of rows to be handled, with range [1, yFrame.height() - firstRow]
158 */
159 static void detectBullseyesSubset(const Frame* yFrame, Bullseyes* bullseyes, Lock* multiThreadLock, const bool useAdaptiveRowSpacing, const unsigned int firstRow, const unsigned int numberRows);
160
161 /**
162 * Detects bullseyes in a row of a grayscale image.
163 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
164 * @param y The index of the row in which the bullseyes will be detected, with range [0, yFrame.height())
165 * @param bullseyes The resulting detected bullseyes, will be added to the end of the vector
166 */
167 static void detectBullseyesInRow(const Frame& yFrame, const unsigned int y, Bullseyes& bullseyes);
168
169 /**
170 * Finds either the next black or the next white pixel towards negative y direction (upwards in an image).
171 * @param yFrame The 8-bit grayscale frame in which the pixel will be searched, must be valid
172 * @param x The horizontal location within the frame at which the search will be performed, in pixels, with range [0, yFrame.width())
173 * @param y The current vertical location within the image, with range [0, yFrame.height())
174 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, y]
175 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
176 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
177 * @return True, if the black or white pixel has been found within the specified range of [1, maximalRows]
178 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
179 */
180 template <bool tFindBlackPixel>
181 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);
182
183 /**
184 * Finds either the next black or the next white pixel towards positive y direction (downwards in an image).
185 * @param yFrame The 8-bit grayscale frame in which the pixel will be searched, must be valid
186 * @param x The horizontal location within the frame at which the search will be performed, in pixels, with range [0, yFrame.width())
187 * @param y The current vertical location within the image, with range [0, yFrame.height())
188 * @param maximalRows The maximal number of rows (vertical pixels) to travel, with range [1, yFrame.height() - y]
189 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
190 * @param rows The resulting number of rows that have been traveled until the black or white pixel has been found
191 * @return True, if the black or white pixel has been found within the specified range of [1, maximalRows]
192 * @tparam tFindBlackPixel True, to find the next black pixel; False, to find the next white pixel
193 */
194 template <bool tFindBlackPixel>
195 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);
196
197 /**
198 * Determines the gray threshold separating bright pixels from dark pixels.
199 * The threshold is based on actual pixel values for which the association is known already.
200 * The provided position is a pointer to any pixel within the image frame.
201 * In addition to the pixels covered by the five segments, pixels neighboring the segments are also used for estimation of the threshold.
202 * @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
203 * @param segmentSize1 The number of pixels covering dark pixels, with range [1, infinity)
204 * @param segmentSize2 The number of pixels covering bright pixels, with range [1, infinity)
205 * @param segmentSize3 The number of pixels covering dark pixels, with range [1, infinity)
206 * @param segmentSize4 The number of pixels covering bright pixels, with range [1, infinity)
207 * @param segmentSize5 The number of pixels covering dark pixels, with range [1, infinity)
208 * @return The threshold separating bright pixels from dark pixels, with range [0, 255], -1 if no valid threshold could be determined
209 */
210 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);
211
212 /**
213 * Checks whether a column contains a bullseye at a specified location.
214 * This function is simply checking for the same bullseye pattern in vertical direction (within a small window).
215 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
216 * @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())
217 * @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())
218 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
219 * @param blackRingSegmentMin The minimal size (thickness) of the black ring, in pixels, with range [1, infinity)
220 * @param blackRingSegmentMax The maximal size (thickness) of the black ring, in pixels, with range [blackRingSegmentMin, infinity)
221 * @param whiteRingSegmentMin The minimal size (thickness) of the white ring, in pixels, with range [1, infinity)
222 * @param whiteRingSegmentMax The maximal size (thickness) of the white ring, in pixels, with range [whiteRingSegmentMin, infinity)
223 * @param dotSegmentMin The minimal size (thickness) of the black dot, in pixels, with range [1, infinity)
224 * @param dotSegmentMax The maximal size (thickness) of the black dot, in pixels, with range [dotSegmentMin, infinity)
225 * @return True, if the column contains a bullseye at the specified location
226 */
227 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);
228
229 /**
230 * Checks whether the direct neighborhood contains a bullseye at a specified location.
231 * This function actually samples the neighborhood at sparse locations only instead of applying a dense check for the bullseye pattern.
232 * @param yFrame The 8-bit grayscale frame in which the bullseyes will be detected, must be valid
233 * @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())
234 * @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())
235 * @param threshold The grayscale threshold separating a bright pixel from a dark pixel, with range [0, 255]
236 * @param whiteRingRadius The radius of the white ring (the center of this ring), in pixels, with range [1, infinity)
237 * @param blackRingRadius The radius of the black ring (the center of this ring), in pixels, with range [whiteRingRadius + 1, infinity)
238 * @param whiteBorderRadius The radius of the white border (the outer area around the black ring), in pixels, with range [blackRingRadius + 1, infinity)
239 * @return True, if the neighborhood contains a bullseye at the specified location
240 */
241 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);
242
243 /**
244 * Determines the sub-pixel location of the center dot of a known bullseye.
245 * @param yFrame The 8-bit grayscale frame in which the bullseye is located, must be valid
246 * @param xBullseye The horizontal location of the bullseye (the center location), the pixel must be black, with range [0, yFrame.width())
247 * @param yBullseye The vertical location of the bullseye (the center location), the pixel must be black, with range [0, yFrame.height())
248 * @param threshold The threshold separating a bright pixel from a dark pixel, with range [0, 255]
249 * @param location The resulting sub-pixel location of the center of the bullseye
250 * @return True, if the sub-pixel location could be determined
251 */
252 static bool determineAccurateBullseyeLocation(const Frame& yFrame, const unsigned int xBullseye, const unsigned int yBullseye, const unsigned int threshold, Vector2& location);
253};
254
255} // namespace Bullseyes
256
257} // namespace Detector
258
259} // namespace CV
260
261} // namespace Ocean
262
263#endif // OCEAN_CV_DETECTOR_BULLSEYES_BULLSEYEDETECTORMONO_H
This class holds the most important parameters for the detector.
Definition BullseyeDetectorMono.h:66
void setFramePyramidLayers(unsigned int framePyramidLayers) noexcept
Sets the number of layers for the frame pyramid.
static Parameters defaultParameters() noexcept
Returns the default parameters for the detector.
bool useAdaptiveRowSpacing_
Determines whether adaptive row spacing is used (true) or every row is scanned (false) during bullsey...
Definition BullseyeDetectorMono.h:133
bool isValid() const noexcept
Returns whether the parameters are valid.
unsigned int framePyramidLayers_
The number of layers for the frame pyramid, with range [1, infinity)
Definition BullseyeDetectorMono.h:130
void setFramePyramidPixelThreshold(unsigned int framePyramidPixelThreshold) noexcept
Sets the pixel threshold for frame pyramid creation.
Parameters()=default
Creates a new valid parameter object.
unsigned int framePyramidLayers() const noexcept
Returns the number of layers for the frame pyramid.
unsigned int framePyramidPixelThreshold_
The pixel threshold for frame pyramid creation, with range [0, infinity)
Definition BullseyeDetectorMono.h:127
bool useAdaptiveRowSpacing() const noexcept
Returns whether adaptive row spacing is enabled during bullseye detection.
void setUseAdaptiveRowSpacing(bool useAdaptiveRowSpacing) noexcept
Sets whether adaptive row spacing should be used during bullseye detection.
unsigned int framePyramidPixelThreshold() const noexcept
Returns the pixel threshold for frame pyramid creation.
Implementation of a monocular detector for the bullseye pattern.
Definition BullseyeDetectorMono.h:37
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 detectBullseyesSubset(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 bool detectBullseyes(const Frame &yFrame, Bullseyes &bullseyes, const Parameters &parameters=Parameters::defaultParameters(), Worker *worker=nullptr)
Detects bullseyes in a given 8-bit grayscale image.
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.
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 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 detectBullseyesInRow(const Frame &yFrame, const unsigned int y, Bullseyes &bullseyes)
Detects bullseyes in a row of a grayscale image.
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