Ocean
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 
16 #include "ocean/cv/PixelPosition.h"
17 
18 #include "ocean/math/FiniteLine2.h"
19 
20 namespace Ocean
21 {
22 
23 namespace CV
24 {
25 
26 namespace Detector
27 {
28 
29 /**
30  * This class implements a line detector optimized for urban lines (Urban Line Finder).
31  * @ingroup cvdetector
32  */
33 class 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 
837 inline LineDetectorULF::EdgeDetector::EdgeDetector(const unsigned int window, const EdgeType edgeType) :
838  window_(window),
839  edgeType_(edgeType)
840 {
841  // nothing to do here
842 }
843 
844 inline unsigned int LineDetectorULF::EdgeDetector::window() const
845 {
846  return window_;
847 }
848 
850 {
851  return edgeType_;
852 }
853 
854 inline 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 
869 inline LineDetectorULF::EdgeDetectors LineDetectorULF::RMSBarEdgeDetectorI::asEdgeDetectors(const unsigned int window, const unsigned int minimalDelta)
870 {
871  return {std::make_shared<RMSBarEdgeDetectorI>(window, minimalDelta)};
872 }
873 
874 unsigned 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 
896 unsigned 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 
906 unsigned 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 
916 unsigned 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 
926 inline 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 
941 template <typename T>
942 void 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 
1013 template <typename T>
1014 void 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 
1085 template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
1086 unsigned 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 
1159 template <typename T, const bool tPositiveThreshold, const int tHorizontalDirection>
1160 unsigned 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 
1233 template <typename T, const bool tPositiveThreshold, const int tVerticalDirection>
1234 unsigned 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 
1412 template <typename T, const bool tPositiveThreshold>
1413 inline 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