Ocean
Loading...
Searching...
No Matches
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
19#include "ocean/math/Vector2.h"
20
21#include <array>
22
23namespace Ocean
24{
25
26namespace CV
27{
28
29namespace Detector
30{
31
32/**
33 * This class is a collection of detectors for geometric shapes.
34 * @ingroup cvdetector
35 */
36class 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
1026inline 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
1038inline 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
1065inline 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
1092inline 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
1107inline 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
1143inline 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
1150inline 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
1168inline 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
1178inline 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
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
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
1290inline 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
1307inline 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
1324template <bool tAllowPerpendicularDirections>
1325ShapeDetector::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
1350inline 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
1372inline 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:1808
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:752
T cross(const VectorT2< T > &vector) const
Returns the cross product of two 2D vectors.
Definition Vector2.h:556
VectorT2< T > perpendicular() const
Returns a vector perpendicular to this vectors.
Definition Vector2.h:562
float Scalar
Definition of a scalar type.
Definition Math.h:129
TriangleT2< Scalar > Triangle2
Definition of the Triangle2 object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION either with sing...
Definition Triangle2.h:28
std::vector< Scalar > Scalars
Definition of a vector holding Scalar objects.
Definition Math.h:145
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition FiniteLine2.h:57
The namespace covering the entire Ocean framework.
Definition Accessor.h:15