Ocean
Loading...
Searching...
No Matches
LineDetectorULF.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 META_OCEAN_CV_DETECTOR_LINE_DETECTOR_ULF_H
9#define META_OCEAN_CV_DETECTOR_LINE_DETECTOR_ULF_H
10
12
13#include "ocean/base/Memory.h"
14
17
19
20namespace Ocean
21{
22
23namespace CV
24{
25
26namespace Detector
27{
28
29/**
30 * This class implements a line detector optimized for urban lines (Urban Line Finder).
31 * @ingroup cvdetector
32 */
33class OCEAN_CV_DETECTOR_EXPORT LineDetectorULF
34{
35 public:
36
37 /**
38 * Definition of individual edge types.
39 */
40 enum EdgeType : uint8_t
41 {
42 /// No edge type.
43 ET_NONE = 0u,
44 /// A bar edge.
45 ET_BAR = 1u,
46 /// A step edge.
47 ET_STEP = 2u,
48 /// Positive sign edge; e.g., a bright bar edge.
49 ET_SIGN_POSITIVE = 4u,
50 /// Negative sign edge; e.g., a dark bar edge.
51 ET_SIGN_NEGATIVE = 8u,
52 /// A bar edge or a step edge.
53 ET_BAR_OR_STEP = ET_BAR | ET_STEP
54 };
55
56 /**
57 * Definition of scan direction of the line detection
58 */
59 enum ScanDirection : uint8_t
60 {
61 /// Scan only for vertical edges
62 SD_VERTICAL = 1u,
63 /// Scan only for horizontal edges
64 SD_HORIZONTAL = 2u,
65 /// Scan for vertical as well as horizontal edges
66 SD_VERTICAL_AND_HORIZONTAL = SD_VERTICAL | SD_HORIZONTAL
67 };
68
69 /**
70 * Definition of a vector holding edge types.
71 */
72 typedef std::vector<EdgeType> EdgeTypes;
73
74 public:
75
76 /**
77 * This class implements the almost abstract base class for all edge detectors.
78 * @see EdgeDetector::invoke().
79 */
80 class OCEAN_CV_DETECTOR_EXPORT EdgeDetector
81 {
82 public:
83
84 /**
85 * Destructor of an edge detector
86 */
87 virtual ~EdgeDetector() = default;
88
89 /**
90 * Returns the width of the sliding window in pixel, with range [1, infinity)
91 * @return The sliding window's width, in pixel, with range [1, infinity)
92 */
93 inline unsigned int window() const;
94
95 /**
96 * Returns the type of the edges this detector detects.
97 */
98 inline EdgeType edgeType() const;
99
100 /**
101 * Invokes the vertical edge detection for the entire frame.
102 * This function is guaranteed to exist in any EdgeDetector object.
103 * @param frame The 8bit grayscale frame on which the edge detection will be applied, must be valid
104 * @param width The width the given frame in pixel, with range [1, infinity)
105 * @param height The height of the given frame in pixel, with range [1, infinity)
106 * @param responses The pointer to the resulting response values one for each pixel, must be valid
107 * @param paddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
108 * @see invokeHorizontal().
109 */
110 virtual void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const = 0;
111
112 /**
113 * Invokes the horizontal edge detection for the entire frame.
114 * Beware: Not every EdgeDetector may implement this function, check whether the function is implemented before calling it.
115 * If this function is not implemented, transpose the input image and call invokeVertical() instead.
116 * @param frame The 8bit grayscale frame on which the edge detection will be applied, must be valid
117 * @param width The width the given frame in pixel, with range [1, infinity)
118 * @param height The height of the given frame in pixel, with range [1, infinity)
119 * @param responses The pointer to the resulting response values one for each pixel, must be valid
120 * @param paddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
121 * @return True, if succeeded
122 * @see hasInvokeHorizontal(), invokeVertical().
123 */
124 virtual bool invokeHorizontal(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const;
125
126 /**
127 * Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
128 * If the detector does not provide an implementation for horizontal edges, transpose the input image and call invokeVertical() instead of invokeHorizontal().
129 * @param width The width of the image to be handled, with range [0, infinity)
130 * @param height The height of the image to be handled, with range [0, infinity)
131 * @return True, if so; False, if no or if e.g., the image resolution is not suitable for the implementation
132 */
133 virtual bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const;
134
135 /**
136 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
137 * This function allows to specify one threshold parameter for any of the implemented detection algorithms.
138 * @param threshold The threshold to be adjusted, with range [0, infinity)
139 * @return The adjusted threshold matching with this detection algorithm
140 */
141 virtual unsigned int adjustThreshold(const unsigned int threshold) const;
142
143 /**
144 * Determines the sums of pixel intensities of sliding windows within a row of a frame.
145 * @param row The row for which the sums will be determined, must be valid
146 * @param width The width of the given row in pixel, with range [7 + window, infinity)
147 * @param window The width of the sliding window in pixel, with range [1, width]
148 * @param windowSums The resulting (width - window + 1) sums of intensities of the sliding windows, must be valid
149 */
150 static void determineRowSums(const uint8_t* row, const unsigned int width, const unsigned int window, uint32_t* windowSums);
151
152 /**
153 * Determines the sums of pixel intensities of sliding windows within a row of a frame.
154 * @param row The row for which the sums will be determined, must be valid
155 * @param width The width of the given row in pixel, with range [7 + window, infinity)
156 * @param window The width of the sliding window in pixel, with range [1, width]
157 * @param windowSums The resulting (width - window + 1) sums of intensities of the sliding windows, must be valid
158 */
159 static void determineRowSums(const uint8_t* row, const unsigned int width, const unsigned int window, uint16_t* windowSums);
160
161 /**
162 * Determines the sums of pixel intensities (and sums of squared pixel intensities) of sliding windows within a row of a frame.
163 * @param row The row for which the sums will be determined, must be valid
164 * @param width The width of the given row in pixel, with range [7 + window, infinity)
165 * @param window The width of the sliding window in pixel, with range [1, width]
166 * @param windowSums The resulting (width - window + 1) sums of intensities of the sliding windows, must be valid
167 * @param windowSqrSums The resulting (width - window + 1) sums of squared intensities of the sliding windows, must be valid
168 */
169 static void determineRowSums(const uint8_t* row, const unsigned int width, const unsigned int window, uint32_t* windowSums, uint32_t* windowSqrSums);
170
171 /**
172 * Determines the sums of pixel intensities (and sums of squared pixel intensities) of sliding windows within a row of a frame.
173 * @param row The row for which the sums will be determined, must be valid
174 * @param width The width of the given row in pixel, with range [7 + window, infinity)
175 * @param window The width of the sliding window in pixel, with range [1, min(width, 255)]
176 * @param windowSums The resulting (width - window + 1) sums of intensities of the sliding windows, must be valid
177 * @param windowSqrSums The resulting (width - window + 1) sums of squared intensities of the sliding windows, must be valid
178 */
179 static void determineRowSums(const uint8_t* row, const unsigned int width, const unsigned int window, uint16_t* windowSums, uint32_t* windowSqrSums);
180
181 /**
182 * Either adds or subtracts one row from the sum and square sum buffers.
183 * @param row The row which will be added or subtracted, must be valid
184 * @param width The width of the row, in pixel, with range [1, infinity)
185 * @param sum The sum values to which the row will be added or from which the row will be subtracted, must be valid
186 * @tparam tAdd True, to add the row to the sum values; False, to subtract the row values from the sum values
187 */
188 template <bool tAdd>
189 static void applyRowSum(const uint8_t* row, const unsigned int width, uint16_t* sum);
190
191 /**
192 * Either adds or subtracts one row from the sum and square sum buffers.
193 * @param row The row which will be added or subtracted, must be valid
194 * @param width The width of the row, in pixel, with range [1, infinity)
195 * @param sum The sum values to which the row will be added or from which the row will be subtracted, must be valid
196 * @param sqrSum The square sum values, to which the row will be added or from which the row will be subtracted, must be valid
197 * @tparam tAdd True, to add the row to the sum values; False, to subtract the row values from the sum values
198 */
199 template <bool tAdd>
200 static void applyRowSum(const uint8_t* row, const unsigned int width, uint16_t* sum, uint32_t* sqrSum);
201
202 protected:
203
204 /**
205 * Protected default constructor.
206 * @param window The width of the sliding window in pixel, with range [1, infinity)
207 * @param edgeType The type of the edge detector
208 */
209 inline EdgeDetector(const unsigned int window, const EdgeType edgeType);
210
211 protected:
212
213 /// The width of the sliding window in pixel, with range [1, infinity)
214 const unsigned int window_;
215
216 // The type of the edges this detector detects.
218 };
219
220 /**
221 * Definition of a vector holding edge detectors.
222 */
223 typedef std::vector<std::shared_ptr<EdgeDetector>> EdgeDetectors;
224
225 /**
226 * This class implements an integer-based bar edge detector based on root mean square residuals.
227 * @see RMSBarEdgeDetectorF.
228 */
229 class OCEAN_CV_DETECTOR_EXPORT RMSBarEdgeDetectorI : public EdgeDetector
230 {
231 protected:
232
233 /// The bar size of this detector.
234 static constexpr unsigned int barSize_ = 3u;
235
236 public:
237
238 /**
239 * Create a new edge detector object.
240 * @param window The window size which will be applied for detection, with range [1, width]
241 * @param minimalDelta The minimal intensity delta between average and center pixel, with range [0, 255]
242 */
243 explicit RMSBarEdgeDetectorI(const unsigned int window = 4u, const unsigned int minimalDelta = barDetectorMinimalDelta());
244
245 /**
246 * Invokes the vertical edge detection for the entire frame.
247 * @param frame The frame for which the edge detection will be applied, must be valid
248 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
249 * @param height The height of the given image in pixel, with range [1, infinity)
250 * @param responses The resulting response values, one for each row pixel, must be valid
251 * @param framePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
252 * @see EdgeDetector::invokeVertical().
253 */
254 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int framePaddingElements) const override;
255
256 /**
257 * Invokes the horizontal edge detection for the entire frame.
258 * Beware: Not every EdgeDetector may implement this function, check whether the function is implemented before calling it.
259 * If this function is not implemented, transpose the input image and call invokeVertical() instead.
260 * @param frame The 8bit grayscale frame on which the edge detection will be applied, must be valid
261 * @param width The width the given frame in pixel, with range [1, infinity)
262 * @param height The height of the given frame in pixel, with range [1, infinity)
263 * @param responses The pointer to the resulting response values one for each pixel, must be valid
264 * @param paddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
265 * @return True, if succeeded
266 * @see EdgeDetector::invokeHorizontal().
267 */
268 bool invokeHorizontal(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const override;
269
270 /**
271 * Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
272 * @see EdgeDetector::hasInvokeHorizontal().
273 */
274 bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override;
275
276 /**
277 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
278 * @see EdgeDetection::adjustThreshold().
279 */
280 unsigned int adjustThreshold(const unsigned int threshold) const override;
281
282 /**
283 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
284 * This function is just the static version of adjustThreshold().
285 * @see EdgeDetection::adjustThreshold().
286 */
287 static inline unsigned int staticAdjustThreshold(const unsigned int threshold);
288
289 /**
290 * Invokes the vertical edge detection in one row of the input frame.
291 * @param row The row for which the edge detection will be applied, must be valid
292 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
293 * @param window The window size which will be applied for detection, with range [1, 11]
294 * @param minimalDelta The minimal intensity delta between average and center pixel, with range [0, 255]
295 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid
296 * @param windowSqrSums The (width - window + 1) sums of squared pixel intensities of the sliding window, must be valid
297 * @param sqrResponses The resulting (squared) response values, one for each row pixel, must be valid
298 */
299 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int window, const unsigned int minimalDelta, const uint16_t* const windowSums, const uint32_t* const windowSqrSums, int16_t* sqrResponses);
300
301 /**
302 * Returns a vector containing just this edge detector with shared pointer (to simplify the usage with detectLines()).
303 * @param window The window size which will be applied for detection, with range [1, width]
304 * @param minimalDelta The minimal intensity delta between average and center pixel, with range [0, 255]
305 * @return This edge detector in a vector
306 */
307 static inline EdgeDetectors asEdgeDetectors(const unsigned int window = 4u, const unsigned int minimalDelta = barDetectorMinimalDelta());
308
309 protected:
310
311 /// The minimal intensity delta between average and center pixel, with range [0, 255].
312 const unsigned int minimalDelta_;
313 };
314
315 /**
316 * This class implements an integer-based bar step detector based on root mean square residuals.
317 */
318 class OCEAN_CV_DETECTOR_EXPORT RMSStepEdgeDetectorI : public EdgeDetector
319 {
320 protected:
321
322 /// The step size of this detector.
323 static constexpr unsigned int stepSize_ = 1u;
324
325 public:
326
327 /**
328 * Create a new edge detector object.
329 * @param window The window size which will be applied for detection, with range [1, width]
330 */
331 explicit RMSStepEdgeDetectorI(const unsigned int window = 4u);
332
333 /**
334 * Invokes the vertical edge detection for the entire frame.
335 * @param frame The frame for which the edge detection will be applied, must be valid
336 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
337 * @param height The height of the given image in pixel, with range [1, infinity)
338 * @param responses The resulting response values, one for each row pixel, must be valid
339 * @param framePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
340 * @see EdgeDetector::invokeVertical().
341 */
342 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int framePaddingElements) const override;
343
344 /**
345 * Invokes the horizontal edge detection for the entire frame.
346 * Beware: Not every EdgeDetector may implement this function, check whether the function is implemented before calling it.
347 * If this function is not implemented, transpose the input image and call invokeVertical() instead.
348 * @param frame The 8bit grayscale frame on which the edge detection will be applied, must be valid
349 * @param width The width the given frame in pixel, with range [1, infinity)
350 * @param height The height of the given frame in pixel, with range [1, infinity)
351 * @param responses The pointer to the resulting response values one for each pixel, must be valid
352 * @param paddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
353 * @return True, if succeeded
354 * @see hasInvokeHorizontal(), invokeVertical().
355 */
356 bool invokeHorizontal(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const override;
357
358 /**
359 * Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
360 * @see EdgeDetector::hasInvokeHorizontal().
361 */
362 bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override;
363
364 /**
365 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
366 * @see EdgeDetection::adjustThreshold().
367 */
368 unsigned int adjustThreshold(const unsigned int threshold) const override;
369
370 /**
371 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
372 * This function is just the static version of adjustThreshold().
373 * @see EdgeDetection::adjustThreshold().
374 */
375 static inline unsigned int staticAdjustThreshold(const unsigned int threshold);
376
377 /**
378 * Invokes the vertical edge detection in one row of the input frame.
379 * @param row The row for which the edge detection will be applied, must be valid
380 * @param width The width of the given row in pixel, with range [8 + window * 2, infinity)
381 * @param window The window size which will be applied for detection, with range [1, min(width, 8)]
382 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid
383 * @param windowSqrSums The (width - window + 1) sums of squared pixel intensities of the sliding window, must be valid
384 * @param sqrResponses The resulting (squared) response values, one for each row pixel, must be valid
385 */
386 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int window, const uint16_t* const windowSums, const uint32_t* const windowSqrSums, int16_t* sqrResponses);
387
388 /**
389 * Returns a vector containing just this edge detector with shared pointer (to simplify the usage with detectLines()).
390 * @param window The window size which will be applied for detection, with range [1, width]
391 * @return This edge detector in a vector
392 */
393 static inline EdgeDetectors asEdgeDetectors(const unsigned int window = 4u);
394 };
395
396 /**
397 * This class implements a floating-point-based bar edge detector based on root mean square residuals.
398 * The edge response is defined by:
399 * <pre>
400 * (peakValue - mean) / rms
401 * rms = sqrt(1/n * sum[(mean - yi)^2])
402 * </pre>
403 * Actually, this class mainly covers the original implementation of ULF's bar edge detector.
404 * @see RMSBarEdgeDetectorI.
405 */
406 class OCEAN_CV_DETECTOR_EXPORT RMSBarEdgeDetectorF : public EdgeDetector
407 {
408 public:
409
410 /**
411 * Create a new edge detector object.
412 * @param window The window size which will be applied for detection, with range [1, width]
413 * @param minimalDelta The minimal intensity delta between average and center pixel, with range [0, 255]
414 */
415 explicit RMSBarEdgeDetectorF(const unsigned int window = 4u, const unsigned int minimalDelta = barDetectorMinimalDelta());
416
417 /**
418 * Invokes the vertical edge detection for the entire frame.
419 * @see EdgeDetector::invokeVertical().
420 */
421 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const override;
422
423 /**
424 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
425 * @see EdgeDetection::adjustThreshold().
426 */
427 unsigned int adjustThreshold(const unsigned int threshold) const override;
428
429 /**
430 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
431 * This function is just the static version of adjustThreshold().
432 * @see EdgeDetection::adjustThreshold().
433 */
434 static inline unsigned int staticAdjustThreshold(const unsigned int threshold);
435
436 /**
437 * Invokes the vertical edge detection in one row of the input frame.
438 * @param row The row for which the edge detection will be applied, must be valid
439 * @param width The width of the given row in pixel, with range [1, infinity)
440 * @param window The window size which will be applied for detection, with range [1, width]
441 * @param minimalDelta The minimal intensity delta between average and center pixel, with range [0, 255]
442 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid
443 * @param windowSqrSums The (width - window + 1) sums of squared pixel intensities of the sliding window, must be valid
444 * @param sqrResponses The resulting (squared) response values, one for each row pixel, must be valid
445 */
446 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int window, const unsigned int minimalDelta, const uint32_t* const windowSums, const uint32_t* const windowSqrSums, int16_t* sqrResponses);
447
448 protected:
449
450 /// The minimal intensity delta between average and center pixel, with range [0, 255].
451 const unsigned int minimalDelta_;
452 };
453
454 /**
455 * This class implements a floating-point-based bar step detector based on root mean square residuals.
456 */
457 class OCEAN_CV_DETECTOR_EXPORT RMSStepEdgeDetectorF : public EdgeDetector
458 {
459 public:
460
461 /**
462 * Create a new edge detector object.
463 * @param window The window size which will be applied for detection, with range [1, width]
464 */
465 explicit RMSStepEdgeDetectorF(const unsigned int window = 4u);
466
467 /**
468 * Invokes the vertical edge detection for the entire frame.
469 * @see EdgeDetector::invokeVertical().
470 */
471 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const override;
472
473 /**
474 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
475 * @see EdgeDetection::adjustThreshold().
476 */
477 unsigned int adjustThreshold(const unsigned int threshold) const override;
478
479 /**
480 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
481 * This function is just the static version of adjustThreshold().
482 * @see EdgeDetection::adjustThreshold().
483 */
484 static inline unsigned int staticAdjustThreshold(const unsigned int threshold);
485
486 /**
487 * Invokes the vertical edge detection in one row of the input frame.
488 * @param row The row for which the edge detection will be applied, must be valid
489 * @param width The width of the given row in pixel, with range [1, infinity)
490 * @param window The window size which will be applied for detection, with range [1, width]
491 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid
492 * @param windowSqrSums The (width - window + 1) sums of squared pixel intensities of the sliding window, must be valid
493 * @param sqrResponses The resulting (squared) response values, one for each row pixel, must be valid
494 */
495 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int window, const uint32_t* const windowSums, const uint32_t* const windowSqrSums, int16_t* sqrResponses);
496 };
497
498 /**
499 * This class implements an integer-based bar edge detector based on averaged differences.
500 */
501 class OCEAN_CV_DETECTOR_EXPORT ADBarEdgeDetectorI : public EdgeDetector
502 {
503 public:
504
505 /**
506 * Create a new edge detector object.
507 * @param window The window size which will be applied for detection, with range [1, width]
508 */
509 explicit ADBarEdgeDetectorI(const unsigned int window = 4u);
510
511 /**
512 * Invokes the vertical edge detection for the entire frame.
513 * @param frame The frame for which the edge detection will be applied, must be valid
514 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
515 * @param height The height of the given image in pixel, with range [1, infinity)
516 * @param responses The resulting response values, one for each row pixel, must be valid
517 * @param framePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
518 * @see EdgeDetector::invokeVertical().
519 */
520 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int framePaddingElements) const override;
521
522 /**
523 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
524 * @see EdgeDetection::adjustThreshold().
525 */
526 unsigned int adjustThreshold(const unsigned int threshold) const override;
527
528 /**
529 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
530 * This function is just the static version of adjustThreshold().
531 * @see EdgeDetection::adjustThreshold().
532 */
533 static inline unsigned int staticAdjustThreshold(const unsigned int threshold);
534
535 /**
536 * Invokes the vertical edge detection in one row of the input frame.
537 * @param row The row for which the edge detection will be applied, must be valid
538 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
539 * @param window The window size which will be applied for detection, with range [1, width]
540 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid
541 * @param responses The resulting response values, one for each row pixel, must be valid
542 */
543 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int window, const uint32_t* const windowSums, int16_t* responses);
544
545 /**
546 * Returns a vector containing just this edge detector with shared pointer (to simplify the usage with detectLines()).
547 * @param window The window size which will be applied for detection, with range [1, width]
548 * @return This edge detector in a vector
549 */
550 static inline EdgeDetectors asEdgeDetectors(const unsigned int window = 4u);
551 };
552
553 /**
554 * This class implements an integer-based (sum difference) step edge detector that computes the difference of two fixed-size sliding window of width 2.
555 * The edge response is defined by:
556 * <pre>
557 * peakValue = leftWindow - rightWindow
558 * </pre>
559 */
560 class OCEAN_CV_DETECTOR_EXPORT SDStepEdgeDetectorI : public EdgeDetector
561 {
562 public:
563
564 /**
565 * Create a new edge detector object.
566 * @param window The window size which will be applied for detection, with range [1, min(width, 127)]
567 * @param stepSize The number of pixels between both windows sums, "should be odd", "should" have range [1, infinity)
568 */
569 explicit SDStepEdgeDetectorI(const unsigned int window = 2u, const unsigned int stepSize = 1u);
570
571 /**
572 * Invokes the vertical edge detection for the entire frame.
573 * @param frame The frame for which the edge detection will be applied, must be valid
574 * @param width The width of the given row in pixel, with range [8 + (window + 1) * 2, infinity)
575 * @param height The height of the given image in pixel, with range [1, infinity)
576 * @param responses The resulting response values, one for each row pixel, must be valid
577 * @param framePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
578 * @see EdgeDetector::invokeVertical().
579 */
580 void invokeVertical(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int framePaddingElements) const override;
581
582 /**
583 * Invokes the horizontal edge detection for the entire frame.
584 * @see EdgeDetector::invokeHorizontal().
585 */
586 bool invokeHorizontal(const uint8_t* frame, const unsigned int width, const unsigned int height, int16_t* responses, const unsigned int paddingElements) const override;
587
588 /**
589 * Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
590 * @see EdgeDetector::hasInvokeHorizontal().
591 */
592 bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override;
593
594 /**
595 * Adjusts the edge detection threshold (which is specified independently of the applied edge detection algorithm) so that it matches with the detection algorithm of this detector.
596 * @see EdgeDetection::adjustThreshold().
597 */
598 unsigned int adjustThreshold(const unsigned int threshold) const override;
599
600 /**
601 * Returns a vector containing just this edge detector with shared pointer (to simplify the usage with detectLines()).
602 * @param window The window size which will be applied for detection, with range [1, width]
603 * @param stepSize The number of pixels between both windows sums, "should be odd", "should" have range [1, infinity)
604 * @return This edge detector in a vector
605 */
606 static inline EdgeDetectors asEdgeDetectors(const unsigned int window = 2u, const unsigned int stepSize = 1u);
607
608 protected:
609
610 /**
611 * Invokes the vertical edge detection in one row of the input image with a fixed window width of 2 pixels
612 * Note this function only computes the difference between a left and a right window.
613 * @param row The row for which the edge detection will be applied, must be valid
614 * @param width The width of the given row in pixel, with range [8 + window * 2, infinity)
615 * @param stepSize The number of pixels between both windows sums, "should be odd", "should" have range [1, infinity)
616 * @param window The window size which will be applied for detection, with range [1, min(width, 127)]
617 * @param windowSums The (width - window + 1) sums of pixel intensities of the sliding window, must be valid for window >= 3
618 * @param responses The resulting response values (not squared!), one for each row pixel, must be valid
619 */
620 static void invokeRowVertical(const uint8_t* const row, const unsigned int width, const unsigned int stepSize, const unsigned int window, const uint16_t* const windowSums, int16_t* responses);
621
622 protected:
623
624 /// The number of pixels between both windows sums, "should be odd", "should" have range [1, infinity).
625 const unsigned int stepSize_;
626 };
627
628 public:
629
630 /**
631 * Returns ULF's two default edge detectors.
632 * The two default edge detectors are: RMSBarEdgeDetectorI, RMSStepEdgeDetectorI.
633 * @param window The window size which will be applied for detection, with range [1, width]
634 * @return The two default edge detectors
635 * @see performanceEdgeDetectors().
636 */
637 static inline EdgeDetectors defaultEdgeDetectors(const unsigned int window = 4u);
638
639 /**
640 * Returns ULF's two high performance edge detectors.
641 * The two performance edge detectors are: ADBarEdgeDetectorI, SDStepEdgeDetectorI.
642 * Compared to ULF's defaultEdgeDetectors() the performance detectors are significantly faster, but will detect less lines.
643 * @param window The window size which will be applied for detection, with range [1, width]
644 * @return The two default edge detectors
645 * see defaultEdgeDetectors().
646 */
647 static inline EdgeDetectors performanceEdgeDetectors(const unsigned int window = 4u);
648
649 /**
650 * Detects finite lines within a given 8bit grayscale image.
651 * @param yFrame The image in which the lines will be detected, must be valid
652 * @param width The width of the given image in pixel, with range [20, infinity)
653 * @param height The height of the given image in pixel, with range [20, infinity)
654 * @param framePaddingElements The number of padding elements at the end of each image row, in elements, with range [0, infinity)
655 * @param edgeDetectors The edge detectors which will be used to detect the lines, at least one
656 * @param threshold The detection threshold to be used to distinguish between weak and strong lines, the higher the threshold, the stronger the detected lines, with range [0, infinity)
657 * @param minimalLength The minimal length an extracted line must have in pixel, with range [2, infinity)
658 * @param maximalStraightLineDistance The maximal distance between the ideal line and every pixel on actual extracted line in pixel, with range [0, infinity)
659 * @param types Optional resulting types of the individual resulting lines, one type for each line
660 * @param scanDirection The scan direction(s) to be applied
661 * @return The detected lines
662 * @see defaultEdgeDetectors().
663 */
664 static FiniteLines2 detectLines(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const EdgeDetectors& edgeDetectors = defaultEdgeDetectors(), const unsigned int threshold = 50u, const unsigned int minimalLength = 20u, const float maximalStraightLineDistance = 1.6f, EdgeTypes* types = nullptr, const ScanDirection scanDirection = SD_VERTICAL_AND_HORIZONTAL);
665
666 protected:
667
668 /**
669 * Extracts straight vertical (+/- 45 degree) finite lines from a given frame with edge responses.
670 * This function supports positive and negative response values and extracts individual lines for negative and positive responses.<br>
671 * For negative response values, the negative thresholds are applied.<br>
672 * This function follows strong responses in vertical direction and is converted the determined seam into one or several finite lines.<br>
673 * The seam is separated into several individual finite lines in case the distance of a seam pixel to the ideal line exceed a threshold.<br>
674 * Note: This function can extract horizontal finite lines if the given input response frame is transposed.
675 * @param responses The frame with edge responses from which the lines will be extracted, must be valid
676 * @param width The width of the given frame in pixels, with range [1, infinity)
677 * @param height The height of the given frame in pixels, with range [1, infinity)
678 * @param paddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
679 * @param transposed True, to create transposes line coordinates (e.g., if the given response frame is transposed)
680 * @param lines The resulting finite lines all fitting within the range [0, width - 1]x[0, height - 1]
681 * @param minimalStartThreshold The minimal (positive) threshold a response value must have to start the line extraction at this location, with range [1, infinity)
682 * @param minimalIntermediateThreshold The minimal (positive) threshold a response value must have once the line extraction has been started, with range [1, minimalStartThreshold]
683 * @param minimalLength The minimal length an extracted line must have in pixel, with range [2, infinity)
684 * @param maximalStraightLineDistance The maximal distance between the ideal line and every pixel on actual extracted line in pixel, with range [0, infinity)
685 * @param types Optional resulting types of the individual resulting lines, one type for each line
686 */
687 template <typename T>
688 static void extractVerticalLines(T* const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const bool transposed, FiniteLines2& lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength = 20u, const float maximalStraightLineDistance = 1.6f, EdgeTypes* types = nullptr);
689
690 /**
691 * Extracts straight horizontal (+/- 45 degree) finite lines from a given frame with edge responses.
692 * This function supports positive and negative response values and extracts individual lines for negative and positive responses.<br>
693 * For negative response values, the negative thresholds are applied.<br>
694 * This function follows strong responses in horizontal direction and is converted the determined seam into one or several finite lines.<br>
695 * The seam is separated into several individual finite lines in case the distance of a seam pixel to the ideal line exceed a threshold.<br>
696 * Note: This function can extract horizontal finite lines if the given input response frame is transposed.
697 * @param responses The frame with edge responses from which the lines will be extracted, must be valid
698 * @param width The width of the given frame in pixels, with range [1, infinity)
699 * @param height The height of the given frame in pixels, with range [1, infinity)
700 * @param paddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
701 * @param lines The resulting finite lines all fitting within the range [0, width - 1]x[0, height - 1]
702 * @param minimalStartThreshold The minimal (positive) threshold a response value must have to start the line extraction at this location, with range [1, infinity)
703 * @param minimalIntermediateThreshold The minimal (positive) threshold a response value must have once the line extraction has been started, with range [1, minimalStartThreshold]
704 * @param minimalLength The minimal length an extracted line must have in pixel, with range [2, infinity)
705 * @param maximalStraightLineDistance The maximal distance between the ideal line and every pixel on actual extracted line in pixel, with range [0, infinity)
706 * @param types Optional resulting types of the individual resulting lines, one type for each line
707 */
708 template <typename T>
709 static void extractHorizontalLines(T* const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, FiniteLines2& lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength = 20u, const float maximalStraightLineDistance = 1.6f, EdgeTypes* types = nullptr);
710
711 /**
712 * Follows an edge in vertical direction while applying a horizontal search radius with one pixel (-1, 0, +1), to determine a seam of edge pixels.
713 * Each edge response value must exceed a specified threshold so that the edge continues.<br>
714 * Visited response values will be set to zero ensuring that we do not use the response again for another edge.<br>
715 * The function will return a connected list of pixel coordinates representing the found edge.<br>
716 * The scheme of the function is depicted below:
717 * <pre>
718 * Previous row n-1: - - - - - ? ? ? - - - - (for tVerticalDirection = -1)
719 * Current row n - - - - - - x - - - - -
720 * Next row n+1 - - - - - ? ? ? - - - - (for tVerticalDirection = +1)
721 *
722 * with '?' candidate response values
723 * </pre>
724 * In case two or move response candidates exceed the threshold and have an equal value, the selection order is: center (0), left (-1), right (+1).
725 * @param data The frame with edge responses in which the edge will be followed, must be valid
726 * @param width The width of the given frame in pixels, with range [1, infinity)
727 * @param height The height of the given frame in pixels, with range [1, infinity)
728 * @param x The horizontal location at which the following process will start, with range [0, width - 1]
729 * @param y The vertical location at which the following process will start, with range [0, height - 1]
730 * @param threshold The threshold every edge response must exceed to count as edge
731 * @param pixelPositionsX The buffer of possible horizontal pixel locations for the resulting edge, the buffer must provide 'height' pixel locations
732 * @param paddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
733 * @return The last valid vertical pixel position, with range [0, height - 1]
734 * @tparam T The data type of the response value (and threshold value)
735 * @tparam tPositiveThreshold True, if the threshold is positive; False, if the threshold is negative
736 * @tparam tVerticalDirection 1 in case the edge should be followed towards positive y direction; -1 in case the edge should be followed towards negative y direction
737 * @see followEdgeVerticalBranchFree().
738 */
739 template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
740 static unsigned int followEdgeVertical(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsX, const unsigned int paddingElements);
741
742 /**
743 * Follows an edge in horizontal direction while applying a vertical search radius with one pixel (-1, 0, +1), to determine a seam of edge pixels.
744 * Each edge response value must exceed a specified threshold so that the edge continues.<br>
745 * Visited response values will be set to zero ensuring that we do not use the response again for another edge.<br>
746 * The function will return a connected list of pixel coordinates representing the found edge.<br>
747 * In case two or move response candidates exceed the threshold and have an equal value, the selection order is: center (0), left (-1), right (+1).
748 * @param data The frame with edge responses in which the edge will be followed, must be valid
749 * @param width The width of the given frame in pixels, with range [1, infinity)
750 * @param height The height of the given frame in pixels, with range [1, infinity)
751 * @param x The horizontal location at which the following process will start, with range [0, width - 1]
752 * @param y The vertical location at which the following process will start, with range [0, height - 1]
753 * @param threshold The threshold every edge response must exceed to count as edge
754 * @param pixelPositionsY The buffer of possible vertical pixel locations for the resulting edge, the buffer must provide 'width' pixel locations
755 * @param paddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
756 * @return The last valid horizontal pixel position, with range [0, width - 1]
757 * @tparam T The data type of the response value (and threshold value)
758 * @tparam tPositiveThreshold True, if the threshold is positive; False, if the threshold is negative
759 * @tparam tHorizontalDirection 1 in case the edge should be followed towards positive x direction; -1 in case the edge should be followed towards negative x direction
760 */
761 template <typename T, const bool tPositiveThreshold, const int tHorizontalDirection>
762 static unsigned int followEdgeHorizontal(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsY, const unsigned int paddingElements);
763
764 /**
765 * Follows an edge in vertical direction while applying a horizontal search radius with one pixel (-1, 0, +1).
766 * This function is similar to 'followEdgeVertical' while avoiding branches as best as possible.<br>
767 * In general, this function should be faster than `followEdgeVertical`.
768 * @param data The frame with edge responses in which the edge will be followed, must be valid
769 * @param width The width of the given frame in pixels, with range [1, infinity)
770 * @param height The height of the given frame in pixels, with range [1, infinity)
771 * @param x The horizontal location at which the following process will start, with range [0, width - 1]
772 * @param y The vertical location at which the following process will start, with range [0, height - 1]
773 * @param threshold The threshold every edge response must exceed to count as edge
774 * @param pixelPositionsX The buffer of possible pixel positions for the resulting edge, the buffer must provide 'height' pixel positions
775 * @param paddingElements The number of padding elements at the end of each response row, in elements, with range [0, infinity)
776 * @tparam T The data type of the response value (and threshold value)
777 * @tparam tPositiveThreshold True, if the threshold is positive; False, if the threshold is negative
778 * @tparam tVerticalDirection 1 in case the edge should be followed towards positive y direction; -1 in case the edge should be followed towards negative y direction
779 * @see followEdgeVertical().
780 */
781 template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
782 static unsigned int followEdgeVerticalBranchFree(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsX, const unsigned int paddingElements);
783
784 /**
785 * Separates a set of connected pixels (almost defining a straight line) into individual perfect straight lines.
786 * @param pixelPositionsMajor The buffer of major pixel positions defining the connected pixels, must be valid
787 * @param firstPositionIndex The index within the given buffer 'pixelPositions' at which the set of connected pixels start, with range [0, infinity)
788 * @param lastPositionIndex The index within the given buffer 'pixelPositions' at which the set of connected pixels end (including position), with range [firstPositionIndex, infinity)
789 * @param lines The resulting separated straight lines, all separated lines will be added to the end of the given vector
790 * @param minimalLength The minimal length a separated straight line must have to be added, with range [2, infinity)
791 * @param maximalOffset The maximal distance/offset between a perfect line and the actual pixel so that a pixel counts as inlier for the line, in pixels, with range [0, infinity)
792 * @param majorIsY True, if the y-axis is the major axis; False, if the x-axis is the major axis
793 * @param refine True, to apply a non linear least square fit for the resulting lines; False, to use the pixel locations as actual end points of the resulting lines
794 */
795 static void separateStraightLines(const unsigned int* pixelPositionsMajor, const unsigned int firstPositionIndex, const unsigned int lastPositionIndex, FiniteLines2& lines, const unsigned int minimalLength, const float maximalOffset, const bool majorIsY, const bool refine);
796
797 /**
798 * Detects lines by applying a given edge detector for an image in horizontal and vertical direction.
799 * In case, the transposed image is not provided, horizontal lines will not be detected.
800 * @param yFrame The 8 bit grayscale frame in which the lines will be detected, which will be used to detect vertical lines, must be valid
801 * @param yFrameTransposedMemory The memory for the transposed frame, will be used if valid, otherwise will be created if necessary
802 * @param width The width of the given (normal) frame in pixels, with range [1, infinity)
803 * @param height The height of the given (normal) frame in pixels, with range [1, infinity)
804 * @param yFramePaddingElements The number of padding elements at the end of each row of the normal frame, with range [0, infinity)
805 * @param yFrameTransposedMemoryPaddingElements The number of padding elements at the end of each row of the transposed frame, with range [0, infinity)
806 * @param edgeDetector The edge detector to be used for line detection
807 * @param detectedLines The resulting lines that are detected, all detected lines will be added to the end of the given vector
808 * @param scanDirection The scan directions to be applied
809 * @param threshold The threshold all detected lines will exceed (at least at one location in the image), with range [1, infinity)
810 * @param reusableResponseBuffer Optional response buffer that can be used within this function, with one response value for each frame pixel, otherwise nullptr so that the function will create an own temporary buffer
811 * @param minimalLength The minimal length an extracted line must have in pixel, with range [2, infinity)
812 * @param maximalStraightLineDistance The maximal distance between the ideal line and every pixel on actual extracted line in pixel, with range [0, infinity)
813 * @param types Optional resulting types of the individual resulting lines, one type for each line
814 * @return True, if succeeded
815 */
816 static bool detectLines(const uint8_t* const yFrame, Memory& yFrameTransposedMemory, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, unsigned int& yFrameTransposedMemoryPaddingElements, const EdgeDetector& edgeDetector, FiniteLines2& detectedLines, const ScanDirection scanDirection, const unsigned int threshold = 50u, int16_t* reusableResponseBuffer = nullptr, const unsigned int minimalLength = 20u, const float maximalStraightLineDistance = 1.6f, EdgeTypes* types = nullptr);
817
818 /**
819 * Returns whether a given value is larger than or equal to a given threshold (or smaller than or equal to a given threshold).
820 * @param value The value to compare
821 * @param threshold The threshold to be used
822 * @return True, if value >= threshold && tPositiveThreshold, or value <= tPositiveThreshold && !tPositiveThreshold
823 * @tparam T The data type of the value and threshold
824 * @tparam tPositiveThreshold True, if the threshold is positive; False, if the threshold is negative
825 */
826 template <typename T, const bool tPositiveThreshold>
827 static inline bool valueMatchesThreshold(const T& value, const T& threshold);
828
829 /**
830 * The threshold for the minimal delta for bar detectors.
831 * @return The threshold value
832 */
833 static constexpr unsigned int barDetectorMinimalDelta();
834
835};
836
837inline LineDetectorULF::EdgeDetector::EdgeDetector(const unsigned int window, const EdgeType edgeType) :
838 window_(window),
839 edgeType_(edgeType)
840{
841 // nothing to do here
842}
843
844inline unsigned int LineDetectorULF::EdgeDetector::window() const
845{
846 return window_;
847}
848
850{
851 return edgeType_;
852}
853
854inline unsigned int LineDetectorULF::RMSBarEdgeDetectorI::staticAdjustThreshold(const unsigned int threshold)
855{
856 /**
857 * The floating point response is:
858 * response = 16 * (peakValue - average) / residual
859 *
860 * sqrResponse = [64 * (2 * area) * (peakValue - average)]^2 / [area * residual]^2
861 * = [64 * 2 * (peakValue - average) / residual]^2
862 * = 16^ * [(peakValue - average) / residual]^2
863 * **TODO** 128^2 ???
864 */
865
866 return threshold * threshold;
867}
868
869inline LineDetectorULF::EdgeDetectors LineDetectorULF::RMSBarEdgeDetectorI::asEdgeDetectors(const unsigned int window, const unsigned int minimalDelta)
870{
871 return {std::make_shared<RMSBarEdgeDetectorI>(window, minimalDelta)};
872}
873
874unsigned int LineDetectorULF::RMSStepEdgeDetectorI::staticAdjustThreshold(const unsigned int threshold)
875{
876 /**
877 * The floating point response is:
878 * response = 4 * (averageL - averageR) / [(residualL + residualR) / 2]
879 * = 8 * (averageL - averageR) / (residualL + residualR)
880 *
881 * sqrResponse = window^2 * (averageL - averageR)^2 / [window^2 * residualL^2 + window^2 + residualR^2)]
882 * = 8^2 * (averageL - averageR)^2 / (residualL^2 + residualR^2)
883 * **TODO** 32 ???
884 *
885 * note this is just an approximation as: (residualL + residualR)^2 != (residualL^2 + residualR^2)
886 */
887
888 return threshold * threshold;
889}
890
892{
893 return {std::make_shared<RMSStepEdgeDetectorI>(window)};
894}
895
896unsigned int LineDetectorULF::RMSBarEdgeDetectorF::staticAdjustThreshold(const unsigned int threshold)
897{
898 /**
899 * The response is:
900 * 16 * (peakValue - average) / residual
901 */
902
903 return threshold;
904}
905
906unsigned int LineDetectorULF::RMSStepEdgeDetectorF::staticAdjustThreshold(const unsigned int threshold)
907{
908 /**
909 * The response is:
910 * 4 * (averageL - averageR) / [(residualL + residualR) / 2]
911 */
912
913 return threshold;
914}
915
916unsigned int LineDetectorULF::ADBarEdgeDetectorI::staticAdjustThreshold(const unsigned int threshold)
917{
918 return threshold; // **TODO**
919}
920
922{
923 return {std::make_shared<ADBarEdgeDetectorI>(window)};
924}
925
926inline LineDetectorULF::EdgeDetectors LineDetectorULF::SDStepEdgeDetectorI::asEdgeDetectors(const unsigned int window, const unsigned int stepSize)
927{
928 return {std::make_shared<SDStepEdgeDetectorI>(window, stepSize)};
929}
930
932{
933 return {std::make_shared<RMSBarEdgeDetectorI>(window, barDetectorMinimalDelta()), std::make_shared<RMSStepEdgeDetectorI>(window)};
934}
935
937{
938 return {std::make_shared<ADBarEdgeDetectorI>(window), std::make_shared<SDStepEdgeDetectorI>(window)};
939}
940
941template <typename T>
942void LineDetectorULF::extractVerticalLines(T* const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const bool transposed, FiniteLines2& lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength, const float maximalStraightLineDistance, EdgeTypes* types)
943{
944 ocean_assert(responses != nullptr);
945 ocean_assert(width != 0u && height != 0u);
946
947 ocean_assert(minimalStartThreshold >= minimalIntermediateThreshold);
948 ocean_assert(minimalStartThreshold >= 0u && minimalIntermediateThreshold >= 0u);
949
950 ocean_assert(double(minimalStartThreshold) <= double(NumericT<T>::maxValue()));
951
952 ocean_assert(maximalStraightLineDistance >= 0.0f);
953
954 ocean_assert(types == nullptr || types->size() == lines.size());
955
956 Memory memoryPixelPositionsX = Memory::create<unsigned int>(height);
957 unsigned int* pixelPositionsX = memoryPixelPositionsX.data<unsigned int>();
958
959 const T* responsePixel = responses;
960
961 for (unsigned int y = 0u; y < height; ++y)
962 {
963 for (unsigned int x = 0u; x < width; ++x)
964 {
965 if ((unsigned int)abs(*responsePixel) >= minimalStartThreshold)
966 {
967 unsigned int firstValidPixelPosition = y;
968 unsigned int lastValidPixelPosition = y;
969
970 const EdgeType edgeTypeSign = *responsePixel >= T(minimalStartThreshold) ? ET_SIGN_POSITIVE : ET_SIGN_NEGATIVE;
971
972 if (*responsePixel >= T(minimalStartThreshold))
973 {
974 constexpr bool positiveThreshold = true;
975
976 lastValidPixelPosition = LineDetectorULF::followEdgeVertical<T, positiveThreshold, 1>(responses, width, height, x, y, T(minimalIntermediateThreshold), pixelPositionsX, paddingElements);
977 firstValidPixelPosition = LineDetectorULF::followEdgeVertical<T, positiveThreshold, -1>(responses, width, height, x, y, T(minimalIntermediateThreshold), pixelPositionsX, paddingElements);
978 }
979 else if (*responsePixel <= -T(minimalStartThreshold))
980 {
981 constexpr bool positiveThreshold = false;
982
983 lastValidPixelPosition = LineDetectorULF::followEdgeVertical<T, positiveThreshold, 1>(responses, width, height, x, y, -T(minimalIntermediateThreshold), pixelPositionsX, paddingElements);
984 firstValidPixelPosition = LineDetectorULF::followEdgeVertical<T, positiveThreshold, -1>(responses, width, height, x, y, -T(minimalIntermediateThreshold), pixelPositionsX, paddingElements);
985 }
986
987 ocean_assert(lastValidPixelPosition >= firstValidPixelPosition);
988 const unsigned int length = lastValidPixelPosition - firstValidPixelPosition + 1u;
989
990 if (length > minimalLength)
991 {
992 const size_t previousNumberLines = lines.size();
993
994 LineDetectorULF::separateStraightLines(pixelPositionsX, firstValidPixelPosition, lastValidPixelPosition, lines, minimalLength, maximalStraightLineDistance, transposed, true);
995
996 const size_t numberNewLines = lines.size() - previousNumberLines;
997
998 if (types && numberNewLines > 0)
999 {
1000 // we set the sign of all new lines which have been created within separateStraightLines() - all new lines have the same sign
1001 types->insert(types->end(), numberNewLines, edgeTypeSign);
1002 }
1003 }
1004 }
1005
1006 ++responsePixel;
1007 }
1008
1009 responsePixel += paddingElements;
1010 }
1011}
1012
1013template <typename T>
1014void LineDetectorULF::extractHorizontalLines(T* const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, FiniteLines2& lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength, const float maximalStraightLineDistance, EdgeTypes* types)
1015{
1016 ocean_assert(responses != nullptr);
1017 ocean_assert(width != 0u && height != 0u);
1018
1019 ocean_assert(minimalStartThreshold >= minimalIntermediateThreshold);
1020 ocean_assert(minimalStartThreshold >= 0u && minimalIntermediateThreshold >= 0u);
1021
1022 ocean_assert(double(minimalStartThreshold) <= double(NumericT<T>::maxValue()));
1023
1024 ocean_assert(maximalStraightLineDistance >= 0.0f);
1025
1026 ocean_assert(types == nullptr || types->size() == lines.size());
1027
1028 Memory memoryPixelPositionsY = Memory::create<unsigned int>(width);
1029 unsigned int* pixelPositionsY = memoryPixelPositionsY.data<unsigned int>();
1030
1031 const T* responsePixel = responses;
1032
1033 for (unsigned int y = 0u; y < height; ++y)
1034 {
1035 for (unsigned int x = 0u; x < width; ++x)
1036 {
1037 if ((unsigned int)abs(*responsePixel) >= minimalStartThreshold)
1038 {
1039 unsigned int firstValidPixelPosition = x;
1040 unsigned int lastValidPixelPosition = x;
1041
1042 const EdgeType edgeTypeSign = *responsePixel >= T(minimalStartThreshold) ? ET_SIGN_POSITIVE : ET_SIGN_NEGATIVE;
1043
1044 if (*responsePixel >= T(minimalStartThreshold))
1045 {
1046 constexpr bool positiveThreshold = true;
1047
1048 lastValidPixelPosition = LineDetectorULF::followEdgeHorizontal<T, positiveThreshold, 1>(responses, width, height, x, y, T(minimalIntermediateThreshold), pixelPositionsY, paddingElements);
1049 firstValidPixelPosition = LineDetectorULF::followEdgeHorizontal<T, positiveThreshold, -1>(responses, width, height, x, y, T(minimalIntermediateThreshold), pixelPositionsY, paddingElements);
1050 }
1051 else if (*responsePixel <= -T(minimalStartThreshold))
1052 {
1053 constexpr bool positiveThreshold = false;
1054
1055 lastValidPixelPosition = LineDetectorULF::followEdgeHorizontal<T, positiveThreshold, 1>(responses, width, height, x, y, -T(minimalIntermediateThreshold), pixelPositionsY, paddingElements);
1056 firstValidPixelPosition = LineDetectorULF::followEdgeHorizontal<T, positiveThreshold, -1>(responses, width, height, x, y, -T(minimalIntermediateThreshold), pixelPositionsY, paddingElements);
1057 }
1058
1059 ocean_assert(lastValidPixelPosition >= firstValidPixelPosition);
1060 const unsigned int length = lastValidPixelPosition - firstValidPixelPosition + 1u;
1061
1062 if (length > minimalLength)
1063 {
1064 const size_t previousNumberLines = lines.size();
1065
1066 LineDetectorULF::separateStraightLines(pixelPositionsY, firstValidPixelPosition, lastValidPixelPosition, lines, minimalLength, maximalStraightLineDistance, true /*majorIsY*/, true);
1067
1068 const size_t numberNewLines = lines.size() - previousNumberLines;
1069
1070 if (types && numberNewLines > 0)
1071 {
1072 // we set the sign of all new lines which have been created within separateStraightLines() - all new lines have the same sign
1073 types->insert(types->end(), numberNewLines, edgeTypeSign);
1074 }
1075 }
1076 }
1077
1078 ++responsePixel;
1079 }
1080
1081 responsePixel += paddingElements;
1082 }
1083}
1084
1085template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
1086unsigned int LineDetectorULF::followEdgeVertical(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsX, const unsigned int paddingElements)
1087{
1088 static_assert(tVerticalDirection == 1 || tVerticalDirection == -1, "Invalid direction value!");
1089
1090 ocean_assert(data != nullptr);
1091 ocean_assert(x < width && y < height);
1092 ocean_assert(threshold != T(0));
1093 ocean_assert(pixelPositionsX != nullptr);
1094
1095 const unsigned int dataStrideElements = width + paddingElements;
1096
1097 data += y * dataStrideElements + x;
1098 *data = T(0); // visited
1099
1100 pixelPositionsX[y] = x;
1101
1102 unsigned int nextX = x;
1103 unsigned int nextY = (unsigned int)(int(y) + tVerticalDirection);
1104
1105 data += tVerticalDirection * int(dataStrideElements);
1106
1107 while (nextY < height) // this test includes negative coordinates: (unsigned int)(-1) >= height
1108 {
1109 ocean_assert(nextX < width);
1110
1111 T bestValue = threshold;
1112 int bestOffset = NumericT<int>::minValue();
1113
1114 // right pixel
1115 if (nextX < width - 1u && valueMatchesThreshold<T, tPositiveThreshold>(*(data + 1), threshold /* = bestValue */))
1116 {
1117 bestValue = *(data + 1);
1118 bestOffset = 1;
1119 }
1120
1121 // left pixel
1122 if (nextX >= 1u && valueMatchesThreshold<T, tPositiveThreshold>(*(data - 1), bestValue))
1123 {
1124 bestValue = *(data - 1);
1125 bestOffset = -1;
1126 }
1127
1128 // center pixel
1129 if (valueMatchesThreshold<T, tPositiveThreshold>(*data, bestValue))
1130 {
1131 // bestValue = *(data + 0); not used below anymore
1132 bestOffset = 0;
1133 }
1134
1135 if (bestOffset == NumericT<int>::minValue())
1136 {
1137 break;
1138 }
1139
1140 data += bestOffset;
1141 *data = 0; // visited
1142
1143 nextX += bestOffset;
1144 pixelPositionsX[nextY] = nextX;
1145
1146 data += tVerticalDirection * int(dataStrideElements);
1147
1148 nextY = (unsigned int)(int(nextY) + tVerticalDirection);
1149 }
1150
1151 ocean_assert(pixelPositionsX[int(nextY) - tVerticalDirection] < width);
1152
1153 ocean_assert((unsigned int)(int(nextY) - tVerticalDirection) < height);
1154
1155 // the previous y value
1156 return (unsigned int)(int(nextY) - tVerticalDirection);
1157}
1158
1159template <typename T, const bool tPositiveThreshold, const int tHorizontalDirection>
1160unsigned int LineDetectorULF::followEdgeHorizontal(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsY, const unsigned int paddingElements)
1161{
1162 static_assert(tHorizontalDirection == 1 || tHorizontalDirection == -1, "Invalid direction value!");
1163
1164 ocean_assert(data != nullptr);
1165 ocean_assert(x < width && y < height);
1166 ocean_assert(threshold != T(0));
1167 ocean_assert(pixelPositionsY != nullptr);
1168
1169 const unsigned int dataStrideElements = width + paddingElements;
1170
1171 data += y * dataStrideElements + x;
1172 *data = T(0); // visited
1173
1174 pixelPositionsY[x] = y;
1175
1176 unsigned int nextX = (unsigned int)(int(x) + tHorizontalDirection);
1177 unsigned int nextY = y;
1178
1179 data += tHorizontalDirection;
1180
1181 while (nextX < width) // this test includes negative coordinates: (unsigned int)(-1) >= width
1182 {
1183 ocean_assert(nextY < height);
1184
1185 T bestValue = threshold;
1186 int bestOffset = NumericT<int>::minValue();
1187
1188 // right pixel
1189 if (nextY < height - 1u && valueMatchesThreshold<T, tPositiveThreshold>(*(data + dataStrideElements), threshold /* = bestValue */))
1190 {
1191 bestValue = *(data + dataStrideElements);
1192 bestOffset = 1;
1193 }
1194
1195 // left pixel
1196 if (nextY >= 1u && valueMatchesThreshold<T, tPositiveThreshold>(*(data - dataStrideElements), bestValue))
1197 {
1198 bestValue = *(data - dataStrideElements);
1199 bestOffset = -1;
1200 }
1201
1202 // center pixel
1203 if (valueMatchesThreshold<T, tPositiveThreshold>(*data, bestValue))
1204 {
1205 // bestValue = *(data + 0); not used below anymore
1206 bestOffset = 0;
1207 }
1208
1209 if (bestOffset == NumericT<int>::minValue())
1210 {
1211 break;
1212 }
1213
1214 data += bestOffset * int(dataStrideElements);
1215 *data = 0; // visited
1216
1217 nextY += bestOffset;
1218 pixelPositionsY[nextX] = nextY;
1219
1220 data += tHorizontalDirection;
1221
1222 nextX = (unsigned int)(int(nextX) + tHorizontalDirection);
1223 }
1224
1225 ocean_assert(pixelPositionsY[int(nextX) - tHorizontalDirection] < height);
1226
1227 ocean_assert((unsigned int)(int(nextX) - tHorizontalDirection) < width);
1228
1229 // the previous x value
1230 return (unsigned int)(int(nextX) - tHorizontalDirection);
1231}
1232
1233template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
1234unsigned int LineDetectorULF::followEdgeVerticalBranchFree(T* data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T& threshold, unsigned int* pixelPositionsX, const unsigned int paddingElements)
1235{
1236 static_assert(tVerticalDirection == 1 || tVerticalDirection == -1, "Invalid direction value!");
1237
1238 ocean_assert(data != nullptr);
1239 ocean_assert(x < width && y < height);
1240 ocean_assert(threshold != T(0));
1241 ocean_assert(pixelPositionsX != nullptr);
1242
1243 const unsigned int dataStrideElements = width + paddingElements;
1244
1245 data += y * dataStrideElements + x;
1246 *data = T(0); // visited
1247
1248 pixelPositionsX[y] = x;
1249
1250 const int intThreshold = int(threshold);
1251
1252 unsigned int nextX = x;
1253 unsigned int nextY = (unsigned int)(int(y) + tVerticalDirection);
1254
1255 data += tVerticalDirection * int(dataStrideElements);
1256
1257 while (nextY < height) // this test includes negative coordinates: (unsigned int)(-1) >= height
1258 {
1259 ocean_assert(nextX < width);
1260
1261 const int leftOrCenterValue = *(data - int(nextX - 1u < width));
1262 const int centerValue = *data;
1263 const int rightOrCenterValue = *(data + int(nextX < width - 1u));
1264
1265#ifdef OCEAN_DEBUG
1266
1267 if (nextX >= 1u)
1268 ocean_assert(leftOrCenterValue == *(data - 1));
1269 else
1270 ocean_assert(leftOrCenterValue == *data);
1271
1272 if (nextX + 1u < width)
1273 ocean_assert(rightOrCenterValue == *(data + 1));
1274 else
1275 ocean_assert(rightOrCenterValue == *data);
1276
1277#endif
1278
1279 // priority if equal: center, right, left
1280
1281 // for positive threshold: center >= threshold && center >= left && center >= right
1282 const int useCenterValue = tPositiveThreshold ? (centerValue >= intThreshold && centerValue >= leftOrCenterValue && centerValue >= rightOrCenterValue) : centerValue <= intThreshold && centerValue <= leftOrCenterValue && centerValue <= rightOrCenterValue;
1283 ocean_assert(useCenterValue == 0 || useCenterValue == 1);
1284
1285 // for positive threshold: right >= threshold && right > center && right > left
1286 const int useRightValue = tPositiveThreshold ? (rightOrCenterValue >= intThreshold && rightOrCenterValue > centerValue && rightOrCenterValue > leftOrCenterValue) : (rightOrCenterValue <= intThreshold && rightOrCenterValue < centerValue && rightOrCenterValue < leftOrCenterValue);
1287 ocean_assert(useRightValue == 0 || useRightValue == 1);
1288
1289 // for positive threshold: left >= threshold && left > center && left >= right
1290 const int useLeftValue = tPositiveThreshold ? (leftOrCenterValue >= intThreshold && leftOrCenterValue > centerValue && leftOrCenterValue >= rightOrCenterValue) : (leftOrCenterValue <= intThreshold && leftOrCenterValue < centerValue && leftOrCenterValue <= rightOrCenterValue);
1291 ocean_assert(useLeftValue == 0 || useLeftValue == 1);
1292
1293 ocean_assert(useCenterValue + useLeftValue + useRightValue == 0 || useCenterValue + useLeftValue + useRightValue == 1);
1294
1295 const int useNoValue = 1 - useCenterValue - useLeftValue - useRightValue;
1296 ocean_assert(useNoValue == 0 || useNoValue == 1);
1297
1298 if (useNoValue != 0)
1299 {
1300 // we have no valid next value
1301
1302#ifdef OCEAN_DEBUG
1303
1304 ocean_assert(useLeftValue == 0);
1305 ocean_assert(useCenterValue == 0);
1306 ocean_assert(useRightValue == 0);
1307
1308 if constexpr (tPositiveThreshold)
1309 {
1310 ocean_assert(*data < intThreshold);
1311 ocean_assert(nextX == 0u || *(data - 1) < intThreshold);
1312 ocean_assert(nextX + 1u >= width || *(data + 1) < intThreshold);
1313 }
1314 else
1315 {
1316 ocean_assert(*data > intThreshold);
1317 ocean_assert(nextX == 0u || *(data - 1) > intThreshold);
1318 ocean_assert(nextX + 1u >= width || *(data + 1) > intThreshold);
1319 }
1320
1321#endif // OCEAN_DEBUG
1322
1323 break;
1324 }
1325
1326 const int nextOffsetX = -useLeftValue /* + useCenterValue * 0 */ + useRightValue;
1327
1328#ifdef OCEAN_DEBUG
1329
1330 if (useNoValue == 0)
1331 {
1332 // we have a valid next value
1333
1334 if (nextOffsetX == -1)
1335 {
1336 ocean_assert(useLeftValue == 1);
1337 ocean_assert(nextX >= 1u);
1338
1339 if constexpr (tPositiveThreshold)
1340 {
1341 ocean_assert(*(data - 1) >= intThreshold);
1342 ocean_assert(*(data - 1) > *data);
1343 ocean_assert(nextX + 1u >= width || *(data - 1) >= *(data + 1));
1344 }
1345 else
1346 {
1347 ocean_assert(*(data - 1) <= intThreshold);
1348 ocean_assert(*(data - 1) < *data);
1349 ocean_assert(nextX + 1u >= width || *(data - 1) <= *(data + 1));
1350 }
1351 }
1352 else if (nextOffsetX == 0)
1353 {
1354 ocean_assert(useCenterValue == 1);
1355
1356 if constexpr (tPositiveThreshold)
1357 {
1358 ocean_assert(*data >= intThreshold);
1359 ocean_assert(nextX >= 1u || *data >= *(data - 1));
1360 ocean_assert(nextX + 1u >= width || *data >= *(data + 1));
1361 }
1362 else
1363 {
1364 ocean_assert(*data <= intThreshold);
1365 ocean_assert(nextX >= 1u || *data <= *(data - 1));
1366 ocean_assert(nextX + 1u >= width || *data <= *(data + 1));
1367 }
1368 }
1369 else
1370 {
1371 ocean_assert(nextOffsetX == 1);
1372
1373 ocean_assert(useRightValue == 1);
1374 ocean_assert(nextX + 1u < width);
1375
1376 if constexpr (tPositiveThreshold)
1377 {
1378 ocean_assert(*(data + 1) >= intThreshold);
1379 ocean_assert(*(data + 1) > *data);
1380 ocean_assert(nextX == 0u || *(data + 1) > *(data - 1));
1381 }
1382 else
1383 {
1384 ocean_assert(*(data + 1) <= intThreshold);
1385 ocean_assert(*(data + 1) < *data);
1386 ocean_assert(nextX == 0u || *(data + 1) < *(data - 1));
1387 }
1388 }
1389
1390 ocean_assert(int(nextX) + nextOffsetX >= 0 && nextX + nextOffsetX < int(width));
1391 }
1392
1393#endif
1394
1395 data += nextOffsetX;
1396 *data = 0; // visited
1397
1398 nextX += nextOffsetX; // nextX + nextOffsetX may actually be wrong
1399 pixelPositionsX[nextY] = nextX;
1400
1401 data += tVerticalDirection * int(dataStrideElements);
1402
1403 nextY += tVerticalDirection;
1404 }
1405
1406 ocean_assert(pixelPositionsX[int(nextY) - tVerticalDirection] < width);
1407
1408 // the previous y value
1409 return (unsigned int)(int(nextY) - tVerticalDirection);
1410}
1411
1412template <typename T, const bool tPositiveThreshold>
1413inline bool LineDetectorULF::valueMatchesThreshold(const T& value, const T& threshold)
1414{
1415 if constexpr (tPositiveThreshold)
1416 {
1417 return value >= threshold;
1418 }
1419 else
1420 {
1421 return value <= threshold;
1422 }
1423}
1424
1426{
1427 return 2u;
1428};
1429
1430}
1431
1432}
1433
1434}
1435
1436#endif // META_OCEAN_CV_DETECTOR_LINE_DETECTOR_ULF_H
This class implements an integer-based bar edge detector based on averaged differences.
Definition LineDetectorULF.h:502
static EdgeDetectors asEdgeDetectors(const unsigned int window=4u)
Returns a vector containing just this edge detector with shared pointer (to simplify the usage with d...
Definition LineDetectorULF.h:921
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int framePaddingElements) const override
Invokes the vertical edge detection for the entire frame.
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int window, const uint32_t *const windowSums, int16_t *responses)
Invokes the vertical edge detection in one row of the input frame.
static unsigned int staticAdjustThreshold(const unsigned int threshold)
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
Definition LineDetectorULF.h:916
ADBarEdgeDetectorI(const unsigned int window=4u)
Create a new edge detector object.
This class implements the almost abstract base class for all edge detectors.
Definition LineDetectorULF.h:81
static void determineRowSums(const uint8_t *row, const unsigned int width, const unsigned int window, uint32_t *windowSums)
Determines the sums of pixel intensities of sliding windows within a row of a frame.
virtual ~EdgeDetector()=default
Destructor of an edge detector.
static void determineRowSums(const uint8_t *row, const unsigned int width, const unsigned int window, uint32_t *windowSums, uint32_t *windowSqrSums)
Determines the sums of pixel intensities (and sums of squared pixel intensities) of sliding windows w...
virtual void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const =0
Invokes the vertical edge detection for the entire frame.
EdgeType edgeType() const
Returns the type of the edges this detector detects.
Definition LineDetectorULF.h:849
virtual unsigned int adjustThreshold(const unsigned int threshold) const
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
const EdgeType edgeType_
Definition LineDetectorULF.h:217
static void applyRowSum(const uint8_t *row, const unsigned int width, uint16_t *sum)
Either adds or subtracts one row from the sum and square sum buffers.
const unsigned int window_
The width of the sliding window in pixel, with range [1, infinity)
Definition LineDetectorULF.h:214
EdgeDetector(const unsigned int window, const EdgeType edgeType)
Protected default constructor.
Definition LineDetectorULF.h:837
virtual bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const
Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
virtual bool invokeHorizontal(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const
Invokes the horizontal edge detection for the entire frame.
static void applyRowSum(const uint8_t *row, const unsigned int width, uint16_t *sum, uint32_t *sqrSum)
Either adds or subtracts one row from the sum and square sum buffers.
static void determineRowSums(const uint8_t *row, const unsigned int width, const unsigned int window, uint16_t *windowSums, uint32_t *windowSqrSums)
Determines the sums of pixel intensities (and sums of squared pixel intensities) of sliding windows w...
static void determineRowSums(const uint8_t *row, const unsigned int width, const unsigned int window, uint16_t *windowSums)
Determines the sums of pixel intensities of sliding windows within a row of a frame.
unsigned int window() const
Returns the width of the sliding window in pixel, with range [1, infinity)
Definition LineDetectorULF.h:844
This class implements a floating-point-based bar edge detector based on root mean square residuals.
Definition LineDetectorULF.h:407
static unsigned int staticAdjustThreshold(const unsigned int threshold)
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
Definition LineDetectorULF.h:896
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int window, const unsigned int minimalDelta, const uint32_t *const windowSums, const uint32_t *const windowSqrSums, int16_t *sqrResponses)
Invokes the vertical edge detection in one row of the input frame.
RMSBarEdgeDetectorF(const unsigned int window=4u, const unsigned int minimalDelta=barDetectorMinimalDelta())
Create a new edge detector object.
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const override
Invokes the vertical edge detection for the entire frame.
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
const unsigned int minimalDelta_
The minimal intensity delta between average and center pixel, with range [0, 255].
Definition LineDetectorULF.h:451
This class implements an integer-based bar edge detector based on root mean square residuals.
Definition LineDetectorULF.h:230
bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override
Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int framePaddingElements) const override
Invokes the vertical edge detection for the entire frame.
RMSBarEdgeDetectorI(const unsigned int window=4u, const unsigned int minimalDelta=barDetectorMinimalDelta())
Create a new edge detector object.
bool invokeHorizontal(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const override
Invokes the horizontal edge detection for the entire frame.
static EdgeDetectors asEdgeDetectors(const unsigned int window=4u, const unsigned int minimalDelta=barDetectorMinimalDelta())
Returns a vector containing just this edge detector with shared pointer (to simplify the usage with d...
Definition LineDetectorULF.h:869
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int window, const unsigned int minimalDelta, const uint16_t *const windowSums, const uint32_t *const windowSqrSums, int16_t *sqrResponses)
Invokes the vertical edge detection in one row of the input frame.
const unsigned int minimalDelta_
The minimal intensity delta between average and center pixel, with range [0, 255].
Definition LineDetectorULF.h:312
static unsigned int staticAdjustThreshold(const unsigned int threshold)
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
Definition LineDetectorULF.h:854
This class implements a floating-point-based bar step detector based on root mean square residuals.
Definition LineDetectorULF.h:458
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int window, const uint32_t *const windowSums, const uint32_t *const windowSqrSums, int16_t *sqrResponses)
Invokes the vertical edge detection in one row of the input frame.
static unsigned int staticAdjustThreshold(const unsigned int threshold)
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
Definition LineDetectorULF.h:906
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const override
Invokes the vertical edge detection for the entire frame.
RMSStepEdgeDetectorF(const unsigned int window=4u)
Create a new edge detector object.
This class implements an integer-based bar step detector based on root mean square residuals.
Definition LineDetectorULF.h:319
static unsigned int staticAdjustThreshold(const unsigned int threshold)
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
Definition LineDetectorULF.h:874
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int framePaddingElements) const override
Invokes the vertical edge detection for the entire frame.
bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override
Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
bool invokeHorizontal(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const override
Invokes the horizontal edge detection for the entire frame.
static EdgeDetectors asEdgeDetectors(const unsigned int window=4u)
Returns a vector containing just this edge detector with shared pointer (to simplify the usage with d...
Definition LineDetectorULF.h:891
RMSStepEdgeDetectorI(const unsigned int window=4u)
Create a new edge detector object.
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int window, const uint16_t *const windowSums, const uint32_t *const windowSqrSums, int16_t *sqrResponses)
Invokes the vertical edge detection in one row of the input frame.
This class implements an integer-based (sum difference) step edge detector that computes the differen...
Definition LineDetectorULF.h:561
const unsigned int stepSize_
The number of pixels between both windows sums, "should be odd", "should" have range [1,...
Definition LineDetectorULF.h:625
void invokeVertical(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int framePaddingElements) const override
Invokes the vertical edge detection for the entire frame.
bool hasInvokeHorizontal(const unsigned int width, const unsigned int height) const override
Returns whether this EdgeDetector object has an implementation for invokeHorizontal().
static void invokeRowVertical(const uint8_t *const row, const unsigned int width, const unsigned int stepSize, const unsigned int window, const uint16_t *const windowSums, int16_t *responses)
Invokes the vertical edge detection in one row of the input image with a fixed window width of 2 pixe...
bool invokeHorizontal(const uint8_t *frame, const unsigned int width, const unsigned int height, int16_t *responses, const unsigned int paddingElements) const override
Invokes the horizontal edge detection for the entire frame.
SDStepEdgeDetectorI(const unsigned int window=2u, const unsigned int stepSize=1u)
Create a new edge detector object.
unsigned int adjustThreshold(const unsigned int threshold) const override
Adjusts the edge detection threshold (which is specified independently of the applied edge detection ...
static EdgeDetectors asEdgeDetectors(const unsigned int window=2u, const unsigned int stepSize=1u)
Returns a vector containing just this edge detector with shared pointer (to simplify the usage with d...
Definition LineDetectorULF.h:926
This class implements a line detector optimized for urban lines (Urban Line Finder).
Definition LineDetectorULF.h:34
ScanDirection
Definition of scan direction of the line detection.
Definition LineDetectorULF.h:60
static FiniteLines2 detectLines(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const unsigned int framePaddingElements, const EdgeDetectors &edgeDetectors=defaultEdgeDetectors(), const unsigned int threshold=50u, const unsigned int minimalLength=20u, const float maximalStraightLineDistance=1.6f, EdgeTypes *types=nullptr, const ScanDirection scanDirection=SD_VERTICAL_AND_HORIZONTAL)
Detects finite lines within a given 8bit grayscale image.
std::vector< EdgeType > EdgeTypes
Definition of a vector holding edge types.
Definition LineDetectorULF.h:72
static void separateStraightLines(const unsigned int *pixelPositionsMajor, const unsigned int firstPositionIndex, const unsigned int lastPositionIndex, FiniteLines2 &lines, const unsigned int minimalLength, const float maximalOffset, const bool majorIsY, const bool refine)
Separates a set of connected pixels (almost defining a straight line) into individual perfect straigh...
static unsigned int followEdgeHorizontal(T *data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T &threshold, unsigned int *pixelPositionsY, const unsigned int paddingElements)
Follows an edge in horizontal direction while applying a vertical search radius with one pixel (-1,...
Definition LineDetectorULF.h:1160
static constexpr unsigned int barDetectorMinimalDelta()
The threshold for the minimal delta for bar detectors.
Definition LineDetectorULF.h:1425
static bool valueMatchesThreshold(const T &value, const T &threshold)
Returns whether a given value is larger than or equal to a given threshold (or smaller than or equal ...
Definition LineDetectorULF.h:1413
static EdgeDetectors performanceEdgeDetectors(const unsigned int window=4u)
Returns ULF's two high performance edge detectors.
Definition LineDetectorULF.h:936
EdgeType
Definition of individual edge types.
Definition LineDetectorULF.h:41
@ ET_SIGN_NEGATIVE
Negative sign edge; e.g., a dark bar edge.
Definition LineDetectorULF.h:51
@ ET_SIGN_POSITIVE
Positive sign edge; e.g., a bright bar edge.
Definition LineDetectorULF.h:49
static void extractVerticalLines(T *const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, const bool transposed, FiniteLines2 &lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength=20u, const float maximalStraightLineDistance=1.6f, EdgeTypes *types=nullptr)
Extracts straight vertical (+/- 45 degree) finite lines from a given frame with edge responses.
Definition LineDetectorULF.h:942
static bool detectLines(const uint8_t *const yFrame, Memory &yFrameTransposedMemory, const unsigned int width, const unsigned int height, const unsigned int yFramePaddingElements, unsigned int &yFrameTransposedMemoryPaddingElements, const EdgeDetector &edgeDetector, FiniteLines2 &detectedLines, const ScanDirection scanDirection, const unsigned int threshold=50u, int16_t *reusableResponseBuffer=nullptr, const unsigned int minimalLength=20u, const float maximalStraightLineDistance=1.6f, EdgeTypes *types=nullptr)
Detects lines by applying a given edge detector for an image in horizontal and vertical direction.
static unsigned int followEdgeVertical(T *data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T &threshold, unsigned int *pixelPositionsX, const unsigned int paddingElements)
Follows an edge in vertical direction while applying a horizontal search radius with one pixel (-1,...
Definition LineDetectorULF.h:1086
static unsigned int followEdgeVerticalBranchFree(T *data, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const T &threshold, unsigned int *pixelPositionsX, const unsigned int paddingElements)
Follows an edge in vertical direction while applying a horizontal search radius with one pixel (-1,...
Definition LineDetectorULF.h:1234
static void extractHorizontalLines(T *const responses, const unsigned int width, const unsigned int height, const unsigned int paddingElements, FiniteLines2 &lines, const unsigned int minimalStartThreshold, const unsigned int minimalIntermediateThreshold, const unsigned int minimalLength=20u, const float maximalStraightLineDistance=1.6f, EdgeTypes *types=nullptr)
Extracts straight horizontal (+/- 45 degree) finite lines from a given frame with edge responses.
Definition LineDetectorULF.h:1014
static EdgeDetectors defaultEdgeDetectors(const unsigned int window=4u)
Returns ULF's two default edge detectors.
Definition LineDetectorULF.h:931
std::vector< std::shared_ptr< EdgeDetector > > EdgeDetectors
Definition of a vector holding edge detectors.
Definition LineDetectorULF.h:223
This class implements an object able to allocate memory.
Definition base/Memory.h:22
void * data()
Returns the pointer to the writable memory which is allocated by this object.
Definition base/Memory.h:303
This class provides basic numeric functionalities.
Definition Numeric.h:57
static constexpr T minValue()
Returns the min scalar value.
Definition Numeric.h:3250
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition FiniteLine2.h:57
The namespace covering the entire Ocean framework.
Definition Accessor.h:15