Ocean
ShapeDetector.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_SHAPE_DETECTOR_H
9 #define META_OCEAN_CV_DETECTOR_SHAPE_DETECTOR_H
10 
12 
13 #include "ocean/base/Frame.h"
14 
16 
17 #include "ocean/math/FiniteLine2.h"
18 #include "ocean/math/Triangle2.h"
19 #include "ocean/math/Vector2.h"
20 
21 #include <array>
22 
23 namespace Ocean
24 {
25 
26 namespace CV
27 {
28 
29 namespace Detector
30 {
31 
32 /**
33  * This class is a collection of detectors for geometric shapes.
34  * @ingroup cvdetector
35  */
36 class OCEAN_CV_DETECTOR_EXPORT ShapeDetector
37 {
38  public:
39 
40  /**
41  * This class implements the base class for all shapes based on two lines.
42  */
44  {
45  public:
46 
47  /**
48  * Definition of individual shape types.
49  */
50  enum ShapeType : unsigned int
51  {
52  /// An invalid shape type.
53  ST_INVALID = 0u,
54  /// An L-shape.
55  ST_SHAPE_L = 1u,
56  /// A T-shape.
57  ST_SHAPE_T = 2u,
58  /// An X-shape.
59  ST_SHAPE_X = 3u
60  };
61 
62  public:
63 
64  /**
65  * Returns the type of the shape.
66  * @return The shape's type
67  */
68  inline ShapeType type() const;
69 
70  /**
71  * Returns the index of the first finite line.
72  * @return Index of the first line, with range [0, infinity)
73  */
74  inline unsigned int finiteLineIndex0() const;
75 
76  /**
77  * Returns the index of the second finite line.
78  * @return Index of the second line, with range [0, infinity)
79  */
80  inline unsigned int finiteLineIndex1() const;
81 
82  /**
83  * Returns the index of the first or second finite line.
84  * @param index The index of the finite line of this shape, range: [0, 1]
85  * @return Index of the line, with range [0, infinity)
86  */
87  inline unsigned int finiteLineIndex(const unsigned int index) const;
88 
89  /**
90  * Returns the position of this shape.
91  * @return The shape's position
92  */
93  inline const Vector2& position() const;
94 
95  /**
96  * Sets or changes the position of this shape.
97  * @param position The new position
98  */
99  inline void setPosition(const Vector2& position);
100 
101  /**
102  * Returns the sore of this shape.
103  * @return The shape's score
104  */
105  inline Scalar score() const;
106 
107  protected:
108 
109  /**
110  * Creates an invalid shape.
111  */
112  inline TwoLineShape();
113 
114  /**
115  * Creates a new shape object.
116  * @param shapeType The type of the shape, must be valid
117  * @param position The position of the shape, e.g., the corner/intersection of both finites line
118  * @param score The score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
119  */
120  inline TwoLineShape(const ShapeType shapeType, const Vector2& position, const Scalar score);
121 
122  /**
123  * Creates a new shape object.
124  * @param shapeType The type of the shape, must be valid
125  * @param finiteLineIndex0 The index of the first finite line, with range [0, infinity)
126  * @param finiteLineIndex1 The index of the second finite line, with range [0, infinity)
127  * @param position The position of the shape, e.g., the corner/intersection of both finites line
128  * @param score The score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
129  */
130  inline TwoLineShape(const ShapeType shapeType, const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Scalar score);
131 
132  protected:
133 
134  /// The shape's type.
135  ShapeType shapeType_ = ST_INVALID;
136 
137  /// The index of the first finite line.
138  unsigned int finiteLineIndex0_ = (unsigned int)(-1);
139 
140  /// The index of the second finite line.
141  unsigned int finiteLineIndex1_ = (unsigned int)(-1);
142 
143  /// The position of this shape.
145 
146  /// The score of this L-shape.
148  };
149 
150  /**
151  * Definition of a vector holding pointers to TwoLineShapes.
152  */
153  typedef std::vector<const CV::Detector::ShapeDetector::TwoLineShape*> TwoLineShapes;
154 
155  /**
156  * This class implements an L-shape element like a corner of a rectangle.
157  * The L-shape is defined by to finite edges almost perpendicular to each other and having a similar end point.<br>
158  * Instead of storing the actual two finite lines defining the L-shape, this class stores the indices of the lines only.
159  *
160  * Direction of L-shapes:
161  * <pre>
162  *
163  * leftEdge
164  * ^
165  * | / direction
166  * | /
167  * | /
168  * +------> rightEdge
169  *
170  * </pre>
171  *
172  * direction = (leftEdge + rightEdge) / ||leftEdge + rightEdge||
173  */
174  class LShape : public TwoLineShape
175  {
176  public:
177 
178  /**
179  * Creates an invalid L-shape object.
180  */
181  inline LShape();
182 
183  /**
184  * Creates a new L-shape object by the L-shape's location, direction and score.
185  * @param position The position of the L-shape, e.g., the corner/intersection of both finites line
186  * @param direction The direction of the L-shape, e.g., the half vector between both finite lines, must have unit length
187  * @param edgeLeft The left edge of the L-shape, left of the direction (half vector), starting at the position, must have unit length
188  * @param edgeRight The right edge of the L-shape, left of the direction (half vector), starting at the position, must have unit length
189  * @param score The score of the L-shape, e.g,. base on the length of the finite lines, with range [0, infinity)
190  */
191  inline LShape(const Vector2& position, const Vector2& direction, const Vector2& edgeLeft, const Vector2& edgeRight, const Scalar score);
192 
193  /**
194  * Creates a new L-shape object by two indices specifying the finite lines, the L-shape's location, direction and score.
195  * @param finiteLineIndex0 The index of the first finite line, with range [0, infinity)
196  * @param finiteLineIndex1 The index of the second finite line, with range [0, infinity)
197  * @param position The position of the L-shape, e.g., the corner/intersection of both finites line
198  * @param direction The direction of the L-shape, e.g., the half vector between both finite lines, must have unit length
199  * @param edgeLeft The left edge of the L-shape, left of the direction (half vector), starting at the position, must have unit length
200  * @param edgeRight The right edge of the L-shape, left of the direction (half vector), starting at the position, must have unit length
201  * @param score The score of the L-shape, e.g,. base on the length of the finite lines, with range [0, infinity)
202  */
203  inline LShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction, const Vector2& edgeLeft, const Vector2& edgeRight, const Scalar score);
204 
205  /**
206  * Returns the left edge of this L-shape.
207  * @return The shape's left edge
208  */
209  inline const Vector2& edgeLeft() const;
210 
211  /**
212  * Returns the right edge of this L-shape.
213  * @return The shape's right edge
214  */
215  inline const Vector2& edgeRight() const;
216 
217  /**
218  * Returns the direction of this L-shape.
219  * @return The shape's direction
220  */
221  inline const Vector2& direction() const;
222 
223  protected:
224 
225  /// The left edge of this L-shape.
227 
228  /// The right edge of this L-shape.
230 
231  /// The direction of this L-shape.
233  };
234 
235  /**
236  * This class implements a T-shape element like a junction connecting two lines, with one line having the connecting at an end point and the other in the middle of th line.
237  * The direction of a T-shape is defined by the line which is connected at one of the end points and pointing away from the connection:
238  * \code
239  * ------------------
240  * |
241  * |
242  * |
243  * |
244  * V
245  * direction
246  * \endcode
247  */
248  class TShape : public TwoLineShape
249  {
250  public:
251 
252  /**
253  * Creates an invalid T-shape object.
254  */
255  inline TShape();
256 
257  /**
258  * Creates a new T-shape object by the T-shape's location and direction.
259  * @param position The position of the L-shape, e.g., the corner/intersection of both finites line
260  * @param direction The direction of the L-shape, e.g., the half vector between both finite lines, must have unit length
261  * @param score The optional score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
262  */
263  inline TShape(const Vector2& position, const Vector2& direction, const Scalar score = Scalar(0));
264 
265  /**
266  * Creates a new T-shape object by two indices specifying the finite lines, the T-shape's location and direction.
267  * @param finiteLineIndex0 The index of the first finite line, with range [0, infinity)
268  * @param finiteLineIndex1 The index of the second finite line, with range [0, infinity)
269  * @param position The position of the L-shape, e.g., the corner/intersection of both finites line
270  * @param direction The direction of the L-shape, e.g., the half vector between both finite lines, must have unit length
271  * @param score The optional score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
272  */
273  inline TShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction, const Scalar score = Scalar(0));
274 
275  /**
276  * Returns the direction of this T-shape.
277  * @return The shape's direction
278  */
279  inline const Vector2& direction() const;
280 
281  protected:
282 
283  /// The direction of this T-shape.
285  };
286 
287  /**
288  * This class implements a X-shape element like a crossing of two lines, with both lines not crossing near to an end point.
289  * The directions of a X-shape are defined by the two lines:
290  * <pre>
291  * |
292  * |
293  * |
294  * -----------------> direction0
295  * |
296  * |
297  * V
298  * direction1
299  * </pre>
300  */
301  class OCEAN_CV_DETECTOR_EXPORT XShape : public TwoLineShape
302  {
303  public:
304 
305  /**
306  * Creates an invalid X-shape object.
307  */
308  inline XShape();
309 
310  /**
311  * Creates a new X-shape object by the X-shape's location and directions.
312  * @param position The position of the X-shape, e.g., the corner/intersection of both finites line
313  * @param direction0 The first direction of the X-shape, must have unit length
314  * @param direction1 The second direction of the X-shape, must have unit length
315  * @param score The optional score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
316  */
317  inline XShape(const Vector2& position, const Vector2& direction0, const Vector2& direction1, const Scalar score = Scalar(0));
318 
319  /**
320  * Creates a new X-shape object by two indices specifying the finite lines, the X-shape's location and directions.
321  * @param finiteLineIndex0 The index of the first finite line, with range [0, infinity)
322  * @param finiteLineIndex1 The index of the second finite line, with range [0, infinity)
323  * @param position The position of the X-shape, e.g., the corner/intersection of both finites line
324  * @param direction0 The first direction of the X-shape, must have unit length
325  * @param direction1 The second direction of the X-shape, must have unit length
326  * @param score The optional score of the L-shape, e.g,. the response parameter of the detector, with range [0, infinity)
327  */
328  inline XShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction0, const Vector2& direction1, const Scalar score = Scalar(0));
329 
330  /**
331  * Verifies whether this X-shape is valid based on underlying image content.
332  * The X-shape is valid if all four edges of the shape have almost the same color.
333  * @param yFrame The frame in which the X-shape is located, must have pixel format FORMAT_Y8, must be valid
334  * @param width The width of the frame in pixel, with range [1, infinity)
335  * @param height The height of the frame in pixel, with range [1, infinity)
336  * @param darkShape True, if the given shape is based on a dark edge; False, if the given shape is based on a bright edge
337  * @param minimalValueRange The minimal value range between the darkest and brightest color intensity to start the investigation, with range [0, 255)
338  * @param sampleOffset The sampling offset to be used for verification, with range [0, infinity)
339  * @param samples The number of samples to be used for verification, with range [1, infinity)
340  * @param yFramePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
341  * @return True, if succeeded
342  */
343  bool verifyShape(const uint8_t* yFrame, const unsigned int width, const unsigned int height, const bool darkShape, const unsigned int minimalValueRange, const unsigned int sampleOffset = 2u, const unsigned int samples = 4u, const unsigned int yFramePaddingElements = 0u) const;
344 
345  /**
346  * Returns the first direction of this X-shape.
347  * @return The shape's first direction
348  */
349  inline const Vector2& direction0() const;
350 
351  /**
352  * Return the second direction of this X-shape.
353  * @return The shape's second direction
354  */
355  inline const Vector2& direction1() const;
356 
357  protected:
358 
359  /// The direction of the first line of this X-shape.
361 
362  /// The direction of the second line of this X-shape.
364  };
365 
366  /**
367  * Definition of a vector holding L-shape objects.
368  */
369  typedef std::vector<LShape> LShapes;
370 
371  /**
372  * Definition of a vector holding T-shape objects.
373  */
374  typedef std::vector<TShape> TShapes;
375 
376  /**
377  * Definition of a vector holding X-shape objects.
378  */
379  typedef std::vector<XShape> XShapes;
380 
381  /**
382  * Definition of an array holding four indices e.g., of L-shape objects.
383  */
384  typedef std::array<Index32, 4> IndexedRectangle;
385 
386  /**
387  * Definition of a vector holding rectangles.
388  */
389  typedef std::vector<IndexedRectangle> IndexedRectangles;
390 
391  /**
392  * A rectangle defined by its four corners (counter-clockwise direction)
393  */
394  typedef std::array<Vector2, 4> Rectangle;
395 
396  /**
397  * A vector of rectangles
398  */
399  typedef std::vector<Rectangle> Rectangles;
400 
401  /**
402  * This class implements a shape detector mainly based on gradients.
403  */
404  class OCEAN_CV_DETECTOR_EXPORT PatternDetectorGradientBased
405  {
406  public:
407 
408  /**
409  * Detects shapes in a given image.
410  * @param yFrame The frame in which the shapes will be detected, must be valid
411  * @param width The width of the frame in pixel, with range [1, infinity)
412  * @param height The height of the frame in pixel, with rang [1, infinity)
413  * @param lShapes The resulting detected L-shapes
414  * @param tShapes The resulting detected T-shapes
415  * @param xShapes The resulting detected X-shapes
416  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment
417  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
418  * @param shapeWidth **TODO** document once finalized
419  * @param shapeHeight **TODO** document once finalized
420  * @param stepSize **TODO** document once finalized
421  * @param topBand **TODO** document once finalized
422  * @param bottomBand **TODO** document once finalized
423  * @param minimalDelta **TODO** document once finalized
424  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
425  */
426  static void detectShapes(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const int sign, const double minimalThreshold = 5.0, const unsigned int shapeWidth = 15u, const unsigned int shapeHeight = 15u, const unsigned int stepSize = 3u, const unsigned int topBand = 4u, const unsigned int bottomBand = 4u, const unsigned int minimalDelta = 5u, const unsigned int framePaddingElements = 0u);
427 
428  /**
429  * Determines the detector response for an gradient-based T-shape detector which is axis aligned.
430  * @param linedIntegralHorizontalSignedGradient The lined integral image providing horizontal signed gradients of the original input image, must be valid
431  * @param linedIntegralHorizontalAbsoluteGradient The lined integral image providing horizontal absolute gradients of the original input image, must be valid
432  * @param linedIntegralVerticalSignedGradient The lined integral image providing vertical signed gradients of the original input image, must be valid
433  * @param linedIntegralVerticalAbsoluteGradient The lined integral image providing vertical absolute gradients of the original input image, must be valid
434  * @param imageWidth The width of the actual image which has been used to determine the integral images, in pixel, with range [1, infinity)
435  * @param imageHeight The height of the actual image which has been used to determine the integral images, in pixel, with range [1, infinity)
436  * @param x The horizontal location at which the detector response will be determined, with range [0, imageWidth)
437  * @param y The vertical location at which the detector response will be determined, with range [0, imageHeight)
438  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment
439  * @param shapeWidth **TODO** document once finalized
440  * @param shapeHeight **TODO** document once finalized
441  * @param stepSize **TODO** document once finalized
442  * @param topBand **TODO** document once finalized
443  * @param bottomBand **TODO** document once finalized
444  * @param minimalDelta **TODO** document once finalized
445  * @param horizontalSignedGradientPaddingElements The number of padding elements at the end of each row of the lined integral image for horizontal signed gradients, in elements, with range [0, infinity)
446  * @param horizontalAbsoluteGradientPaddingElements The number of padding elements at the end of each row of the lined integral image for horizontal absolute gradients, in elements, with range [0, infinity)
447  * @param verticalSignedGradientPaddingElements The number of padding elements at the end of each row of the lined integral image for vertical signed gradients, in elements, with range [0, infinity)
448  * @param verticalAbsoluteGradientPaddingElements The number of padding elements at the end of each row of the lined integral image for vertical absolute gradients, in elements, with range [0, infinity)
449  * @return The response of the T-shape detector, with range [0, infinity)
450  */
451  static double tShapeResponse(const int32_t* linedIntegralHorizontalSignedGradient, const uint32_t* linedIntegralHorizontalAbsoluteGradient, const int32_t* linedIntegralVerticalSignedGradient, const uint32_t* linedIntegralVerticalAbsoluteGradient, const unsigned int imageWidth, const unsigned int imageHeight, const unsigned int x, const unsigned int y, const int sign, const unsigned int shapeWidth, const unsigned int shapeHeight, const unsigned int stepSize, const unsigned int topBand, const unsigned int bottomBand, const unsigned int minimalDelta = 5u, const unsigned int horizontalSignedGradientPaddingElements = 0u, const unsigned int horizontalAbsoluteGradientPaddingElements = 0u, const unsigned int verticalSignedGradientPaddingElements = 0u, const unsigned int verticalAbsoluteGradientPaddingElements = 0u);
452  };
453 
454  /**
455  * This class implements a shape detector mainly based on variance.
456  */
457  class OCEAN_CV_DETECTOR_EXPORT PatternDetectorVarianceBased
458  {
459  public:
460 
461  /**
462  * Detects shapes in a given image.
463  * @param yFrame The frame in which the shapes will be detected, must be valid
464  * @param width The width of the frame in pixel, with range [1, infinity)
465  * @param height The height of the frame in pixel, with rang [1, infinity)
466  * @param lShapes The resulting detected L-shapes
467  * @param tShapes The resulting detected T-shapes
468  * @param xShapes The resulting detected X-shapes
469  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
470  * @param shapeWidth **TODO** document once finalized
471  * @param shapeHeight **TODO** document once finalized
472  * @param stepSize **TODO** document once finalized
473  * @param topBand **TODO** document once finalized
474  * @param bottomBand **TODO** document once finalized
475  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
476  */
477  static void detectShapes(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const float minimalThreshold = 5.421f, const unsigned int shapeWidth = 15u, const unsigned int shapeHeight = 15u, const unsigned int stepSize = 3u, const unsigned int topBand = 4u, const unsigned int bottomBand = 4u, const unsigned int framePaddingElements = 0u);
478 
479  /**
480  * Determines the detector response for an variance-based T-shape detector which is axis aligned.
481  * @param linedIntegral The lined integral image of pixel intensities of the original input image, must be valid
482  * @param linedIntegralSquare The lined integral image of squared pixel intensities of the original input image, must be valid
483  * @param width The width of the actual image which has been used to determine the integral images, in pixel, with range [1, infinity)
484  * @param height The height of the actual image which has been used to determine the integral images, in pixel, with range [1, infinity)
485  * @param x The horizontal location at which the detector response will be determined, with range [0, imageWidth)
486  * @param y The vertical location at which the detector response will be determined, with range [0, imageHeight)
487  * @param shapeWidth **TODO** document once finalized
488  * @param shapeHeight **TODO** document once finalized
489  * @param stepSize **TODO** document once finalized
490  * @param topBand **TODO** document once finalized
491  * @param bottomBand **TODO** document once finalized
492  * @param linedIntegralPaddingElements The number of padding elements at the end of each row of the lined integral image, in elements, with range [0, infinity)
493  * @param linedIntegralSquaredPaddingElements The number of padding elements at the end of each row of the lined integral image for squared pixel intensities, in elements, with range [0, infinity)
494  * @return The response of the T-shape detector, with range [0, infinity)
495  */
496  static float tShapeResponse(const uint32_t* linedIntegral, const uint64_t* linedIntegralSquare, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const unsigned int shapeWidth, const unsigned int shapeHeight, const unsigned int stepSize, const unsigned int topBand, const unsigned int bottomBand, const unsigned int linedIntegralPaddingElements = 0u, const unsigned int linedIntegralSquaredPaddingElements = 0u);
497  };
498 
499  /**
500  * This class implements a shape detector based on gradients and variance.
501  */
502  class OCEAN_CV_DETECTOR_EXPORT PatternDetectorGradientVarianceBased
503  {
504  protected:
505 
506  /// The width of the T-shape in pixel, with range [shapeStepSize_ + 2, infinity), must be odd.
507  static constexpr unsigned int shapeWidth_ = 15u;
508 
509  /// The height of the T-shape in pixel, with range [shapeStepSize_ + 1, infinity)
510  static constexpr unsigned int shapeHeight_ = 15u;
511 
512  /// The step size of the T-shape in pixel, with range [1, infinity), must be odd.
513  static constexpr unsigned int shapeStepSize_ = 3u;
514 
515  /// The band size of the T-shape in pixel, with range [1, infinity).
516  static constexpr unsigned int shapeBandSize_ = 4u;
517 
518  /// The width of the T-shape divided by 2, in pixel, beware: shapeWidth_2 * 2 + 1 == shapeWidth
519  static constexpr unsigned int shapeWidth_2_ = shapeWidth_ / 2u;
520 
521  /// The step size of the T-shape divided by 2, in pixel, beware: shapeStepSize_2 * 2 + 1 == shapeStepSize
522  static constexpr unsigned int shapeStepSize_2_ = shapeStepSize_ / 2u;
523 
524  static_assert(shapeWidth_ >= 1u && shapeWidth_ % 2u == 1u, "Invalid shape width!");
525  static_assert(shapeHeight_ >= shapeStepSize_ + 1u, "Invalid shape height!");
526  static_assert(shapeStepSize_ >= 1u && shapeStepSize_ % 2u == 1u, "Invalid shape step size!");
527  static_assert(shapeBandSize_ >= 1u, "Invalid shape band size!");
528 
529  static_assert(shapeWidth_ >= shapeStepSize_ + 2u, "Invalid shape height!");
530  static_assert(shapeHeight_ >= shapeStepSize_ + 1u, "Invalid shape height!");
531 
532  public:
533 
534  /**
535  * Detects shapes in a given image while applying floating-point precision.
536  * @param yFrame The frame in which the shapes will be detected, must be valid
537  * @param width The width of the frame in pixel, with range [1, infinity)
538  * @param height The height of the frame in pixel, with range [1, 2^16 / width)
539  * @param lShapes The resulting detected L-shapes
540  * @param tShapes The resulting detected T-shapes
541  * @param xShapes The resulting detected X-shapes
542  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment, 0 to accept shapes with both signs
543  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
544  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
545  * @param topDownResponseFrame Optional resulting response frame for the top-down direction
546  * @param bottomUpResponseFrame Optional resulting response frame for the bottom-up direction
547  */
548  static void detectShapesF(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const int sign, const float minimalThreshold = 6.0f, const unsigned int framePaddingElements = 0u, Frame* topDownResponseFrame = nullptr, Frame* bottomUpResponseFrame = nullptr);
549 
550  /**
551  * Detects shapes in a given image while applying integer precision.
552  * @param yFrame The frame in which the shapes will be detected, must be valid
553  * @param width The width of the frame in pixel, with range [1, infinity)
554  * @param height The height of the frame in pixel, with range [1, 2^16 / width)
555  * @param lShapes The resulting detected L-shapes
556  * @param tShapes The resulting detected T-shapes
557  * @param xShapes The resulting detected X-shapes
558  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment, 0 to accept shapes with both signs
559  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
560  * @param framePaddingElements The number of padding elements at the end of each frame row, in elements, with range [0, infinity)
561  * @param topDownResponseFrame Optional resulting response frame for the top-down direction
562  * @param bottomUpResponseFrame Optional resulting response frame for the bottom-up direction
563  */
564  static void detectShapesI(const uint8_t* const yFrame, const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const int sign, const float minimalThreshold = 6.0f, const unsigned int framePaddingElements = 0u, Frame* topDownResponseFrame = nullptr, Frame* bottomUpResponseFrame = nullptr);
565 
566  protected:
567 
568  /**
569  * Returns the width of the horizontal response frame.
570  * @param width The width of the image for which the horizontal response will be determined, in pixel, with range [20, infinity)
571  * @return The width of the horizontal response frame, in pixel, which is: width - shapeWidth + 1
572  */
573  static inline unsigned int determineHorizontalResponseWidth(const unsigned int width);
574 
575  /**
576  * Returns the height of the horizontal response frame.
577  * @param height The height of the image for which the horizontal response will be determined, in pixel, with range [20, infinity)
578  * @return The height of the horizontal response frame, in pixel, which is: height - (shapeBandSize * 2 + shapeStepSize) + 1
579  */
580  static inline unsigned int determineHorizontalResponseHeight(const unsigned int height);
581 
582  /**
583  * Returns the width of the vertical response frame.
584  * @param width The width of the image for which the vertical response will be determined, in pixel, with range [20, infinity)
585  * @return The width of the vertical response frame, in pixel, which is: width - (shapeBandSize * 2 + shapeStepSize) + 1
586  */
587  static inline unsigned int determineVerticalResponseWidth(const unsigned int width);
588 
589  /**
590  * Returns the height of the vertical response frame.
591  * @param height The height of the image for which the vertical response will be determined, in pixel, with range [20, infinity)
592  * @return The height of the vertical response frame, in pixel, which is: height - (shapeHeight - shapeStepSize) + 1
593  */
594  static inline unsigned int determineVerticalResponseHeight(const unsigned int height);
595 
596  /**
597  * Returns the translation offset in x-direction between the horizontal top-down response location and the frame.
598  * @return The translation between response and frame in x-direction
599  */
600  static constexpr int frameX_T_topDownHorizontalResponseX();
601 
602  /**
603  * Returns the translation offset in y-direction between the horizontal top-down response location and the frame.
604  * @return The translation between response and frame in y-direction
605  */
606  static constexpr int frameY_T_topDownHorizontalResponseY();
607 
608  /**
609  * Returns the translation offset in x-direction between the vertical top-down response location and the frame.
610  * @return The translation between response and frame in x-direction
611  */
612  static constexpr int frameX_T_topDownVerticalResponseX();
613 
614  /**
615  * Returns the translation offset in y-direction between the vertical top-down response location and the frame.
616  * @return The translation between response and frame in y-direction
617  */
618  static constexpr int frameY_T_topDownVerticalResponseY();
619 
620  /**
621  * Returns the translation offset in x-direction between the top-down response location and the frame.
622  * @return The translation between response and frame in x-direction
623  */
624  static constexpr int frameX_T_topDownResponseX();
625 
626  /**
627  * Returns the translation offset in y-direction between the top-down response location and the frame.
628  * @return The translation between response and frame in y-direction
629  */
630  static constexpr int frameY_T_topDownResponseY();
631 
632  /**
633  * Returns the translation offset in x-direction between the horizontal bottom-up response location and the frame.
634  * @return The translation between response and frame in x-direction
635  */
636  static constexpr int frameX_T_bottomUpHorizontalResponseX();
637 
638  /**
639  * Returns the translation offset in y-direction between the horizontal bottom-up response location and the frame.
640  * @return The translation between response and frame in y-direction
641  */
642  static constexpr int frameY_T_bottomUpHorizontalResponseY();
643 
644  /**
645  * Returns the translation offset in x-direction between the vertical bottom-up response location and the frame.
646  * @return The translation between response and frame in x-direction
647  */
648  static constexpr int frameX_T_bottomUpVerticalResponseX();
649 
650  /**
651  * Returns the translation offset in y-direction between the vertical bottom-up response location and the frame.
652  * @return The translation between response and frame in y-direction
653  */
654  static constexpr int frameY_T_bottomUpVerticalResponseY();
655 
656  /**
657  * Returns the translation offset in x-direction between the bottom-up response location and the frame.
658  * @return The translation between response and frame in x-direction
659  */
660  static constexpr int frameX_T_bottomUpResponseX();
661 
662  /**
663  * Returns the translation offset in y-direction between the bottom-up response location and the frame.
664  * @return The translation between response and frame in y-direction
665  */
666  static constexpr int frameY_T_bottomUpResponseY();
667 
668  /**
669  * Determines the integer horizontal responses for the T-shape and stores the results in a given response image/buffer.
670  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
671  * The response is stored at the upper left pixel in the response area, the response area has size (shapeWidth)x(shapeBandSize * 2 + shapeStepSize).<br>
672  * The response offset for the top-down T-shape is (shapeWidth / 2)x(shapeBandSize + shapeStepSize / 2).
673  * @param linedIntegralAndSquared The lined mean and mean squared integral image of the original yFrame, with resolution ((width + 1 * 2)x(height + 1), must be valid
674  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
675  * @param height The height of the original yFrame, in pixel, with range [20, 2^16 / width)
676  * @param horizontalResponses Resulting horizontal response frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
677  * @param linedIntegralAndSquaredPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
678  * @param horizontalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
679  * @tparam tUseSIMD True, to use SIMD instructions if possible; False; to use standard compiler result
680  * @see CV::IntegralImage::createLinedImageAndSquared().
681  */
682  template <bool tUseSIMD>
683  static void determineHorizontalResponsesI(const uint32_t* linedIntegralAndSquared, const unsigned int width, const unsigned int height, int32_t* horizontalResponses, const unsigned int linedIntegralAndSquaredPaddingElements = 0u, const unsigned int horizontalResponsesPaddingElements = 0u);
684 
685  /**
686  * Determines the integer horizontal responses for the T-shape and stores the results in a given response image/buffer.
687  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
688  * The response is stored at the upper left pixel in the response area, the response area has size (shapeWidth)x(shapeBandSize * 2 + shapeStepSize).<br>
689  * The response offset for the top-down T-shape is (shapeWidth / 2)x(shapeBandSize + shapeStepSize / 2).
690  * @param linedIntegral The lined mean integral image of the original yFrame, with resolution (width + 1)x(height + 1), must be valid
691  * @param linedIntegralSquared The lined mean squared integral image of the original yFrame, with resolution (width + 1)x(height + 1), must be valid
692  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
693  * @param height The height of the original yFrame, in pixel, with range [20, infinity)
694  * @param horizontalResponses Resulting horizontal response frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
695  * @param linedIntegralPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
696  * @param linedIntegralSquaredPaddingElements Optional number of padding elements at the end of each integral squared image, in elements, with range [0, infinity)
697  * @param horizontalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
698  * @tparam tUseSIMD True, to use SIMD instructions if possible; False; to use standard compiler result
699  * @see CV::IntegralImage::createLinedImageAndSquared().
700  */
701  template <bool tUseSIMD>
702  static void determineHorizontalResponsesI(const uint32_t* linedIntegral, const uint64_t* linedIntegralSquared, const unsigned int width, const unsigned int height, int32_t* horizontalResponses, const unsigned int linedIntegralPaddingElements = 0u, const unsigned int linedIntegralSquaredPaddingElements = 0u, const unsigned int horizontalResponsesPaddingElements = 0u);
703 
704  /**
705  * Determines the floating-point horizontal responses for the T-shape and stores the results in a given response image/buffer.
706  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
707  * The response is stored at the upper left pixel in the response area, the response area has size (shapeWidth)x(shapeBandSize * 2 + shapeStepSize).<br>
708  * The response offset for the top-down T-shape is (shapeWidth / 2)x(shapeBandSize + shapeStepSize / 2).
709  * @param linedIntegralAndSquared The lined mean and mean squared integral image of the original yFrame, with resolution ((width + 1 * 2)x(height + 1), must be valid
710  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
711  * @param height The height of the original yFrame, in pixel, with range [20, 2^16 / width)
712  * @param horizontalResponses Resulting horizontal response frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
713  * @param linedIntegralAndSquaredPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
714  * @param horizontalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
715  * @tparam tSquaredResponse True, to determine the squared response (avoiding sqrt calculations and normalizing with variances); False, to determine the responses normalized with deviations
716  */
717  template <bool tSquaredResponse>
718  static void determineHorizontalResponsesF(const uint32_t* linedIntegralAndSquared, const unsigned int width, const unsigned int height, float* horizontalResponses, const unsigned int linedIntegralAndSquaredPaddingElements = 0u, const unsigned int horizontalResponsesPaddingElements = 0u);
719 
720  /**
721  * Determines the integer vertical responses for the T-shape and stores the results in a given response image/buffer.
722  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
723  * The response is stored at the upper left pixel in the response area, the response area has size (shapeBandSize * 2 + shapeStepSize)x(shapeHeight - shapeStepSize).<br>
724  * The response offset for the top-down T-shape is (shapeBandSize + shapeStepSize_ / 2)x(-shapeStepSize / 2 - 1).
725  * @param linedIntegralAndSquared The lined mean and mean squared integral image of the original yFrame, with resolution ((width + 1 * 2)x(height + 1), must be valid
726  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
727  * @param height The height of the original yFrame, in pixel, with range [20, 2^16 / width)
728  * @param verticalResponses Resulting vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
729  * @param linedIntegralAndSquaredPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
730  * @param verticalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
731  * @tparam tUseSIMD True, to use SIMD instructions if possible; False; to use standard compiler result
732  */
733  template <bool tUseSIMD>
734  static void determineVerticalResponsesI(const uint32_t* linedIntegralAndSquared, const unsigned int width, const unsigned int height, int32_t* verticalResponses, const unsigned int linedIntegralAndSquaredPaddingElements = 0u, const unsigned int verticalResponsesPaddingElements = 0u);
735 
736  /**
737  * Determines the integer vertical responses for the T-shape and stores the results in a given response image/buffer.
738  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
739  * The response is stored at the upper left pixel in the response area, the response area has size (shapeBandSize * 2 + shapeStepSize)x(shapeHeight - shapeStepSize).<br>
740  * The response offset for the top-down T-shape is (shapeBandSize + shapeStepSize_ / 2)x(-shapeStepSize / 2 - 1).
741  * @param linedIntegral The lined mean integral image of the original yFrame, with resolution (width + 1)x(height + 1), must be valid
742  * @param linedIntegralSquared The lined mean squared integral image of the original yFrame, with resolution (width + 1)x(height + 1), must be valid
743  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
744  * @param height The height of the original yFrame, in pixel, with range [20, infinity)
745  * @param verticalResponses Resulting vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
746  * @param linedIntegralPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
747  * @param linedIntegralSquaredPaddingElements Optional number of padding elements at the end of each integral squared image, in elements, with range [0, infinity)
748  * @param verticalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
749  * @tparam tUseSIMD True, to use SIMD instructions if possible; False; to use standard compiler result
750  */
751  template <bool tUseSIMD>
752  static void determineVerticalResponsesI(const uint32_t* linedIntegral, const uint64_t* linedIntegralSquared, const unsigned int width, const unsigned int height, int32_t* verticalResponses, const unsigned int linedIntegralPaddingElements = 0u, const unsigned int linedIntegralSquaredPaddingElements = 0u, const unsigned int verticalResponsesPaddingElements = 0u);
753 
754  /**
755  * Determines the floating-point vertical responses for the T-shape and stores the results in a given response image/buffer.
756  * The resolution of the response image is smaller than the original yFrame, the buffer does not contain zero responses at the boundaries of the image.<br>
757  * The response is stored at the upper left pixel in the response area, the response area has size (shapeBandSize * 2 + shapeStepSize)x(shapeHeight - shapeStepSize).<br>
758  * The response offset for the top-down T-shape is (shapeBandSize + shapeStepSize_ / 2)x(-shapeStepSize / 2 - 1).
759  * @param linedIntegralAndSquared The lined mean and mean squared integral image of the original yFrame, with resolution ((width + 1 * 2)x(height + 1), must be valid
760  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
761  * @param height The height of the original yFrame, in pixel, with range [20, 2^16 / width)
762  * @param verticalResponses Resulting vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
763  * @param linedIntegralAndSquaredPaddingElements Optional number of padding elements at the end of each integral image, in elements, with range [0, infinity)
764  * @param verticalResponsesPaddingElements Optional number of padding elements at the end of each response image, in elements, with range [0, infinity)
765  * @tparam tSquaredResponse True, to determine the squared response (avoiding sqrt calculations and normalizing with variances); False, to determine the responses normalized with deviations
766  */
767  template <bool tSquaredResponse>
768  static void determineVerticalResponsesF(const uint32_t* linedIntegralAndSquared, const unsigned int width, const unsigned int height, float* verticalResponses, const unsigned int linedIntegralAndSquaredPaddingElements = 0u, const unsigned int verticalResponsesPaddingElements = 0u);
769 
770  /**
771  * Determines the floating-point T-shape responses for the top-down direction.
772  * @param horizontalResponses The horizontal response frame, frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
773  * @param verticalResponses The vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
774  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
775  * @param height The height of the original yFrame, in pixel, with range [20, infinity)
776  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment, 0 to accept shapes with both signs
777  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
778  * @param nonMaximumSuppression The non-maximum-suppression object in which the responses will be stored, with resolution (width)x(height)
779  * @param responseFrame Optional resulting response frame if `tCreateResponseFrame = true`; nullptr if `tCreateResponseFrame = false`
780  * @tparam tSquaredResponse True, to determine the squared response (avoiding sqrt calculations and normalizing with variances); False, to determine the responses normalized with deviations
781  * @tparam tCreateResponseFrame True, to create a response frame
782  */
783  template <bool tSquaredResponse, bool tCreateResponseFrame = false>
784  static void determineTopDownResponsesF(const float* horizontalResponses, const float* verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const float minimalThreshold, CV::NonMaximumSuppression<float>& nonMaximumSuppression, Frame* responseFrame = nullptr);
785 
786  /**
787  * Determines the floating-point T-shape responses for the bottom-up direction.
788  * @param horizontalResponses The horizontal response frame, frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
789  * @param verticalResponses The vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
790  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
791  * @param height The height of the original yFrame, in pixel, with range [20, infinity)
792  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment, 0 to accept shapes with both signs
793  * @param minimalThreshold The minimal threshold for a detected shape, with range (0, infinity)
794  * @param nonMaximumSuppression The non-maximum-suppression object in which the responses will be stored, with resolution (width)x(height)
795  * @param responseFrame Optional resulting response frame if `tCreateResponseFrame = true`; nullptr if `tCreateResponseFrame = false`
796  * @tparam tSquaredResponse True, to determine the squared response (avoiding sqrt calculations and normalizing with variances); False, to determine the responses normalized with deviations
797  * @tparam tCreateResponseFrame True, to create a response frame
798  */
799  template <bool tSquaredResponse, bool tCreateResponseFrame = false>
800  static void determineBottomUpResponsesF(const float* horizontalResponses, const float* verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const float minimalThreshold, CV::NonMaximumSuppression<float>& nonMaximumSuppression, Frame* responseFrame = nullptr);
801 
802  /**
803  * Determines the integer T-shape responses for the top-down and bottom-up direction.
804  * @param horizontalResponses The horizontal response frame, frame, with resolution (width - shapeWidth + 1)x(height - (shapeBandSize * 2 + shapeStepSize) + 1), must be valid
805  * @param verticalResponses The vertical response frame, with resolution (width - (shapeBandSize * 2 + shapeStepSize) + 1)x(height - (shapeHeight - shapeStepSize) + 1), must be valid
806  * @param width The width of the original yFrame, in pixel, with range [20, infinity)
807  * @param height The height of the original yFrame, in pixel, with range [20, infinity)
808  * @param sign The sign of the shape to be detected, -1 for shapes with dark edges and bright environment, 1 for shapes with bright edges and dark environment, 0 to accept shapes with both signs
809  * @param minimalSqrThreshold The minimal squared threshold for a detected shape, with range (0, infinity)
810  * @param nonMaximumSuppressionTopDown The non-maximum-suppression object in which the top-down responses will be stored, with resolution (width)x(height)
811  * @param nonMaximumSuppressionBottomUp The non-maximum-suppression object in which the bottom-up responses will be stored, with resolution (width)x(height)
812  * @param responseFrameTopDown Optional resulting response frame for top-down responses if `tCreateResponseFrame = true`; nullptr if `tCreateResponseFrame = false`
813  * @param responseFrameBottomUp Optional resulting response frame for bottom-up responses if `tCreateResponseFrame = true`; nullptr if `tCreateResponseFrame = false`
814  * @tparam tCreateResponseFrame True, to create a response frame
815  */
816  template <bool tCreateResponseFrame = false>
817  static void determineResponsesI(const int32_t* horizontalResponses, const int32_t* verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const uint32_t minimalSqrThreshold, CV::NonMaximumSuppression<uint32_t>& nonMaximumSuppressionTopDown, CV::NonMaximumSuppression<uint32_t>& nonMaximumSuppressionBottomUp, Frame* responseFrameTopDown = nullptr, Frame* responseFrameBottomUp = nullptr);
818 
819  /**
820  * Returns whether the sign of two responses matches the expected sign.
821  * @param sign the expected sign, -1 for negative values, +1 for positive values, 0 to expect any sign as long both responses have the same sign
822  * @param horizontalResponse The signed horizontal response to check, with range (-infinity, infinity)
823  * @param verticalResponse The signed vertical response to check, with range (-infinity, infinity)
824  * @return True, if so
825  */
826  static inline bool haveCorrectSign(const int32_t sign, const float horizontalResponse, const float verticalResponse);
827 
828  /**
829  * Returns whether the sign of two responses matches the expected sign.
830  * @param sign the expected sign, -1 for negative values, +1 for positive values, 0 to expect any sign as long both responses have the same sign
831  * @param horizontalResponse The signed horizontal response to check, with range (-infinity, infinity)
832  * @param verticalResponse The signed vertical response to check, with range (-infinity, infinity)
833  * @return True, if so
834  */
835  static inline bool haveCorrectSign(const int32_t sign, const int32_t horizontalResponse, const int32_t verticalResponse);
836  };
837 
838  public:
839 
840  /**
841  * Detect approximately axis-aligned rectangles in images
842  * @param yFrame The grayscale image in which rectangles will be detected, optimal size if long edge of image is ~300 px long, must be valid
843  * @param rectangleWidth The expected width of the rectangle in the input image, range: [1, yframe.width())
844  * @param aspectRatio The aspect ratio (width : height) of the rectangles that will be detected, range: (0.01, 100)
845  * @param aspectRatioTolerance A scale factor to define a minimum and maximum acceptable aspect ratio (i.e. `1 - tolerance` and `1 + tolerance`), range: [0, 1)
846  * @param alignmentAngleTolerance The angle in radian specifying how much the orientation of a rectangle may deviate from the being aligned with the x-axis, range: [0, deg2rad(90)]
847  * @param sortRectangles If true, all detected rectangles will by sorted by their area in descending order, otherwise their order will be undefined
848  * @param lineImageBorderDistanceThreshold Optional parameter that defines a minimum distance from the image border in pixels; lines with endpoints below this threshold will be removed, range: [0, infinity)
849  * @param perpendicularSampleDistance Optional parameter which is propagated to optimizeRectangleAlongEdges(), see that func for more details, range: [1, infinity)
850  * @return A collection of detected rectangles
851  */
852  static Rectangles detectAlignedRectangles(const Frame& yFrame, const unsigned int rectangleWidth, const Scalar aspectRatio, const Scalar aspectRatioTolerance = Scalar(0.10), const Scalar alignmentAngleTolerance = Numeric::deg2rad(35), const bool sortRectangles = true, const unsigned int lineImageBorderDistanceThreshold = 5u, const unsigned int perpendicularSampleDistance = 5u);
853 
854  /**
855  * Determines all possible L-shape elements which can be extracted from a set of finite lines.
856  * @param finiteLines A collection line segments which could form L-shapes, lines that are not fully inside the image boundaries will be ignored
857  * @param width The width of the image from which the line segments were extracted, range: [1, infinity)
858  * @param height The height of the image from which the line segments were extracted, range: [1, infinity)
859  * @param thresholdDistance Threshold specifying the maximum acceptable distance between two ends of a pair of line segments in order to still be counted a L-shape, range: [0, infinity)
860  * @param thresholdAngle Angle specifying the maximum acceptable deviation from perfect orthogonality of two ends of a pair of line segements in order to be counted as a L-shape, range: [0, deg2rad(45)]
861  * @return The L-shapes found in the collection of line segments
862  */
863  static LShapes determineLShapes(const FiniteLines2& finiteLines, const unsigned int width, const unsigned int height, const Scalar thresholdDistance = Scalar(15), const Scalar thresholdAngle = Numeric::deg2rad(15));
864 
865  /**
866  * Determines all possible L-shapes, T-shapes, and X-shapes which can be extracted from two sets of finite lines.
867  * The lines in both sets are supposed to be perpendicular to each other
868  * @param horizontalFiniteLines The first set of finite lines, e.g., the horizontal finite lines, at least one
869  * @param verticalFiniteLines The second set of finite lines, e.g., the vertical finite lines, at least one
870  * @param width The width of the image from which the line segments were extracted, range: [1, infinity)
871  * @param height The height of the image from which the line segments were extracted, range: [1, infinity)
872  * @param lShapes The resulting L-shapes
873  * @param tShapes The resulting T-shapes
874  * @param xShapes The resulting X-shapes
875  * @param thresholdShortDistance The short distance threshold e.g., for L-shapes, or T-shapes, in pixel, with range [0, infinity)
876  * @param thresholdLongDistance The long distance threshold e.g., for X-shapes, in pixel, with range [0, infinity)
877  * @param thresholdShapeAngle The angle threshold for L-shapes and T-shapes, in radian, with range [0, PI/4)
878  * @param thresholdAngleXShape The angle threshold for X-shapes, in radian, with range [0, thresholdShapeAngle]
879  */
880  static void determineShapes(const FiniteLines2& horizontalFiniteLines, const FiniteLines2& verticalFiniteLines, const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const Scalar thresholdShortDistance = Scalar(2), const Scalar thresholdLongDistance = Scalar(5), const Scalar thresholdShapeAngle = Numeric::deg2rad(20), const Scalar thresholdAngleXShape = Numeric::deg2rad(5));
881 
882  /**
883  * Post-processes determined shapes and merges similar shapes.
884  * @param width The width of the detection area in pixel, with range [1, infinity)
885  * @param height The height of the detection area in pixel, with range [1, infinity)
886  * @param lShapes The L-shapes to be post-processed
887  * @param tShapes The T-shapes to be post-processed
888  * @param xShapes The X-shapes to be post-processed
889  * @param similarPointDistance The maximal distance between two shapes to count as similar, in pixel, with range [0, infinity)
890  * @param similarAngle The maximal angle between two shape directions to count as similar, in radian, with range [0, PI/2)
891  */
892  static void postAdjustShapes(const unsigned int width, const unsigned int height, LShapes& lShapes, TShapes& tShapes, XShapes& xShapes, const Scalar similarPointDistance = Scalar(1.5), const Scalar similarAngle = Numeric::deg2rad(15));
893 
894  /**
895  * Filters L-shape objects based on their direction.
896  * @param lShapes A collection of L-shapes which will be filtered
897  * @param alignmentDirection The unit vector specifying the direction in which the L-shapes should point, must be valid and have unit length
898  * @param alignmentAngleThreshold The angle in radian specifying how much the direction of L-Shapes may deviate from the alignment direction, range: [0, deg2rad(90)]
899  * @return The subset of aligned L-shapes
900  */
901  template <bool tAllowPerpendicularDirections>
902  static LShapes filterLShapesBasedOnDirection(const LShapes& lShapes, const Vector2 alignmentDirection, const Scalar alignmentAngleThreshold = Numeric::deg2rad(15));
903 
904  /**
905  * Applies a non-maximum suppression of L-shapes.
906  * @param lShapes A collection of L-shapes which will be filtered
907  * @param width The width of the image from which the line segments were extracted, range: [1, infinity)
908  * @param height The height of the image from which the line segments were extracted, range: [1, infinity)
909  * @param thresholdDistance Maximum distance between two L-shapes in order to be evaluated during non-maximum suppression (otherwise they are said to be too far apart to be neighbors), range: [0, infinity)
910  * @param thresholdAngle Maximum difference between the directions of two L-shapes in order to be evaluated during non-maximum suppresion (otherwise they are said to be to different to be neighbors), range: [0, deg2rad(90)] (in radian!)
911  * @return The subset of non-maximum-suppressed L-shapes
912  */
913  static LShapes nonMaximumSuppressionLShapes(const LShapes& lShapes, const unsigned int width, const unsigned int height, const Scalar thresholdDistance = Scalar(10), const Scalar thresholdAngle = Numeric::deg2rad(25));
914 
915  /**
916  * Determines rectangles aligned with a specified direction.
917  * @param finiteLines A collection line segments which could form rectangles, must be valid
918  * @param lShapes A collection of L-shapes extracted from the line segments, must be valid
919  * @param topLeftCornerDirection The direction of the L-shape that is located in the top-left corner of a rectangle, must have unit length
920  * @param minDistanceBetweenCorners Minimum distance in pixels between neighboring corners of detected rectangles, range: [0, infinity)
921  * @param thresholdCornerDirectionAngle Angle of maximum deviation from the top-left corner direction, range: [0, pi/4]
922  * @param thresholdConnectedShapesAngle Maximal angle between the directions of two connected L-shapes, range: [0, deg2rad(15)]
923  * @return A collection of detected rectangles
924  * @sa determineLShapes()
925  */
926  static IndexedRectangles determineAlignedRectangles(const FiniteLines2& finiteLines, const LShapes& lShapes, const Vector2& topLeftCornerDirection, const Scalar minDistanceBetweenCorners = 10, const Scalar thresholdCornerDirectionAngle = Numeric::deg2rad(15), const Scalar thresholdConnectedShapesAngle = Numeric::deg2rad(5));
927 
928  /**
929  * Determines rectangles of specific size and with certain aspect ratios.
930  * @param finiteLines A collection line segments which could form rectangles, must be valid
931  * @param lShapes A collection of L-shapes extracted from the line segments, must be valid
932  * @param rectangles A collection of rectangles extracted from the L-shapes, must be valid
933  * @param aspectRatio The aspect ratio (width : height) of the rectangles that will be filtered out, range: (0.01, 100)
934  * @param minimalWidth The minimum width of rectangles that will be filtered out, in pixels, with range: [10, infinity)
935  * @param maximalWidth The maximum width of the rectangles that will be filtered out, range: [minimalWidth, infinity)
936  * @param aspectRatioTolerance Maximum deviation of the measured aspect ratios from the specified one (`aspectRatio +/- aspectRatioTolerance`), range: [0, 1)
937  * @param orthogonalAngleTolerance Angle defining the maximum deviation from perfectly perpendicular corners of the rectangles , range: [0, pi/2) (in radian!)
938  * @return A collection of rectangles of minimum size and specified aspect ratio
939  * @sa determineAlignedRectangles()
940  */
941  static IndexedRectangles determineShapedRectangles(const FiniteLines2& finiteLines, const LShapes& lShapes, const IndexedRectangles& rectangles, const Scalar aspectRatio, const Scalar minimalWidth = 90, const Scalar maximalWidth = 250, const Scalar aspectRatioTolerance = Scalar(0.1), const Scalar orthogonalAngleTolerance = Numeric::deg2rad(10));
942 
943  /**
944  * Guesses rectangles of a specific aspect ratio from a set of upper left & right corners (provided as lShapes)
945  * Based on good upper edges, it generates candidates in two ways:
946  * - It will build rectangles with vertical edges orthogonal to the upper edge, and whose length is consistent with the aspect ratio of the keyboard.
947  * - It will build rectangles with vertical edges that follow the directions of the lshapes, and whose length is consistent with the aspect ratio of the keyboard.
948  * @param lShapes A collection of L-shapes extracted from the line segments, must be valid
949  * @param topLeftCornerDirection The direction of the L-shape that is located in the top-left corner of a rectangle, must have unit length
950  * @param aspectRatio The aspect ratio (width : height) of the rectangles that will be filtered out, range: (0.01, 10)
951  * @param imageHeight The height of the images used for detection (needed to check if the generated lower corners are out of bounds), range: (0, infinity)
952  * @param maxNumberOfCandidates The maximum number of candidates that we would like to generate (used to keep compute bounded). Range: [1, infinity)
953  * @param thresholdCornerDirectionAngle Angle of maximum deviation from the top-left corner direction, range: [0, pi/4]
954  * @param thresholdConnectedShapesAngle Maximal angle between the directions of two connected L-shapes, range: [0, deg2rad(15)]
955  * @param minimalRectangleWidth The minimum width of rectangles that will be filtered out, in pixels, with range: [10, infinity)
956  * @param maximalRectangleWidth The maximum width of the rectangles that will be filtered out, in pixels, with range: [minimalWidth, infinity)
957  * @param numCandidatePairsToGeneratePerEdge Once a good upper edge is found we will generate this number of candidate pairs. First candidates use the exact aspect ratio and the following ones build rectangles with increasingly long vertical edges. Range: [1, 10]
958  * @param sideEdgeRatioMultiplier To apply a perturbed aspect ratio of the keyboard model (wrt the nominal value) when generating the candidates, with range: [0.5, 2]
959  * @return A collection of rectangles of minimum size and specified aspect ratio
960  * @sa determineAlignedRectangles()
961  */
962  static Rectangles guessShapedRectanglesFromUpperCorners(const LShapes& lShapes, const Vector2& topLeftCornerDirection, const Scalar aspectRatio, const unsigned int imageHeight, const unsigned int maxNumberOfCandidates, const Scalar thresholdCornerDirectionAngle = Numeric::deg2rad(15), const Scalar thresholdConnectedShapesAngle = Numeric::deg2rad(5), const Scalar minimalRectangleWidth = 90, const Scalar maximalRectangleWidth = 250, const unsigned int numCandidatePairsToGeneratePerEdge = 1u, const Scalar sideEdgeRatioMultiplier = 1.0);
963 
964  /**
965  * Checks whether two L-shapes are connected based on their orientation and edge alignment.
966  * @param lShapeA First L-shape, must be valid
967  * @param lShapeB Second L-Shape, must be valid
968  * @param directionA The edge of `lShapeA` that points into the direction of `lShapeB`
969  * @param directionB The edge of `lShapeB` that points into the direciton of `lShapeA`
970  * @param thresholdAngleCos The cosine of the angle that defines the maximum difference in the orientation of the direction vectors and the vector connecting the two L-shapes, range: [cos(0), cos(deg2rad(15))]
971  * @return True if the two L-shapes are connected, otherwise false
972  */
973  static inline bool areLShapesConnected(const LShape& lShapeA, const LShape& lShapeB, const Vector2& directionA, const Vector2& directionB, const Scalar thresholdAngleCos = Numeric::cos(Numeric::deg2rad(5)));
974 
975  /**
976  * Removes finite lines with end points too close to the frame border.
977  * @param finiteLines A collection of line segments that will be filtered based on the distance of their end points to the border of an image, must be valid
978  * @param width The width of the image that these line segments were extracted from, range: (thresholdDistance, infinity)
979  * @param height The height of the image that these line segments were extracted from, range: (thresholdDistance, infinity)
980  * @param thresholdDistance Lines with end points close to the image border than this value will be discarded, in pixels, range: [0, infinity)
981  */
982  static void removeLinesTooCloseToBorder(FiniteLines2& finiteLines, const unsigned int width, const unsigned int height, const Scalar thresholdDistance = Scalar(10));
983 
984  /**
985  * Optimize the location of a rectangle to its corresponding image edges
986  * Fits the line segments of a rectangle that was detected in an image to the corresponding image edges.
987  * @param yFrame A grayscale image in which the specified line will be fitted to its corresponding image edge, must be valid (1 channel, 8-bit)
988  * @param rectangle The rectangle that will be fitted to its corresponding image edges, must be valid
989  * @param perpendicularSampleDistance Defines the extent of the search direction which is perpendicular to the direction of the line, range: [1, infinity)
990  * @return True if the rectangle has been optimzed, otherwise false
991  */
992  static bool optimizeRectangleAlongEdges(const Frame& yFrame, Rectangle& rectangle, const unsigned int perpendicularSampleDistance = 5u);
993 
994  /**
995  * Optimize the location of a line to that of a corresponding image edge
996  * For line segments extracted from an image, this function "snaps" the line segments to its corresponding image edges
997  * @param yFrame A grayscale image in which the specified line will be fitted to its corresponding image edge, must be valid (1 channel, 8-bit)
998  * @param line The line that will be fitted to its corresponding image edge, must be valid
999  * @param optimizedLine The resulting optimized line
1000  * @param perpendicularSampleDistance Defines the extent of the search direction which is perpendicular to the direction of the line, range: [1, infinity)
1001  * @param sampleLocations Number of equi-distant locations along the line on which the line position will be optimized, range: [2, infinity)
1002  * @param minimalValidSampleLocations Minimum of required sample locations for an optimization to count as meaningful/successful,range: [2, infinity)
1003  * @param sampleLocationsPercent Ignore this; only for development purposes
1004  * @return True if the line has been optimzed, otherwise false
1005  */
1006  static bool optimizeLineAlongEdge(const Frame& yFrame, const FiniteLine2& line, Line2& optimizedLine, const unsigned int perpendicularSampleDistance = 5u, const unsigned int sampleLocations = 30u, const unsigned int minimalValidSampleLocations = 5u, const Scalars& sampleLocationsPercent = Scalars());
1007 
1008  /**
1009  * Returns true if the area of the first rectangle is larger than that of the second rectangle
1010  * @param firstRectangle The first rectangle to used in the comparison
1011  * @param secondRectangle The second rectangle to be used in the comparison
1012  * @return True if the area of first rectangle is larger than the area of the second rectangle, otherwise false
1013  */
1014  static inline bool hasGreaterArea(const Rectangle& firstRectangle, const Rectangle& secondRectangle);
1015 };
1016 
1018  shapeType_(ST_INVALID),
1019  finiteLineIndex0_((unsigned int)(-1)),
1020  finiteLineIndex1_((unsigned int)(-1)),
1021  position_(0, 0)
1022 {
1023  // nothing to do here
1024 }
1025 
1026 inline ShapeDetector::TwoLineShape::TwoLineShape(const ShapeType shapeType, const Vector2& position, const Scalar score) :
1027  shapeType_(shapeType),
1028  finiteLineIndex0_((unsigned int)(-1)),
1029  finiteLineIndex1_((unsigned int)(-1)),
1030  position_(position),
1031  score_(score)
1032 {
1033  ocean_assert(shapeType_ != ST_INVALID);
1034 
1035  ocean_assert(score_ >= Scalar(0));
1036 }
1037 
1038 inline ShapeDetector::TwoLineShape::TwoLineShape(const ShapeType shapeType, const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Scalar score) :
1039  shapeType_(shapeType),
1040  finiteLineIndex0_(finiteLineIndex0),
1041  finiteLineIndex1_(finiteLineIndex1),
1042  position_(position),
1043  score_(score)
1044 {
1045  ocean_assert(shapeType_ != ST_INVALID);
1046 
1047  ocean_assert(score_ >= Scalar(0));
1048 }
1049 
1051 {
1052  return shapeType_;
1053 }
1054 
1056 {
1057  return finiteLineIndex0_;
1058 }
1059 
1061 {
1062  return finiteLineIndex1_;
1063 }
1064 
1065 inline unsigned int ShapeDetector::TwoLineShape::finiteLineIndex(const unsigned int index) const
1066 {
1067  ocean_assert(index <= 1u);
1068  return index == 0u ? finiteLineIndex0() : finiteLineIndex1();
1069 }
1070 
1072 {
1073  return position_;
1074 }
1075 
1077 {
1078  position_ = position;
1079 }
1080 
1082 {
1083  return score_;
1084 }
1085 
1087  TwoLineShape()
1088 {
1089  // nothing to do here
1090 }
1091 
1092 inline ShapeDetector::LShape::LShape(const Vector2& position, const Vector2& direction, const Vector2& edgeLeft, const Vector2& edgeRight, const Scalar score) :
1093  TwoLineShape(ST_SHAPE_L, position, score),
1094  edgeLeft_(edgeLeft),
1095  edgeRight_(edgeRight),
1096  direction_(direction)
1097 {
1098  ocean_assert(direction_.isUnit());
1099  ocean_assert(edgeLeft_.isUnit());
1100  ocean_assert(edgeRight_.isUnit());
1101 
1102  ocean_assert(edgeLeft_.cross(edgeRight_) >= 0);
1103  ocean_assert(edgeLeft_.cross(direction_) >= 0);
1104  ocean_assert(direction_.cross(edgeRight_) >= 0);
1105 }
1106 
1107 inline ShapeDetector::LShape::LShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction, const Vector2& edgeLeft, const Vector2& edgeRight, const Scalar score) :
1108  TwoLineShape(ST_SHAPE_L, finiteLineIndex0, finiteLineIndex1, position, score),
1109  edgeLeft_(edgeLeft),
1110  edgeRight_(edgeRight),
1111  direction_(direction)
1112 {
1113  ocean_assert(direction_.isUnit());
1114  ocean_assert(edgeLeft_.isUnit());
1115  ocean_assert(edgeRight_.isUnit());
1116 
1117  ocean_assert(edgeLeft_.cross(edgeRight_) >= 0);
1118  ocean_assert(edgeLeft_.cross(direction_) >= 0);
1119  ocean_assert(direction_.cross(edgeRight_) >= 0);
1120 }
1121 
1123 {
1124  return edgeLeft_;
1125 }
1126 
1128 {
1129  return edgeRight_;
1130 }
1131 
1133 {
1134  return direction_;
1135 }
1136 
1138  TwoLineShape()
1139 {
1140  // nothing to do here
1141 }
1142 
1143 inline ShapeDetector::TShape::TShape(const Vector2& position, const Vector2& direction, const Scalar score) :
1144  TwoLineShape(ST_SHAPE_T, position, score),
1145  direction_(direction)
1146 {
1147  ocean_assert(direction_.isUnit());
1148 }
1149 
1150 inline ShapeDetector::TShape::TShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction, const Scalar score) :
1151  TwoLineShape(ST_SHAPE_T, finiteLineIndex0, finiteLineIndex1, position, score),
1152  direction_(direction)
1153 {
1154  ocean_assert(direction_.isUnit());
1155 }
1156 
1158 {
1159  return direction_;
1160 }
1161 
1163  TwoLineShape()
1164 {
1165  // nothing to do here
1166 }
1167 
1168 inline ShapeDetector::XShape::XShape(const Vector2& position, const Vector2& direction0, const Vector2& direction1, const Scalar score) :
1169  TwoLineShape(ST_SHAPE_X, position, score),
1170  direction0_(direction0),
1171  direction1_(direction1)
1172 {
1173  ocean_assert(direction0_.isUnit());
1174  ocean_assert(direction1_.isUnit());
1175  ocean_assert(Numeric::abs(direction0_ * direction1_) < Scalar(0.5));
1176 }
1177 
1178 inline ShapeDetector::XShape::XShape(const unsigned int finiteLineIndex0, const unsigned int finiteLineIndex1, const Vector2& position, const Vector2& direction0, const Vector2& direction1, const Scalar score) :
1179  TwoLineShape(ST_SHAPE_X, finiteLineIndex0, finiteLineIndex1, position, score),
1180  direction0_(direction0),
1181  direction1_(direction1)
1182 {
1183  ocean_assert(direction0_.isUnit());
1184  ocean_assert(direction1_.isUnit());
1185  ocean_assert(Numeric::abs(direction0_ * direction1_) < Scalar(0.5));
1186 }
1187 
1189 {
1190  return direction0_;
1191 }
1192 
1194 {
1195  return direction1_;
1196 }
1197 
1199 {
1200  ocean_assert(width >= shapeWidth_);
1201  return width - shapeWidth_ + 1u;
1202 }
1203 
1205 {
1206  ocean_assert(height >= shapeBandSize_ * 2u + shapeStepSize_);
1207  return height - (shapeBandSize_ * 2u + shapeStepSize_) + 1u;
1208 }
1209 
1211 {
1212  ocean_assert(width >= shapeBandSize_ * 2u + shapeStepSize_);
1213  return width - (shapeBandSize_ * 2u + shapeStepSize_) + 1u;
1214 }
1215 
1217 {
1218  ocean_assert(height >= shapeHeight_ - shapeStepSize_);
1219  return height - (shapeHeight_ - shapeStepSize_) + 1u;
1220 }
1221 
1223 {
1224  return int(shapeWidth_2_);
1225 }
1226 
1228 {
1229  return int(shapeBandSize_ + shapeStepSize_2_);
1230 }
1231 
1233 {
1234  return int(shapeBandSize_ + shapeStepSize_2_);
1235 }
1236 
1238 {
1239  return -int(shapeStepSize_2_ + 1u);
1240 }
1241 
1243 {
1244  // not allowed in constexpr: return std::max(frameX_T_topDownHorizontalResponseX(), frameX_T_topDownVerticalResponseX());
1245 
1246  return frameX_T_topDownHorizontalResponseX() > frameX_T_topDownVerticalResponseX() ? frameX_T_topDownHorizontalResponseX() : frameX_T_topDownVerticalResponseX();
1247 }
1248 
1250 {
1251  // not allowed in constexpr: return std::max(frameY_T_topDownHorizontalResponseY(), frameY_T_topDownVerticalResponseY());
1252 
1253  return frameY_T_topDownHorizontalResponseY() > frameY_T_topDownVerticalResponseY() ? frameY_T_topDownHorizontalResponseY() : frameY_T_topDownVerticalResponseY();
1254 }
1255 
1257 {
1258  return int(shapeWidth_2_);
1259 }
1260 
1262 {
1263  return int(shapeBandSize_ + shapeStepSize_2_);
1264 }
1265 
1267 {
1268  return int(shapeBandSize_ + shapeStepSize_2_);
1269 }
1270 
1272 {
1273  return int(shapeHeight_ - shapeStepSize_2_ - 1u);
1274 }
1275 
1277 {
1278  // not allowed in constexpr: return std::max(frameX_T_bottomUpHorizontalResponseX(), frameX_T_bottomUpVerticalResponseX());
1279 
1280  return frameX_T_bottomUpHorizontalResponseX() > frameX_T_bottomUpVerticalResponseX() ? frameX_T_bottomUpHorizontalResponseX() : frameX_T_bottomUpVerticalResponseX();
1281 }
1282 
1284 {
1285  // not allowed in constexpr: return std::max(frameY_T_bottomUpHorizontalResponseY(), frameY_T_bottomUpVerticalResponseY());
1286 
1287  return frameY_T_bottomUpHorizontalResponseY() > frameY_T_bottomUpVerticalResponseY() ? frameY_T_bottomUpHorizontalResponseY() : frameY_T_bottomUpVerticalResponseY();
1288 }
1289 
1290 inline bool ShapeDetector::PatternDetectorGradientVarianceBased::haveCorrectSign(const int32_t sign, const float horizontalResponse, const float verticalResponse)
1291 {
1292  if (sign < 0)
1293  {
1294  return horizontalResponse < 0.0f && verticalResponse < 0.0f;
1295  }
1296  else if (sign > 0)
1297  {
1298  return horizontalResponse > 0.0f && verticalResponse > 0.0f;
1299  }
1300  else
1301  {
1302  ocean_assert(sign == 0);
1303  return (horizontalResponse < 0.0f && verticalResponse < 0.0f) || (horizontalResponse > 0.0f && verticalResponse > 0.0f);
1304  }
1305 }
1306 
1307 inline bool ShapeDetector::PatternDetectorGradientVarianceBased::haveCorrectSign(const int32_t sign, const int32_t horizontalResponse, const int32_t verticalResponse)
1308 {
1309  if (sign < 0)
1310  {
1311  return horizontalResponse < 0 && verticalResponse < 0;
1312  }
1313  else if (sign > 0)
1314  {
1315  return horizontalResponse > 0 && verticalResponse > 0;
1316  }
1317  else
1318  {
1319  ocean_assert(sign == 0);
1320  return (horizontalResponse < 0 && verticalResponse < 0) || (horizontalResponse > 0 && verticalResponse > 0);
1321  }
1322 }
1323 
1324 template <bool tAllowPerpendicularDirections>
1325 ShapeDetector::LShapes ShapeDetector::filterLShapesBasedOnDirection(const LShapes& lShapes, const Vector2 alignmentDirection, const Scalar alignmentAngleThreshold)
1326 {
1327  ocean_assert(alignmentDirection.isUnit());
1328  ocean_assert(alignmentAngleThreshold >= 0 && alignmentAngleThreshold <= Numeric::pi_2());
1329 
1330  const Vector2 perpendicularAlignmentDirection = alignmentDirection.perpendicular();
1331  ocean_assert(perpendicularAlignmentDirection.isUnit());
1332 
1333  const Scalar alginmentAngleThresholdCos = Numeric::cos(alignmentAngleThreshold);
1334 
1335  LShapes filteredLShapes;
1336  filteredLShapes.reserve(lShapes.size());
1337 
1338  for (const LShape& lShape : lShapes)
1339  {
1340  if (Numeric::abs(lShape.direction() * alignmentDirection) >= alginmentAngleThresholdCos
1341  || (tAllowPerpendicularDirections && Numeric::abs(lShape.direction() * perpendicularAlignmentDirection) >= alginmentAngleThresholdCos))
1342  {
1343  filteredLShapes.push_back(lShape);
1344  }
1345  }
1346 
1347  return filteredLShapes;
1348 }
1349 
1350 inline bool ShapeDetector::areLShapesConnected(const LShape& lShapeA, const LShape& lShapeB, const Vector2& directionA, const Vector2& directionB, const Scalar thresholdAngleCos)
1351 {
1352  ocean_assert(thresholdAngleCos >= Numeric::cos(Numeric::deg2rad(15)) && thresholdAngleCos <= Numeric::cos(Numeric::deg2rad(0)));
1353  ocean_assert(directionA.isUnit() && directionB.isUnit());
1354 
1355  const Vector2 direction = (lShapeB.position() - lShapeA.position()).normalized();
1356 
1357  if (directionA * direction < thresholdAngleCos)
1358  {
1359  // non of the two finite lines of the first L-shape has the same direction
1360  return false;
1361  }
1362 
1363  if (-(directionB * direction) < thresholdAngleCos)
1364  {
1365  // non of the two finite lines of the first L-shape has the same direction
1366  return false;
1367  }
1368 
1369  return true;
1370 }
1371 
1372 inline bool ShapeDetector::hasGreaterArea(const Rectangle& firstRectangle, const Rectangle& secondRectangle)
1373 {
1374  ocean_assert(Triangle2(firstRectangle[0], firstRectangle[1], firstRectangle[2]).isValid() && Triangle2(firstRectangle[2], firstRectangle[3], firstRectangle[0]).isValid());
1375  ocean_assert(Triangle2(secondRectangle[0], secondRectangle[1], secondRectangle[2]).isValid() && Triangle2(secondRectangle[2], secondRectangle[3], secondRectangle[0]).isValid());
1376 
1377  const Scalar areaFirstRectangle = Triangle2(firstRectangle[0], firstRectangle[1], firstRectangle[2]).area2() + Triangle2(firstRectangle[2], firstRectangle[3], firstRectangle[0]).area2();
1378  const Scalar areaSecondRectangle = Triangle2(secondRectangle[0], secondRectangle[1], secondRectangle[2]).area2() + Triangle2(secondRectangle[2], secondRectangle[3], secondRectangle[0]).area2();
1379 
1380  return areaFirstRectangle > areaSecondRectangle;
1381 }
1382 
1383 } // namespace Detector
1384 
1385 } // namespace CV
1386 
1387 } // namespace Ocean
1388 
1389 #endif // META_OCEAN_CV_DETECTOR_SHAPE_DETECTOR_H
This class implements an L-shape element like a corner of a rectangle.
Definition: ShapeDetector.h:175
const Vector2 & edgeLeft() const
Returns the left edge of this L-shape.
Definition: ShapeDetector.h:1122
Vector2 edgeLeft_
The left edge of this L-shape.
Definition: ShapeDetector.h:226
Vector2 edgeRight_
The right edge of this L-shape.
Definition: ShapeDetector.h:229
LShape()
Creates an invalid L-shape object.
Definition: ShapeDetector.h:1086
Vector2 direction_
The direction of this L-shape.
Definition: ShapeDetector.h:232
const Vector2 & direction() const
Returns the direction of this L-shape.
Definition: ShapeDetector.h:1132
const Vector2 & edgeRight() const
Returns the right edge of this L-shape.
Definition: ShapeDetector.h:1127
This class implements a shape detector mainly based on gradients.
Definition: ShapeDetector.h:405
static double tShapeResponse(const int32_t *linedIntegralHorizontalSignedGradient, const uint32_t *linedIntegralHorizontalAbsoluteGradient, const int32_t *linedIntegralVerticalSignedGradient, const uint32_t *linedIntegralVerticalAbsoluteGradient, const unsigned int imageWidth, const unsigned int imageHeight, const unsigned int x, const unsigned int y, const int sign, const unsigned int shapeWidth, const unsigned int shapeHeight, const unsigned int stepSize, const unsigned int topBand, const unsigned int bottomBand, const unsigned int minimalDelta=5u, const unsigned int horizontalSignedGradientPaddingElements=0u, const unsigned int horizontalAbsoluteGradientPaddingElements=0u, const unsigned int verticalSignedGradientPaddingElements=0u, const unsigned int verticalAbsoluteGradientPaddingElements=0u)
Determines the detector response for an gradient-based T-shape detector which is axis aligned.
static void detectShapes(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const int sign, const double minimalThreshold=5.0, const unsigned int shapeWidth=15u, const unsigned int shapeHeight=15u, const unsigned int stepSize=3u, const unsigned int topBand=4u, const unsigned int bottomBand=4u, const unsigned int minimalDelta=5u, const unsigned int framePaddingElements=0u)
Detects shapes in a given image.
This class implements a shape detector based on gradients and variance.
Definition: ShapeDetector.h:503
static void determineVerticalResponsesI(const uint32_t *linedIntegral, const uint64_t *linedIntegralSquared, const unsigned int width, const unsigned int height, int32_t *verticalResponses, const unsigned int linedIntegralPaddingElements=0u, const unsigned int linedIntegralSquaredPaddingElements=0u, const unsigned int verticalResponsesPaddingElements=0u)
Determines the integer vertical responses for the T-shape and stores the results in a given response ...
static constexpr int frameY_T_topDownResponseY()
Returns the translation offset in y-direction between the top-down response location and the frame.
Definition: ShapeDetector.h:1249
static constexpr int frameX_T_bottomUpVerticalResponseX()
Returns the translation offset in x-direction between the vertical bottom-up response location and th...
Definition: ShapeDetector.h:1266
static void detectShapesI(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const int sign, const float minimalThreshold=6.0f, const unsigned int framePaddingElements=0u, Frame *topDownResponseFrame=nullptr, Frame *bottomUpResponseFrame=nullptr)
Detects shapes in a given image while applying integer precision.
static constexpr int frameX_T_topDownVerticalResponseX()
Returns the translation offset in x-direction between the vertical top-down response location and the...
Definition: ShapeDetector.h:1232
static void determineVerticalResponsesI(const uint32_t *linedIntegralAndSquared, const unsigned int width, const unsigned int height, int32_t *verticalResponses, const unsigned int linedIntegralAndSquaredPaddingElements=0u, const unsigned int verticalResponsesPaddingElements=0u)
Determines the integer vertical responses for the T-shape and stores the results in a given response ...
static void determineVerticalResponsesF(const uint32_t *linedIntegralAndSquared, const unsigned int width, const unsigned int height, float *verticalResponses, const unsigned int linedIntegralAndSquaredPaddingElements=0u, const unsigned int verticalResponsesPaddingElements=0u)
Determines the floating-point vertical responses for the T-shape and stores the results in a given re...
static constexpr int frameX_T_topDownHorizontalResponseX()
Returns the translation offset in x-direction between the horizontal top-down response location and t...
Definition: ShapeDetector.h:1222
static constexpr int frameY_T_bottomUpVerticalResponseY()
Returns the translation offset in y-direction between the vertical bottom-up response location and th...
Definition: ShapeDetector.h:1271
static constexpr int frameY_T_bottomUpHorizontalResponseY()
Returns the translation offset in y-direction between the horizontal bottom-up response location and ...
Definition: ShapeDetector.h:1261
static void determineResponsesI(const int32_t *horizontalResponses, const int32_t *verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const uint32_t minimalSqrThreshold, CV::NonMaximumSuppression< uint32_t > &nonMaximumSuppressionTopDown, CV::NonMaximumSuppression< uint32_t > &nonMaximumSuppressionBottomUp, Frame *responseFrameTopDown=nullptr, Frame *responseFrameBottomUp=nullptr)
Determines the integer T-shape responses for the top-down and bottom-up direction.
static void determineHorizontalResponsesF(const uint32_t *linedIntegralAndSquared, const unsigned int width, const unsigned int height, float *horizontalResponses, const unsigned int linedIntegralAndSquaredPaddingElements=0u, const unsigned int horizontalResponsesPaddingElements=0u)
Determines the floating-point horizontal responses for the T-shape and stores the results in a given ...
static bool haveCorrectSign(const int32_t sign, const float horizontalResponse, const float verticalResponse)
Returns whether the sign of two responses matches the expected sign.
Definition: ShapeDetector.h:1290
static void determineTopDownResponsesF(const float *horizontalResponses, const float *verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const float minimalThreshold, CV::NonMaximumSuppression< float > &nonMaximumSuppression, Frame *responseFrame=nullptr)
Determines the floating-point T-shape responses for the top-down direction.
static constexpr int frameY_T_topDownVerticalResponseY()
Returns the translation offset in y-direction between the vertical top-down response location and the...
Definition: ShapeDetector.h:1237
static unsigned int determineVerticalResponseWidth(const unsigned int width)
Returns the width of the vertical response frame.
Definition: ShapeDetector.h:1210
static unsigned int determineHorizontalResponseHeight(const unsigned int height)
Returns the height of the horizontal response frame.
Definition: ShapeDetector.h:1204
static constexpr int frameY_T_bottomUpResponseY()
Returns the translation offset in y-direction between the bottom-up response location and the frame.
Definition: ShapeDetector.h:1283
static void determineHorizontalResponsesI(const uint32_t *linedIntegralAndSquared, const unsigned int width, const unsigned int height, int32_t *horizontalResponses, const unsigned int linedIntegralAndSquaredPaddingElements=0u, const unsigned int horizontalResponsesPaddingElements=0u)
Determines the integer horizontal responses for the T-shape and stores the results in a given respons...
static void determineHorizontalResponsesI(const uint32_t *linedIntegral, const uint64_t *linedIntegralSquared, const unsigned int width, const unsigned int height, int32_t *horizontalResponses, const unsigned int linedIntegralPaddingElements=0u, const unsigned int linedIntegralSquaredPaddingElements=0u, const unsigned int horizontalResponsesPaddingElements=0u)
Determines the integer horizontal responses for the T-shape and stores the results in a given respons...
static constexpr int frameX_T_bottomUpResponseX()
Returns the translation offset in x-direction between the bottom-up response location and the frame.
Definition: ShapeDetector.h:1276
static unsigned int determineVerticalResponseHeight(const unsigned int height)
Returns the height of the vertical response frame.
Definition: ShapeDetector.h:1216
static unsigned int determineHorizontalResponseWidth(const unsigned int width)
Returns the width of the horizontal response frame.
Definition: ShapeDetector.h:1198
static constexpr int frameY_T_topDownHorizontalResponseY()
Returns the translation offset in y-direction between the horizontal top-down response location and t...
Definition: ShapeDetector.h:1227
static constexpr int frameX_T_bottomUpHorizontalResponseX()
Returns the translation offset in x-direction between the horizontal bottom-up response location and ...
Definition: ShapeDetector.h:1256
static constexpr int frameX_T_topDownResponseX()
Returns the translation offset in x-direction between the top-down response location and the frame.
Definition: ShapeDetector.h:1242
static void detectShapesF(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const int sign, const float minimalThreshold=6.0f, const unsigned int framePaddingElements=0u, Frame *topDownResponseFrame=nullptr, Frame *bottomUpResponseFrame=nullptr)
Detects shapes in a given image while applying floating-point precision.
static void determineBottomUpResponsesF(const float *horizontalResponses, const float *verticalResponses, const unsigned int width, const unsigned int height, const int32_t sign, const float minimalThreshold, CV::NonMaximumSuppression< float > &nonMaximumSuppression, Frame *responseFrame=nullptr)
Determines the floating-point T-shape responses for the bottom-up direction.
This class implements a shape detector mainly based on variance.
Definition: ShapeDetector.h:458
static void detectShapes(const uint8_t *const yFrame, const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const float minimalThreshold=5.421f, const unsigned int shapeWidth=15u, const unsigned int shapeHeight=15u, const unsigned int stepSize=3u, const unsigned int topBand=4u, const unsigned int bottomBand=4u, const unsigned int framePaddingElements=0u)
Detects shapes in a given image.
static float tShapeResponse(const uint32_t *linedIntegral, const uint64_t *linedIntegralSquare, const unsigned int width, const unsigned int height, const unsigned int x, const unsigned int y, const unsigned int shapeWidth, const unsigned int shapeHeight, const unsigned int stepSize, const unsigned int topBand, const unsigned int bottomBand, const unsigned int linedIntegralPaddingElements=0u, const unsigned int linedIntegralSquaredPaddingElements=0u)
Determines the detector response for an variance-based T-shape detector which is axis aligned.
This class implements a T-shape element like a junction connecting two lines, with one line having th...
Definition: ShapeDetector.h:249
Vector2 direction_
The direction of this T-shape.
Definition: ShapeDetector.h:284
const Vector2 & direction() const
Returns the direction of this T-shape.
Definition: ShapeDetector.h:1157
TShape()
Creates an invalid T-shape object.
Definition: ShapeDetector.h:1137
This class implements the base class for all shapes based on two lines.
Definition: ShapeDetector.h:44
void setPosition(const Vector2 &position)
Sets or changes the position of this shape.
Definition: ShapeDetector.h:1076
TwoLineShape()
Creates an invalid shape.
Definition: ShapeDetector.h:1017
ShapeType type() const
Returns the type of the shape.
Definition: ShapeDetector.h:1050
Scalar score_
The score of this L-shape.
Definition: ShapeDetector.h:147
Vector2 position_
The position of this shape.
Definition: ShapeDetector.h:144
unsigned int finiteLineIndex(const unsigned int index) const
Returns the index of the first or second finite line.
Definition: ShapeDetector.h:1065
unsigned int finiteLineIndex1() const
Returns the index of the second finite line.
Definition: ShapeDetector.h:1060
ShapeType shapeType_
The shape's type.
Definition: ShapeDetector.h:135
ShapeType
Definition of individual shape types.
Definition: ShapeDetector.h:51
@ ST_INVALID
An invalid shape type.
Definition: ShapeDetector.h:53
Scalar score() const
Returns the sore of this shape.
Definition: ShapeDetector.h:1081
unsigned int finiteLineIndex0() const
Returns the index of the first finite line.
Definition: ShapeDetector.h:1055
const Vector2 & position() const
Returns the position of this shape.
Definition: ShapeDetector.h:1071
This class implements a X-shape element like a crossing of two lines, with both lines not crossing ne...
Definition: ShapeDetector.h:302
XShape()
Creates an invalid X-shape object.
Definition: ShapeDetector.h:1162
const Vector2 & direction1() const
Return the second direction of this X-shape.
Definition: ShapeDetector.h:1193
Vector2 direction1_
The direction of the second line of this X-shape.
Definition: ShapeDetector.h:363
bool verifyShape(const uint8_t *yFrame, const unsigned int width, const unsigned int height, const bool darkShape, const unsigned int minimalValueRange, const unsigned int sampleOffset=2u, const unsigned int samples=4u, const unsigned int yFramePaddingElements=0u) const
Verifies whether this X-shape is valid based on underlying image content.
Vector2 direction0_
The direction of the first line of this X-shape.
Definition: ShapeDetector.h:360
const Vector2 & direction0() const
Returns the first direction of this X-shape.
Definition: ShapeDetector.h:1188
This class is a collection of detectors for geometric shapes.
Definition: ShapeDetector.h:37
static bool optimizeRectangleAlongEdges(const Frame &yFrame, Rectangle &rectangle, const unsigned int perpendicularSampleDistance=5u)
Optimize the location of a rectangle to its corresponding image edges Fits the line segments of a rec...
std::array< Vector2, 4 > Rectangle
A rectangle defined by its four corners (counter-clockwise direction)
Definition: ShapeDetector.h:394
static bool hasGreaterArea(const Rectangle &firstRectangle, const Rectangle &secondRectangle)
Returns true if the area of the first rectangle is larger than that of the second rectangle.
Definition: ShapeDetector.h:1372
std::vector< LShape > LShapes
Definition of a vector holding L-shape objects.
Definition: ShapeDetector.h:369
static LShapes filterLShapesBasedOnDirection(const LShapes &lShapes, const Vector2 alignmentDirection, const Scalar alignmentAngleThreshold=Numeric::deg2rad(15))
Filters L-shape objects based on their direction.
Definition: ShapeDetector.h:1325
std::vector< const CV::Detector::ShapeDetector::TwoLineShape * > TwoLineShapes
Definition of a vector holding pointers to TwoLineShapes.
Definition: ShapeDetector.h:153
std::array< Index32, 4 > IndexedRectangle
Definition of an array holding four indices e.g., of L-shape objects.
Definition: ShapeDetector.h:384
static bool areLShapesConnected(const LShape &lShapeA, const LShape &lShapeB, const Vector2 &directionA, const Vector2 &directionB, const Scalar thresholdAngleCos=Numeric::cos(Numeric::deg2rad(5)))
Checks whether two L-shapes are connected based on their orientation and edge alignment.
Definition: ShapeDetector.h:1350
static Rectangles guessShapedRectanglesFromUpperCorners(const LShapes &lShapes, const Vector2 &topLeftCornerDirection, const Scalar aspectRatio, const unsigned int imageHeight, const unsigned int maxNumberOfCandidates, const Scalar thresholdCornerDirectionAngle=Numeric::deg2rad(15), const Scalar thresholdConnectedShapesAngle=Numeric::deg2rad(5), const Scalar minimalRectangleWidth=90, const Scalar maximalRectangleWidth=250, const unsigned int numCandidatePairsToGeneratePerEdge=1u, const Scalar sideEdgeRatioMultiplier=1.0)
Guesses rectangles of a specific aspect ratio from a set of upper left & right corners (provided as l...
std::vector< Rectangle > Rectangles
A vector of rectangles.
Definition: ShapeDetector.h:399
std::vector< TShape > TShapes
Definition of a vector holding T-shape objects.
Definition: ShapeDetector.h:374
static void determineShapes(const FiniteLines2 &horizontalFiniteLines, const FiniteLines2 &verticalFiniteLines, const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const Scalar thresholdShortDistance=Scalar(2), const Scalar thresholdLongDistance=Scalar(5), const Scalar thresholdShapeAngle=Numeric::deg2rad(20), const Scalar thresholdAngleXShape=Numeric::deg2rad(5))
Determines all possible L-shapes, T-shapes, and X-shapes which can be extracted from two sets of fini...
std::vector< XShape > XShapes
Definition of a vector holding X-shape objects.
Definition: ShapeDetector.h:379
static void removeLinesTooCloseToBorder(FiniteLines2 &finiteLines, const unsigned int width, const unsigned int height, const Scalar thresholdDistance=Scalar(10))
Removes finite lines with end points too close to the frame border.
static LShapes determineLShapes(const FiniteLines2 &finiteLines, const unsigned int width, const unsigned int height, const Scalar thresholdDistance=Scalar(15), const Scalar thresholdAngle=Numeric::deg2rad(15))
Determines all possible L-shape elements which can be extracted from a set of finite lines.
std::vector< IndexedRectangle > IndexedRectangles
Definition of a vector holding rectangles.
Definition: ShapeDetector.h:389
static bool optimizeLineAlongEdge(const Frame &yFrame, const FiniteLine2 &line, Line2 &optimizedLine, const unsigned int perpendicularSampleDistance=5u, const unsigned int sampleLocations=30u, const unsigned int minimalValidSampleLocations=5u, const Scalars &sampleLocationsPercent=Scalars())
Optimize the location of a line to that of a corresponding image edge For line segments extracted fro...
static Rectangles detectAlignedRectangles(const Frame &yFrame, const unsigned int rectangleWidth, const Scalar aspectRatio, const Scalar aspectRatioTolerance=Scalar(0.10), const Scalar alignmentAngleTolerance=Numeric::deg2rad(35), const bool sortRectangles=true, const unsigned int lineImageBorderDistanceThreshold=5u, const unsigned int perpendicularSampleDistance=5u)
Detect approximately axis-aligned rectangles in images.
static void postAdjustShapes(const unsigned int width, const unsigned int height, LShapes &lShapes, TShapes &tShapes, XShapes &xShapes, const Scalar similarPointDistance=Scalar(1.5), const Scalar similarAngle=Numeric::deg2rad(15))
Post-processes determined shapes and merges similar shapes.
static LShapes nonMaximumSuppressionLShapes(const LShapes &lShapes, const unsigned int width, const unsigned int height, const Scalar thresholdDistance=Scalar(10), const Scalar thresholdAngle=Numeric::deg2rad(25))
Applies a non-maximum suppression of L-shapes.
static IndexedRectangles determineShapedRectangles(const FiniteLines2 &finiteLines, const LShapes &lShapes, const IndexedRectangles &rectangles, const Scalar aspectRatio, const Scalar minimalWidth=90, const Scalar maximalWidth=250, const Scalar aspectRatioTolerance=Scalar(0.1), const Scalar orthogonalAngleTolerance=Numeric::deg2rad(10))
Determines rectangles of specific size and with certain aspect ratios.
static IndexedRectangles determineAlignedRectangles(const FiniteLines2 &finiteLines, const LShapes &lShapes, const Vector2 &topLeftCornerDirection, const Scalar minDistanceBetweenCorners=10, const Scalar thresholdCornerDirectionAngle=Numeric::deg2rad(15), const Scalar thresholdConnectedShapesAngle=Numeric::deg2rad(5))
Determines rectangles aligned with a specified direction.
This class implements the possibility to find local maximum in a 2D array by applying a non-maximum-s...
Definition: NonMaximumSuppression.h:41
This class implements Ocean's image class.
Definition: Frame.h:1760
This class implements an infinite line in 2D space.
Definition: Line2.h:83
static constexpr T deg2rad(const T deg)
Converts deg to rad.
Definition: Numeric.h:3232
static constexpr T pi_2()
Returns PI/2 which is equivalent to 90 degree.
Definition: Numeric.h:938
static T abs(const T value)
Returns the absolute value of a given value.
Definition: Numeric.h:1220
static T cos(const T value)
Returns the cosine of a given value.
Definition: Numeric.h:1584
bool isUnit(const T eps=NumericT< T >::eps()) const
Returns whether this vector is a unit vector (whether the vector has the length 1).
Definition: Vector2.h:740
T cross(const VectorT2< T > &vector) const
Returns the cross product of two 2D vectors.
Definition: Vector2.h:544
VectorT2< T > perpendicular() const
Returns a vector perpendicular to this vectors.
Definition: Vector2.h:550
float Scalar
Definition of a scalar type.
Definition: Math.h:128
TriangleT2< Scalar > Triangle2
Definition of the Triangle2 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with sing...
Definition: Triangle2.h:21
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition: FiniteLine2.h:57
std::vector< Scalar > Scalars
Definition of a vector holding Scalar objects.
Definition: Math.h:144
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15