Ocean
Canvas.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_CANVAS_H
9 #define META_OCEAN_CV_CANVAS_H
10 
11 #include "ocean/cv/CV.h"
12 
13 #include "ocean/base/DataType.h"
14 #include "ocean/base/Frame.h"
15 #include "ocean/base/Singleton.h"
16 
17 #include "ocean/cv/Bresenham.h"
18 #include "ocean/cv/PixelPosition.h"
19 
20 #include "ocean/math/Box2.h"
21 #include "ocean/math/FiniteLine2.h"
22 #include "ocean/math/Line2.h"
23 #include "ocean/math/Rotation.h"
25 #include "ocean/math/Vector3.h"
26 
27 namespace Ocean
28 {
29 
30 namespace CV
31 {
32 
33 /**
34  * This class implements canvas functions.
35  * @ingroup cv
36  */
37 class OCEAN_CV_EXPORT Canvas
38 {
39  public:
40 
41  /**
42  * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
43  * Best practice is to avoid using these functions if binary size matters,<br>
44  * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.<br>
45  */
46  class OCEAN_CV_EXPORT Comfort
47  {
48  public:
49 
50  /**
51  * Paints a point with sub-pixel accuracy.
52  * @param frame The frame in which the point will be painted, must be valid
53  * @param position Sub-pixel position of the point, with range (-infinity, infinity)x(-infinity, infinity)
54  * @param pixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
55  * @param size The size (width) of the point, in pixel, with range [1, 15] and must be odd
56  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
57  * @return True, if succeeded
58  */
59  static bool point(Frame& frame, const Vector2& position, const PixelCenter pixelCenter, const unsigned int size, const uint8_t* value = nullptr);
60  };
61 
62  protected:
63 
64  /**
65  * This class implements a helper class that provides binomial filter parameters for a specific filter size.
66  * @tparam tFilterSize Size of the binomial 1D filter, with range [1, infinity) and must be odd
67  */
68  template <unsigned int tFilterSize>
70  {
71  public:
72 
73  /**
74  * Creates a new filter factor object.
75  */
76  inline FilterFactors();
77 
78  /**
79  * Returns the filter factor for a specific index.
80  * @param index The index of the filter parameter, with range [0, tFilterSize)
81  * @return Filter parameter
82  */
83  inline unsigned int factor(const unsigned int index) const;
84 
85  /**
86  * Returns the filter factor for a specific index.
87  * If the index lies outside the filter size, than zero is returned.<br>
88  * @param index The index of the filter parameter, with range (-infinity, infinity)
89  * @return Filter parameter, or zero
90  */
91  inline unsigned int clampedFactor(const int index) const;
92 
93  /**
94  * Returns the maximal (center) filter parameter for the specified filter size.
95  * @return Maximal filter parameter
96  */
97  inline unsigned int maximalFactor() const;
98 
99  protected:
100 
101  /// The individual filter factor.
102  unsigned int factors_[tFilterSize];
103 
104  /// The maximal filter factor.
105  unsigned int maximalFactor_ = 0u;
106  };
107 
108  /**
109  * This class implements a standard font similar to a code-block like font.
110  */
111  class OCEAN_CV_EXPORT Font : public Singleton<Font>
112  {
113  friend class Singleton<Font>;
114 
115  public:
116 
117  /**
118  * This class implements one character of a font for which each pixel has as size of at most 16x16.
119  */
120  class OCEAN_CV_EXPORT Character
121  {
122  public:
123 
124  /**
125  * Creates an invalid character object.
126  */
128 
129  /**
130  * Creates a new character from a given image in which the actual character is visible.
131  * @param frame The frame in which the character is visible, with maximal resolution 16x16
132  * @param color The color of the character, must be valid
133  */
134  Character(const Frame& frame, const uint8_t* color);
135 
136  /**
137  * Creates a new frame and paints the character in the frame.
138  * The size of the frame fits with the size of the character.
139  * @param pixelFormat The pixel format of the resulting frame, must be a generic pixel format like e.g., FORMAT_Y8 or FORMAT_RGB24
140  * @param foregroundColor The foreground color to be used when painting the character, must be valid
141  * @param backgroundColor The background color to be used when paining the character, must be valid
142  * @return The frame with character
143  */
144  Frame frame(const FrameType::PixelFormat pixelFormat, const uint8_t* foregroundColor, const uint8_t* backgroundColor) const;
145 
146  /**
147  * Paints the character at the specific location in a given frame.
148  * The given location can be partially outside of the frame.
149  * @param frame The frame in which the character will be painted, must have a generic pixel format like e.g., FORMAT_Y8 or FORMAT_RGB24, must be valid
150  * @param left The horizontal start position of the character within the frame, in pixel, with range (-infinity, infinity)
151  * @param top The vertical start position of the character within the frame, in pixel, with range (-infinity, infinity)
152  * @param foregroundColor The foreground color to be used when painting the character, must be valid
153  * @param backgroundColor The optional background color to be used when paining the character, nullptr to paint the foreground pixels only
154  * @return True, if succeeded
155  */
156  bool paint(Frame& frame, const int left, const int top, const uint8_t* foregroundColor, const uint8_t* backgroundColor = nullptr) const;
157 
158  /**
159  * Returns the width of this character in pixel.
160  * @return The characters width in pixel, with range [0, 16]
161  */
162  unsigned int width() const;
163 
164  /**
165  * Returns the height of this character in pixel.
166  * @return The characters height in pixel, with range [0, 16]
167  */
168  unsigned int height() const;
169 
170  /**
171  * Returns whether this character holds valid data.
172  */
173  bool isValid() const;
174 
175  protected:
176 
177  /// The data defining the character: 1 byte width, 1 byte height, 32 bytes = 16 * 16 bits for the visual information.
178  uint8_t data_[2 + 32];
179  };
180 
181  /**
182  * Definition of a vector holding characters.
183  */
184  typedef std::vector<Character> Characters;
185 
186  public:
187 
188  /**
189  * Paints a given text into a given frame using this font.
190  * The given location can be partially outside of the frame.
191  * @param frame The frame in which the text will be painted, must have a generic pixel format like e.g., FORMAT_Y8 or FORMAT_RGB24, must be valid
192  * @param text The text to be painted, the text can contain end-of-line characters to paint the remaining the following characters in the next line, can be empty
193  * @param left The horizontal start position of the text within the frame, in pixel, with range (-infinity, infinity)
194  * @param top The vertical start position of the text within the frame, in pixel, with range (-infinity, infinity)
195  * @param foregroundColor The foreground color to be used when painting the character, must be valid
196  * @param backgroundColor The optional background color to be used when paining the character, nullptr to paint the foreground pixels only
197  * @return True, if succeeded
198  */
199  bool drawText(Frame& frame, const std::string& text, const int left, const int top, const uint8_t* foregroundColor, const uint8_t* backgroundColor = nullptr) const;
200 
201  /**
202  * Returns the bounding box a given text will occupy in pixel space when using this font.
203  * @param text The text for which the extent will be determined, can be empty
204  * @param width The width of the bounding box, in pixel, with range [0, infinity)
205  * @param height The height of the bounding box, in pixel, with range [0, infinity)
206  * @return True, if succeeded
207  */
208  bool textExtent(const std::string& text, unsigned int& width, unsigned int& height) const;
209 
210  protected:
211 
212  /**
213  * The protected constructor creating a new font.
214  */
215  Font();
216 
217  protected:
218 
219  /**
220  * The characters of this font.
221  */
223  };
224 
225  public:
226 
227  /**
228  * Returns the color values for a white color.
229  * Values of alpha channel are set to 0xFF.
230  * @param pixelFormat The pixel format for which the color will be returned
231  * @return The requested color value matching with the pixel format
232  */
233  static const uint8_t* white(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
234 
235  /**
236  * Returns the color values for a black color.
237  * Values of alpha channel are set to 0xFF.
238  * @param pixelFormat The pixel format for which the color will be returned
239  * @return The requested color value matching with the pixel format
240  */
241  static const uint8_t* black(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
242 
243  /**
244  * Returns the color values for a gray color.
245  * Values of alpha channel are set to 0xFF.
246  * @param pixelFormat The pixel format for which the color will be returned
247  * @return The requested color value matching with the pixel format
248  */
249  static const uint8_t* gray(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
250 
251  /**
252  * Returns the color values for a red color.
253  * Values of alpha channel are set to 0xFF.
254  * @param pixelFormat The pixel format for which the color will be returned
255  * @return The requested color value matching with the pixel format
256  */
257  static const uint8_t* red(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
258 
259  /**
260  * Returns the color values for a green color.
261  * Values of alpha channel are set to 0xFF.
262  * @param pixelFormat The pixel format for which the color will be returned
263  * @return The requested color value matching with the pixel format
264  */
265  static const uint8_t* green(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
266 
267  /**
268  * Returns the color values for a blue color.
269  * Values of alpha channel are set to 0xFF.
270  * @param pixelFormat The pixel format for which the color will be returned
271  * @return The requested color value matching with the pixel format
272  */
273  static const uint8_t* blue(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
274 
275  /**
276  * Returns the color values for a yellow color.
277  * Values of alpha channel are set to 0xFF.
278  * @param pixelFormat The pixel format for which the color will be returned
279  * @return The requested color value matching with the pixel format
280  */
281  static const uint8_t* yellow(const FrameType::PixelFormat pixelFormat = FrameType::FORMAT_RGB24);
282 
283  /**
284  * Paints a line with specified start and end position with pixel accuracy.
285  * The specified start and end positions will be included.
286  * @param frame The frame in which the line will be painted, must be valid
287  * @param xStart Horizontal start position, with range (-infinity, infinity)
288  * @param yStart Vertical start position, with range (-infinity, infinity)
289  * @param xEnd Horizontal end position, with range (-infinity, infinity)
290  * @param yEnd Vertical end position, with range (-infinity, infinity)
291  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
292  * @see lines().
293  */
294  static bool line(Frame& frame, const int xStart, const int yStart, const int xEnd, const int yEnd, const uint8_t* value = nullptr);
295 
296  /**
297  * Paints several lines with specified start and end positions with pixel accuracy.
298  * The specified start and end positions will be included.
299  * @param frame The frame in which the line will be painted, must be valid
300  * @param positions Interleaved start and end positions of the lines, with range (-infinity, infinity)x(-infinity, infinity)
301  * @param numberPositions Number of provided positions, should be even - otherwise the last line will not be painted
302  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
303  * @return True, if succeeded
304  * @see line().
305  */
306  static bool lines(Frame& frame, const PixelPosition* positions, const unsigned int numberPositions, const uint8_t* value = nullptr);
307 
308  /**
309  * Paints a line with specified start and end position with pixel accuracy.
310  * The specified start and end positions will be included.
311  * @param frame The frame in which the line will be painted, must be valid
312  * @param width The width of the frame in pixel, with range [1, infinity)
313  * @param height The height of the frame in pixel, with range [1, infinity)
314  * @param xStart Horizontal start position, with range (-infinity, infinity)
315  * @param yStart Vertical start position, with range (-infinity, infinity)
316  * @param xEnd Horizontal end position, with range (-infinity, infinity)
317  * @param yEnd Vertical end position, with range (-infinity, infinity)
318  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
319  * @param framePaddingElements Optional number of padding elements at the end of each row, in elements, with range [0, infinity)
320  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
321  * @see lines8BitPerChannel().
322  */
323  template <unsigned int tChannels>
324  static void line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const int xStart, const int yStart, const int xEnd, const int yEnd, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
325 
326  /**
327  * Paints several lines with specified start and end positions with pixel accuracy.
328  * The specified start and end positions will be included.
329  * @param frame The frame in which the line will be painted, must be valid
330  * @param width The width of the frame in pixel, with range [0, infinity)
331  * @param height The height of the frame in pixel, with range [0, infinity)
332  * @param positions Interleaved start and end positions of the lines, with range (-infinity, infinity)x(-infinity, infinity)
333  * @param numberPositions Number of provided positions, should be even - otherwise the last line will not be painted
334  * @param value Color value to be used, nullptr to apply 0x00 for each channel
335  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
336  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
337  * @see line8BitPerChannel().
338  */
339  template <unsigned int tChannels>
340  static void lines8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition* positions, const unsigned int numberPositions, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
341 
342  /**
343  * Paints a line with specified start and end position with sub-pixel accuracy.
344  * The specified start and end positions will be included.
345  * @param frame The frame in which the line will be painted, must be valid
346  * @param xStart Horizontal start position, with range (-infinity, infinity)
347  * @param yStart Vertical start position, with range (-infinity, infinity)
348  * @param xEnd Horizontal end position, with range (-infinity, infinity)
349  * @param yEnd Vertical end position, with range (-infinity, infinity)
350  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
351  * @return True, if succeeded
352  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
353  * @see lines().
354  */
355  template <unsigned int tSize>
356  static bool line(Frame& frame, const Scalar xStart, const Scalar yStart, const Scalar xEnd, const Scalar yEnd, const uint8_t* value = nullptr);
357 
358  /**
359  * Paints a line with specified start and end position with sub-pixel accuracy.
360  * The specified start and end positions will be included.
361  * @param frame The frame receiving the line, must be valid
362  * @param width The width of the frame in pixel, with range [1, infinity)
363  * @param height The height of the frame in pixel, with range [1, infinity)
364  * @param xStart Horizontal start position, with range (-infinity, infinity)
365  * @param yStart Vertical start position, with range (-infinity, infinity)
366  * @param xEnd Horizontal end position, with range (-infinity, infinity)
367  * @param yEnd Vertical end position, with range (-infinity, infinity)
368  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
369  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
370  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
371  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
372  * @see lines8BitPerChannel().
373  */
374  template <unsigned int tChannels, unsigned int tSize>
375  static void line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Scalar xStart, const Scalar yStart, const Scalar xEnd, const Scalar yEnd, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
376 
377  /**
378  * Paints a line with specified start and end position with sub-pixel accuracy.
379  * The specified start and end positions will be included.
380  * @param frame The frame in which the line will be painted, must be valid
381  * @param start The start position, with range (-infinity, infinity)x(-infinity, infinity)
382  * @param end The end position, with range (-infinity, infinity)x(-infinity, infinity)
383  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
384  * @return True, if succeeded
385  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
386  * @see lines().
387  */
388  template <unsigned int tSize>
389  static bool line(Frame& frame, const Vector2& start, const Vector2& end, const uint8_t* value = nullptr);
390 
391  /**
392  * Paints a line with specified start and end position with sub-pixel accuracy.
393  * The specified start and end positions will be included.
394  * @param frame The frame receiving the line, must be valid
395  * @param width The width of the frame in pixel, with range [1, infinity)
396  * @param height The height of the frame in pixel, with range [1, infinity)
397  * @param start The start position, with range (-infinity, infinity)x(-infinity, infinity)
398  * @param end The end position, with range (-infinity, infinity)x(-infinity, infinity)
399  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
400  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
401  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
402  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
403  * @see lines8BitPerChannel().
404  */
405  template <unsigned int tChannels, unsigned int tSize>
406  static void line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& start, const Vector2& end, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
407 
408  /**
409  * Paints a finite line with sub-pixel accuracy.
410  * The specified start and end positions will be included.
411  * @param frame The frame in which the line will be painted, must be valid
412  * @param line The finite line to be drawn, must be valid
413  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
414  * @return True, if succeeded
415  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
416  * @see lines8BitPerChannel().
417  */
418  template <unsigned int tSize>
419  static bool line(Frame& frame, const FiniteLine2& line, const uint8_t* value = nullptr);
420 
421  /**
422  * Paints several finite lines with sub-pixel accuracy.
423  * The specified start and end positions will be included.<br>
424  * @param frame The frame in which the line will be painted, must be valid
425  * @param lines The finite lines to be drawn, must be valid
426  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
427  * @return True, if succeeded
428  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
429  * @see line().
430  */
431  template <unsigned int tSize>
432  static inline bool lines(Frame& frame, const FiniteLines2& lines, const uint8_t* value = nullptr);
433 
434  /**
435  * Paints a finite line with sub-pixel accuracy.
436  * The specified start and end positions will be included.
437  * @param frame The frame receiving the line, must be valid
438  * @param width The width of the frame in pixel, with range [1, infinity)
439  * @param height The height of the frame in pixel, with range [1, infinity)
440  * @param line The finite line to be drawn, must be valid
441  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
442  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
443  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
444  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
445  * @see lines8BitPerChannel().
446  */
447  template <unsigned int tChannels, unsigned int tSize>
448  static void line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const FiniteLine2& line, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
449 
450  /**
451  * Paints an infinite line with sub-pixel accuracy.
452  * @param frame The frame in which the line will be painted, must be valid
453  * @param line The line to be drawn, must be valid
454  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
455  * @return True, if succeeded
456  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
457  * @see lines8BitPerChannel().
458  */
459  template <unsigned int tSize>
460  static bool line(Frame& frame, const Line2& line, const uint8_t* value = nullptr);
461 
462  /**
463  * Paints several infinite lines with sub-pixel accuracy.
464  * @param frame The frame in which the line will be painted, must be valid
465  * @param lines The lines to be drawn, must be valid
466  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
467  * @return True, if succeeded
468  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
469  * @see line().
470  */
471  template <unsigned int tSize>
472  static inline bool lines(Frame& frame, const Lines2& lines, const uint8_t* value = nullptr);
473 
474  /**
475  * Paints an infinite line with sub-pixel accuracy.
476  * @param frame The frame receiving the line, must be valid
477  * @param width The width of the frame in pixel, with range [1, infinity)
478  * @param height The height of the frame in pixel, with range [1, infinity)
479  * @param line The line to be drawn, must be valid
480  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
481  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
482  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
483  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
484  * @see lines8BitPerChannel().
485  */
486  template <unsigned int tChannels, unsigned int tSize>
487  static void line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Line2& line, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
488 
489  /**
490  * Paints a 2D axis aligned bounding box with sub-pixel accuracy.
491  * @param frame The frame in which the line will be painted, must be valid
492  * @param box The 2D axis aligned bounding box to be drawn, must be valid
493  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
494  * @return True, if succeeded
495  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
496  * @see lines8BitPerChannel().
497  */
498  template <unsigned int tSize>
499  static bool box(Frame& frame, const Box2& box, const uint8_t* value = nullptr);
500 
501  /**
502  * Paints a 2D axis aligned bounding box with sub-pixel accuracy.
503  * @param frame The frame receiving the line, must be valid
504  * @param width The width of the frame in pixel, with range [1, infinity)
505  * @param height The height of the frame in pixel, with range [1, infinity)
506  * @param box The 2D axis aligned bounding box to be drawn, must be valid
507  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
508  * @param framePaddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
509  * @tparam tChannels Number of channels of the given frame, with range [1, infinity)
510  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
511  * @see lines8BitPerChannel().
512  */
513  template <unsigned int tChannels, unsigned int tSize>
514  static void box8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Box2& box, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
515 
516  /**
517  * Paints an ellipse at a specified position with specified size.
518  * @param frame The frame receiving the elliptic blob-region, must be valid
519  * @param position Center position of the elliptic mask, with range [0, frame.width())x[0, frame.height())
520  * @param horizontal The horizontal size of the elliptic mask in pixel, must be odd, with range [3, infinity)
521  * @param vertical The vertical size of the elliptic mask in pixel, must be odd, with range [3, infinity)
522  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
523  * @return True, if succeeded
524  * @see ellipse8BitPerChannel().
525  */
526  static bool ellipse(Frame& frame, const PixelPosition& position, const unsigned int horizontal, const unsigned int vertical, const uint8_t* value = nullptr);
527 
528  /**
529  * Paints an ellipse at a specified position with specified size.
530  * @param frame The frame receiving the elliptic blob-region, must be valid
531  * @param width The width of the mask frame in pixel, with range [1, infinity)
532  * @param height The height of the mask frame in pixel, with range [1, infinity)
533  * @param position Center position of the elliptic mask, with range [0, width)x[0, height)
534  * @param horizontal The horizontal size of the elliptic mask, must be odd, with range [3, infinity)
535  * @param vertical The vertical size of the elliptic mask, must be odd, with range [3, infinity)
536  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
537  * @param paddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
538  * @tparam tChannels Number of data channels of the frame data
539  * @see ellipse().
540  */
541  template <unsigned int tChannels>
542  static inline void ellipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontal, const unsigned int vertical, const uint8_t* value = nullptr, const unsigned int paddingElements = 0u);
543 
544  /**
545  * Paints a rotated elliptic region at a specified position with specified size and rotation angle.
546  * @param frame The frame receiving the elliptic blob-region, must be valid
547  * @param position Center position of the elliptic mask, with range [0, frame.width())x[0, frame.height())
548  * @param horizontal The horizontal size of the elliptic mask in pixel, must be odd, with range [3, infinity)
549  * @param vertical The vertical size of the elliptic mask in pixel, must be odd, with range [3, infinity)
550  * @param angle Rotation angle, in radian
551  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
552  * @return True, if succeeded
553  * @see ellipse8BitPerChannel().
554  */
555  static bool rotatedEllipse(Frame& frame, const PixelPosition& position, const unsigned int horizontal, const unsigned int vertical, const Scalar angle, const uint8_t* value = nullptr);
556 
557  /**
558  * Paints a rectangle at a specified position with specified size.
559  * @param frame The frame receiving the rectangle, must be valid
560  * @param left Horizontal start position (top, left) of the rectangle in pixel, with range (-infinity, infinity)
561  * @param top Vertical start position (top, left) of the rectangle in pixel, with range (-infinity, infinity)
562  * @param xSize Width of the rectangle in pixel, with range [0u, infinity)
563  * @param ySize Height of the rectangle in pixel, with range [0u, infinity)
564  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
565  * @return True, if succeeded
566  */
567  static bool rectangle(Frame& frame, const int left, const int top, const unsigned int xSize, const unsigned int ySize, const uint8_t* value = nullptr);
568 
569  /**
570  * Paints a rectangle at a specified position with specified size.
571  * @param frame The frame receiving the rectangle, must be valid
572  * @param width The width of the frame in pixel, with range [1u, infinity)
573  * @param height The height of the frame in pixel, with range [1u, infinity)
574  * @param left Horizontal start position (top, left) of the rectangle in pixel, with range (-infinity, infinity)
575  * @param top Vertical start position (top, left) of the rectangle in pixel, with range (-infinity, infinity)
576  * @param xSize Width of the rectangle in pixel, with range [0u, infinity)
577  * @param ySize Height of the rectangle in pixel, with range [0u, infinity)
578  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
579  * @param framePaddingElements Number of padding elements at the end of each frame row, in elements, with range [0, infinity)
580  * @tparam tChannels Number of data channels of the frame data, with range [1, infinity)
581  */
582  template <unsigned int tChannels>
583  static void rectangle8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const int left, const int top, const unsigned int xSize, const unsigned int ySize, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
584 
585  /**
586  * Paints a point with sub-pixel accuracy.
587  * @param frame The frame in which the point will be painted, must be valid
588  * @param position Sub-pixel position of the point, with range (-infinity, infinity)x(-infinity, infinity)
589  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
590  * @return True, if succeeded
591  * @tparam tSize The size (width) of the point in pixel, with range [1, infinity) and must be odd
592  * @tparam tPixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
593  */
594  template <unsigned int tSize, PixelCenter tPixelCenter = CV::PC_CENTER>
595  static bool point(Frame& frame, const Vector2& position, const uint8_t* value = nullptr);
596 
597  /**
598  * Paints a point with sub-pixel accuracy.
599  * @param frame The frame in which the point will be painted
600  * @param width The width of the frame in pixel, with range [1, infinity)
601  * @param height The height of the frame in pixel, with range [1, infinity)
602  * @param position Sub-pixel position of the point, with range (-infinity, infinity)x(-infinity, infinity)
603  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
604  * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
605  * @tparam tChannels Number of frame channels, with range [1, infinity)
606  * @tparam tSize The size (width) of the point in pixel, with range [1, infinity) and must be odd
607  * @tparam tPixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
608  */
609  template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter = CV::PC_CENTER>
610  static void point8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& position, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
611 
612  /**
613  * Paints points with sub-pixel accuracy.
614  * @param frame The frame in which the point will be painted, must be valid
615  * @param positions Sub-pixel positions of the points, with range (-infinity, infinity)x(-infinity, infinity)
616  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
617  * @return True, if succeeded
618  * @tparam tSize The size (width) of the point in pixel, with range [1, infinity) and must be odd
619  * @tparam tPixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
620  */
621  template <unsigned int tSize, PixelCenter tPixelCenter = CV::PC_CENTER>
622  static bool points(Frame& frame, const Vectors2& positions, const uint8_t* value = nullptr);
623 
624  /**
625  * Paints points with sub-pixel accuracy.
626  * @param frame The frame in which the point will be painted
627  * @param width The width of the frame in pixel, with range [1, infinity)
628  * @param height The height of the frame in pixel, with range [1, infinity)
629  * @param positions Sub-pixel positions of the points, with range (-infinity, infinity)x(-infinity, infinity)
630  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
631  * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
632  * @tparam tChannels Number of frame channels, with range [1, infinity)
633  * @tparam tSize The size (width) of the point in pixel, with range [1, infinity) and must be odd
634  * @tparam tPixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
635  */
636  template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter = CV::PC_CENTER>
637  static void points8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vectors2& positions, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
638 
639  /**
640  * Fills an image area with a given color, an recursive seed-fill-algorithm is implemented.
641  * The fill area is determined by all pixels that lie in a successive 4-neighborhood of the given start position and have the same color value as the start pixel.
642  * @param frame The frame to be filled
643  * @param position The start position defining the color of the fill area, with range [0, width)x[0, height)
644  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
645  * @return True, if succeeded
646  */
647  static bool fill(Frame& frame, const PixelPosition& position, const uint8_t* value = nullptr);
648 
649  /**
650  * Fills an image area with a given color, an recursive seed-fill-algorithm is implemented.
651  * The fill area is determined by all pixels that lie in a successive 4-neighborhood of the given start position and have the same color value as the start pixel.
652  * @param frame The frame to be filled, must be valid
653  * @param width The width of the frame in pixel, with range [1, infinity)
654  * @param height The height of the frame in pixel, with range [1, infinity)
655  * @param position The start position defining the color of the fill area, with range [0, width)x[0, height)
656  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
657  * * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
658  * @tparam tChannels Number of frame channels, with range [1, infinity)
659  */
660  template <unsigned int tChannels>
661  static void fill8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const uint8_t* value = nullptr, const unsigned int framePaddingElements = 0u);
662 
663  /**
664  * Paints the outline of a polygon with sub-pixel accuracy.
665  * @param frame The frame in which the polygon will be painted, must be valid
666  * @param points The points of the polygon to be drawn, must be valid
667  * @param numberPoints The number of given polygon points, with range [0, infinity)
668  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
669  * @param closeLoop True, to close the loop of the polygon (between first and last point); False, to not paint the connection between first and last point
670  * @return True, if succeeded
671  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
672  */
673  template <unsigned int tSize>
674  static bool polygon(Frame& frame, const Vector2* points, size_t numberPoints, const uint8_t* value = nullptr, const bool closeLoop = true);
675 
676  /**
677  * Paints the outline of a polygon with sub-pixel accuracy.
678  * @param frame The frame in which the polygon will be painted, must be valid
679  * @param width The width of the frame in pixel, with range [1, infinity)
680  * @param height The height of the frame in pixel, with range [1, infinity)
681  * @param points The points of the polygon to be drawn, must be valid
682  * @param numberPoints The number of given polygon points, with range [0, infinity)
683  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
684  * @param closeLoop True, to close the loop of the polygon (between first and last point); False, to not paint the connection between first and last point
685  * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
686  * @tparam tChannels Number of frame channels, with range [1, infinity)
687  * @tparam tSize Size (thickness) of the line in pixel, with range [1, infinity) and must be odd
688  */
689  template <unsigned int tChannels, unsigned int tSize>
690  static void polygon8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2* points, size_t numberPoints, const uint8_t* value = nullptr, const bool closeLoop = true, const unsigned int framePaddingElements = 0u);
691 
692  /**
693  * Paints a given text into a given frame using the standard (code style) font supporting only one size.
694  * Use Ocean::CV::Fonts in case arbitrary fonts are necessary.
695  * The given location can be partially outside of the frame.
696  * @param frame The frame in which the text will be painted, must have a generic pixel format like e.g., FORMAT_Y8 or FORMAT_RGB24, must be valid
697  * @param text The text to be painted, the text can contain end-of-line characters to paint the remaining the following characters in the next line, can be empty
698  * @param left The horizontal start position of the text within the frame, in pixel, with range (-infinity, infinity)
699  * @param top The vertical start position of the text within the frame, in pixel, with range (-infinity, infinity)
700  * @param foregroundColor The foreground color to be used when painting the character, must be valid
701  * @param backgroundColor The optional background color to be used when paining the character, nullptr to paint the foreground pixels only
702  * @return True, if succeeded
703  * @see textExtent(), CV::Fonts::Font::drawText().
704  */
705  static bool drawText(Frame& frame, const std::string& text, const int left, const int top, const uint8_t* foregroundColor, const uint8_t* backgroundColor = nullptr);
706 
707  /**
708  * Returns the bounding box a given text will occupy in pixel space when using the standard font.
709  * @param text The text for which the extent will be determined, can be empty
710  * @param width The width of the bounding box, in pixel, with range [0, infinity)
711  * @param height The height of the bounding box, in pixel, with range [0, infinity)
712  * @return True, if succeeded
713  * @see drawText(), CV::Fonts::Font::textExtent().
714  */
715  static bool textExtent(const std::string& text, unsigned int& width, unsigned int& height);
716 
717  private:
718 
719  /**
720  * Returns a memory block to 32 bytes as a backup in case a requested color value does not exist for a specific pixel format.
721  * @return The 32 byte memory block
722  */
723  static const uint8_t* memoryBlock32Byte();
724 
725  /**
726  * Paints a ellipse at a specified position with specified size.
727  * @param frame The frame receiving the elliptic blob-region, must be valid
728  * @param width The width of the mask frame in pixel, with range [1, infinity)
729  * @param height The height of the mask frame in pixel, with range [1, infinity)
730  * @param position Center position of the elliptic mask, with range [0, width - 1]x[0, height - 1]
731  * @param horizontalHalf Half horizontal size of the elliptic mask, with range [1, infinity)
732  * @param verticalHalf Half vertical size of the elliptic mask, with range [1, infinity)
733  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
734  * @param paddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
735  * @tparam T Internal data type to determine the elliptic region
736  * @tparam tChannels Number of channels of the given frame
737  */
738  template <typename T, unsigned int tChannels>
739  static void ellipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontalHalf, const unsigned int verticalHalf, const uint8_t* value, const unsigned int paddingElements = 0u);
740 
741  /**
742  * Paints a rotated elliptic region at a specified position with specified size.
743  * @param frame The frame receiving the elliptic blob-region, must be valid
744  * @param width The width of the mask frame in pixel, with range [1, infinity)
745  * @param height The height of the mask frame in pixel, with range [1, infinity)
746  * @param position Center position of the elliptic mask, with range [0, width)x[0, height)
747  * @param horizontalHalf Half horizontal size of the elliptic mask, with range [1, infinity)
748  * @param verticalHalf Half vertical size of the elliptic mask, with range [1, infinity)
749  * @param angle Rotation angle, in radian, with range [0, 2 * PI)
750  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
751  * @param paddingElements Optional number of padding elements at the end of each row, with range [0, infinity)
752  * @tparam tChannels Number of channels of the given frame
753  */
754  template <unsigned int tChannels>
755  static void rotatedEllipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontalHalf, const unsigned int verticalHalf, const Scalar angle, const uint8_t* value, const unsigned int paddingElements = 0u);
756 
757  /**
758  * Paints a point with sub-pixel accuracy.
759  * @param frame The frame in which the point will be painted
760  * @param width The width of the frame in pixel, with range [1, infinity)
761  * @param height The height of the frame in pixel, with range [1, infinity)
762  * @param position Sub-pixel position of the point, with range (-infinity, infinity)x(-infinity, infinity)
763  * @param value Color value to be used, make sure that the provided buffer has at least as many bytes as the pixel format for one pixel, nullptr to apply 0x00 for each channel
764  * @param factors Filter factors for the specified point size
765  * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, with range [0, infinity)
766  * @tparam tChannels Number of frame channels, with range [1, infinity)
767  * @tparam tSize The size (width) of the point in pixel, with range [1, infinity) and must be odd
768  * @tparam tPixelCenter The pixel center of the provided position, either 'PC_TOP_LEFT' or 'PC_CENTER'
769  */
770  template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
771  static void point8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& position, const uint8_t* value, const FilterFactors<tSize>& factors, const unsigned int framePaddingElements = 0u);
772 };
773 
774 template <unsigned int tFilterSize>
776 {
777  static_assert(tFilterSize % 2u == 1u, "Invalid aliasing direction filter size.");
778 
779  if constexpr (tFilterSize <= 5u)
780  {
781  for (unsigned int k = 0u; k < tFilterSize; ++k)
782  {
783  factors_[k] = NumericT<unsigned int>::binomialCoefficient(tFilterSize - 1u, k);
784  }
785 
786  maximalFactor_ = NumericT<unsigned int>::binomialCoefficient(tFilterSize - 1, tFilterSize / 2u);
787  }
788  else
789  {
790  for (unsigned int k = 0u; k < tFilterSize; ++k)
791  {
792  if (k < 5u / 2u)
793  {
794  factors_[k] = NumericT<unsigned int>::binomialCoefficient(5u - 1u, k);
795  }
796  else if (k >= tFilterSize - 5u / 2u)
797  {
798  factors_[k] = NumericT<unsigned int>::binomialCoefficient(5u - 1u, 5u - (tFilterSize - k));
799  }
800  else
801  {
802  factors_[k] = NumericT<unsigned int>::binomialCoefficient(5u - 1u, 5u / 2u);
803  }
804  }
805 
806  maximalFactor_ = NumericT<unsigned int>::binomialCoefficient(5u - 1u, 5u / 2u);
807  }
808 }
809 
810 template <unsigned int tFilterSize>
811 inline unsigned int Canvas::FilterFactors<tFilterSize>::factor(const unsigned int index) const
812 {
813  ocean_assert(index < tFilterSize);
814 
815  return factors_[index];
816 }
817 
818 template <unsigned int tFilterSize>
819 inline unsigned int Canvas::FilterFactors<tFilterSize>::clampedFactor(const int index) const
820 {
821  if (index < 0 || index >= int(tFilterSize))
822  {
823  return 0u;
824  }
825 
826  return factors_[index];
827 }
828 
829 template <unsigned int tFilterSize>
831 {
832  return maximalFactor_;
833 }
834 
835 template <unsigned int tChannels>
836 void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const int xStart, const int yStart, const int xEnd, const int yEnd, const uint8_t* value, const unsigned int framePaddingElements)
837 {
838  static_assert(tChannels >= 1u, "Invalid channel number!");
839 
840  ocean_assert(frame != nullptr);
841  ocean_assert(width != 0u && height != 0u);
842 
843  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
844 
845  const uint8_t zeroValue[tChannels] = {0u};
846  const uint8_t* const color = value ? value : zeroValue;
847 
848  int x = int(xStart);
849  int y = int(yStart);
850 
851  Bresenham bresenham(x, y, int(xEnd), int(yEnd));
852 
853  if (bresenham.isValid())
854  {
855  do
856  {
857  if ((unsigned int)x < width && (unsigned int)y < height)
858  {
859  uint8_t* const pixel = frame + y * frameStrideElements + x * tChannels;
860 
861  for (unsigned int n = 0u; n < tChannels; ++n)
862  {
863  pixel[n] = color[n];
864  }
865  }
866 
867  bresenham.findNext(x, y);
868  }
869  while (x != int(xEnd) || y != int(yEnd));
870  }
871 
872  // end point
873  ocean_assert(x == int(xEnd) || y == int(yEnd));
874 
875  if ((unsigned int)x < width && (unsigned int)y < height)
876  {
877  uint8_t* const pixel = frame + y * frameStrideElements + x * tChannels;
878 
879  for (unsigned int n = 0u; n < tChannels; ++n)
880  {
881  pixel[n] = color[n];
882  }
883  }
884 }
885 
886 template <unsigned int tChannels>
887 void Canvas::lines8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition* positions, const unsigned int numberPositions, const uint8_t* value, const unsigned int framePaddingElements)
888 {
889  static_assert(tChannels >= 1u, "Invalid channel number!");
890 
891  ocean_assert(frame != nullptr);
892  ocean_assert(width != 0u && height != 0u);
893 
894  if (numberPositions == 0u)
895  {
896  return;
897  }
898 
899  ocean_assert(positions != nullptr);
900 
901  for (unsigned int n = 0u; n < numberPositions - 1u; n += 2u)
902  {
903  ocean_assert(n + 1u < numberPositions);
904  line8BitPerChannel<tChannels>(frame, width, height, positions[n].x(), positions[n].y(), positions[n + 1].x(), positions[n + 1].y(), value, framePaddingElements);
905  }
906 }
907 
908 template <unsigned int tSize>
909 bool Canvas::line(Frame& frame, const Scalar xStart, const Scalar yStart, const Scalar xEnd, const Scalar yEnd, const uint8_t* value)
910 {
911  return line<tSize>(frame, Vector2(xStart, yStart), Vector2(xEnd, yEnd), value);
912 }
913 
914 template <unsigned int tChannels, unsigned int tSize>
915 void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Scalar xStart, const Scalar yStart, const Scalar xEnd, const Scalar yEnd, const uint8_t* value, const unsigned int framePaddingElements)
916 {
917  line8BitPerChannel<tChannels, tSize>(frame, width, height, Vector2(xStart, yStart), Vector2(xEnd, yEnd), value, framePaddingElements);
918 }
919 
920 template <unsigned int tSize>
921 bool Canvas::line(Frame& frame, const Vector2& start, const Vector2& end, const uint8_t* value)
922 {
923  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
924 
925  ocean_assert(frame);
926 
927  if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
928  {
929  switch (frame.channels())
930  {
931  case 1u:
932  line8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
933  return true;
934 
935  case 2u:
936  line8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
937  return true;
938 
939  case 3u:
940  line8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
941  return true;
942 
943  case 4u:
944  line8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
945  return true;
946  }
947  }
948 
949  ocean_assert(false && "Invalid frame type!");
950  return false;
951 }
952 
953 template <unsigned int tChannels, unsigned int tSize>
954 void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& start, const Vector2& end, const uint8_t* value, const unsigned int framePaddingElements)
955 {
956  static_assert(tChannels >= 1u, "Invalid channel number!");
957  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
958 
959  ocean_assert(frame != nullptr);
960 
961  const Vector2 direction(end - start);
962  const Scalar length = direction.length();
963 
964  const uint8_t zeroValue[tChannels] = {0x00};
965  const uint8_t* const color = value ? value : zeroValue;
966 
967  if (length < 1)
968  {
969  point8BitPerChannel<tChannels, tSize, PC_CENTER>(frame, width, height, start, color, FilterFactors<tSize>(), framePaddingElements);
970  }
971  else
972  {
973  const Vector2 step = direction / length;
974 
975  for (unsigned int n = 0u; n <= (unsigned int)(length); ++n)
976  {
977  const Vector2 position(start + step * Scalar(n));
978 
979  if (position.x() >= -Scalar(tSize / 2u) - 1 && position.y() >= -Scalar(tSize / 2u) - 1 && position.x() <= Scalar(width + tSize / 2u) && position.y() <= Scalar(height + tSize / 2u))
980  {
981  point8BitPerChannel<tChannels, tSize, PC_CENTER>(frame, width, height, position, color, FilterFactors<tSize>(), framePaddingElements);
982  }
983  }
984  }
985 }
986 
987 template <unsigned int tSize>
988 bool Canvas::line(Frame& frame, const FiniteLine2& line, const uint8_t* value)
989 {
990  return Canvas::line<tSize>(frame, line.point0(), line.point1(), value);
991 }
992 
993 template <unsigned int tSize>
994 inline bool Canvas::lines(Frame& frame, const FiniteLines2& lines, const uint8_t* value)
995 {
996  for (const FiniteLine2& line : lines)
997  {
998  if (!Canvas::line<tSize>(frame, line, value))
999  {
1000  return false;
1001  }
1002  }
1003 
1004  return true;
1005 }
1006 
1007 template <unsigned int tChannels, unsigned int tSize>
1008 void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const FiniteLine2& line, const uint8_t* value, const unsigned int framePaddingElements)
1009 {
1010  static_assert(tChannels >= 1u, "Invalid channel number!");
1011  static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1012 
1013  ocean_assert(frame != nullptr);
1014  ocean_assert(width >= 1u && height >= 1u);
1015  ocean_assert(line.isValid());
1016 
1017  Canvas::line8BitPerChannel<tChannels, tSize>(frame, width, height, line.point0(), line.point1(), value, framePaddingElements);
1018 }
1019 
1020 template <unsigned int tSize>
1021 bool Canvas::line(Frame& frame, const Line2& line, const uint8_t* value)
1022 {
1023  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1024 
1025  ocean_assert(frame.isValid());
1026 
1027  if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1028  {
1029  switch (frame.channels())
1030  {
1031  case 1u:
1032  line8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1033  return true;
1034 
1035  case 2u:
1036  line8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1037  return true;
1038 
1039  case 3u:
1040  line8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1041  return true;
1042 
1043  case 4u:
1044  line8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1045  return true;
1046  }
1047  }
1048 
1049  ocean_assert(false && "Invalid frame type!");
1050  return false;
1051 }
1052 
1053 template <unsigned int tSize>
1054 inline bool Canvas::lines(Frame& frame, const Lines2& lines, const uint8_t* value)
1055 {
1056  for (const Line2& line : lines)
1057  {
1058  if (!Canvas::line<tSize>(frame, line, value))
1059  {
1060  return false;
1061  }
1062  }
1063 
1064  return true;
1065 }
1066 
1067 template <unsigned int tChannels, unsigned int tSize>
1068 void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Line2& line, const uint8_t* value, const unsigned int framePaddingElements)
1069 {
1070  static_assert(tChannels >= 1u, "Invalid channel number!");
1071  static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1072 
1073  ocean_assert(frame != nullptr);
1074  ocean_assert(width >= 1u && height >= 1u);
1075  ocean_assert(line.isValid());
1076 
1077  Scalar x0, y0, x1, y1;
1078  if (CV::Bresenham::borderIntersection(line, -Scalar(tSize) * Scalar(0.5), -Scalar(tSize) * Scalar(0.5), Scalar(width + tSize / 2u), Scalar(height + tSize / 2u), x0, y0, x1, y1))
1079  {
1080  line8BitPerChannel<tChannels, tSize>(frame, width, height, x0, y0, x1, y1, value, framePaddingElements);
1081  }
1082 }
1083 
1084 template <unsigned int tSize>
1085 bool Canvas::box(Frame& frame, const Box2& box, const uint8_t* value)
1086 {
1087  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1088 
1089  ocean_assert(frame.isValid());
1090 
1091  if (frame.numberPlanes() == 1u && frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8)
1092  {
1093  switch (frame.channels())
1094  {
1095  case 1u:
1096  box8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1097  return true;
1098 
1099  case 2u:
1100  box8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1101  return true;
1102 
1103  case 3u:
1104  box8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1105  return true;
1106 
1107  case 4u:
1108  box8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1109  return true;
1110  }
1111  }
1112 
1113  ocean_assert(false && "Invalid frame type!");
1114  return false;
1115 }
1116 
1117 template <unsigned int tChannels, unsigned int tSize>
1118 void Canvas::box8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Box2& box, const uint8_t* value, const unsigned int paddingElements)
1119 {
1120  ocean_assert(frame != nullptr);
1121  ocean_assert(width >= 1u && height >= 1u);
1122  ocean_assert(box.isValid());
1123 
1124  line8BitPerChannel<tChannels, tSize>(frame, width, height, box.left(), box.top(), box.left(), box.bottom(), value, paddingElements);
1125  line8BitPerChannel<tChannels, tSize>(frame, width, height, box.left(), box.bottom(), box.right(), box.bottom(), value, paddingElements);
1126  line8BitPerChannel<tChannels, tSize>(frame, width, height, box.right(), box.bottom(), box.right(), box.top(), value, paddingElements);
1127  line8BitPerChannel<tChannels, tSize>(frame, width, height, box.right(), box.top(), box.left(), box.top(), value, paddingElements);
1128 }
1129 
1130 template <unsigned int tChannels>
1131 void Canvas::ellipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontal, const unsigned int vertical, const uint8_t* value, const unsigned int paddingElements)
1132 {
1133  ocean_assert(frame);
1134  ocean_assert(position.x() < width);
1135  ocean_assert(position.y() < height);
1136 
1137  ocean_assert(horizontal >= 3u);
1138  ocean_assert(vertical >= 3u);
1139  ocean_assert(horizontal % 2u == 1u);
1140  ocean_assert(vertical % 2u == 1u);
1141 
1142  // implicit form:
1143  // (x / a)^2 + (y / b)^2 == 1
1144  //
1145  // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1146 
1147  const unsigned int horizontalHalf = horizontal >> 1u;
1148  const unsigned int verticalHalf = vertical >> 1u;
1149 
1150  if (horizontalHalf < 199u && verticalHalf < 199u)
1151  {
1152  ellipse8BitPerChannel<unsigned int, tChannels>(frame, width, height, position, horizontalHalf, verticalHalf, value, paddingElements);
1153  }
1154  else
1155  {
1156  ellipse8BitPerChannel<unsigned long long, tChannels>(frame, width, height, position, horizontalHalf, verticalHalf, value, paddingElements);
1157  }
1158 }
1159 
1160 template <unsigned int tChannels>
1161 void Canvas::rectangle8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const int left, const int top, const unsigned int xSize, const unsigned int ySize, const uint8_t* value, const unsigned int framePaddingElements)
1162 {
1163  static_assert(tChannels != 0u, "Invalid channel number!");
1164 
1165  ocean_assert(frame != 0u);
1166  ocean_assert(width >= 1u && height >= 1u);
1167 
1168  const int clampedLeft = max(0, left);
1169  const int clampedTop = max(0, top);
1170 
1171  const int clampedRightEnd = min(left + int(xSize), int(width)); // exclusive
1172  const int clampedBottomEnd = min(top + int(ySize), int(height));
1173 
1174  if (clampedRightEnd <= clampedLeft || clampedBottomEnd <= clampedTop)
1175  {
1176  // we are entirely outside the frame
1177  return;
1178  }
1179 
1180  typedef typename DataType<uint8_t, tChannels>::Type PixelType;
1181 
1182  const uint8_t black[tChannels] = {0u};
1183  const PixelType pixelValue = value ? *(const PixelType*)value : *(const PixelType*)black;
1184 
1185  const unsigned int clampedWidth = (unsigned int)(clampedRightEnd - clampedLeft);
1186  const unsigned int clampedHeight = (unsigned int)(clampedBottomEnd - clampedTop);
1187 
1188  ocean_assert(clampedWidth <= xSize);
1189  ocean_assert(clampedHeight <= ySize);
1190 
1191  ocean_assert(clampedLeft + clampedWidth <= width);
1192  ocean_assert(clampedTop + clampedHeight <= height);
1193 
1194  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1195 
1196  for (unsigned int y = clampedTop; y < clampedTop + clampedHeight; ++y)
1197  {
1198  PixelType* const rowLeft = (PixelType*)(frame + y * frameStrideElements) + clampedLeft;
1199 
1200  for (unsigned int x = 0u; x < clampedWidth; ++x)
1201  {
1202  rowLeft[x] = pixelValue;
1203  }
1204  }
1205 }
1206 
1207 template <unsigned int tSize, PixelCenter tPixelCenter>
1208 bool Canvas::point(Frame& frame, const Vector2& position, const uint8_t* value)
1209 {
1210  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1211  static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1212 
1213  ocean_assert(frame);
1214 
1215  if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1216  {
1217  switch (frame.channels())
1218  {
1219  case 1u:
1220  point8BitPerChannel<1u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1221  return true;
1222 
1223  case 2u:
1224  point8BitPerChannel<2u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1225  return true;
1226 
1227  case 3u:
1228  point8BitPerChannel<3u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1229  return true;
1230 
1231  case 4u:
1232  point8BitPerChannel<4u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1233  return true;
1234  }
1235  }
1236 
1237  ocean_assert(false && "Invalid frame type!");
1238  return false;
1239 }
1240 
1241 
1242 template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1243 void Canvas::point8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& position, const uint8_t* value, const unsigned int framePaddingElements)
1244 {
1245  static_assert(tChannels >= 1u, "Invalid channel number!");
1246  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1247  static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1248 
1249  ocean_assert(frame != nullptr);
1250 
1251  const uint8_t explicitValue[tChannels] = {0x00};
1252 
1253  point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, value ? value : explicitValue, FilterFactors<tSize>(), framePaddingElements);
1254 }
1255 
1256 template <unsigned int tSize, PixelCenter tPixelCenter>
1257 bool Canvas::points(Frame& frame, const Vectors2& positions, const uint8_t* value)
1258 {
1259  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1260  static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1261 
1262  ocean_assert(frame);
1263 
1264  if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1265  {
1266  switch (frame.channels())
1267  {
1268  case 1u:
1269  points8BitPerChannel<1u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1270  return true;
1271 
1272  case 2u:
1273  points8BitPerChannel<2u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1274  return true;
1275 
1276  case 3u:
1277  points8BitPerChannel<3u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1278  return true;
1279 
1280  case 4u:
1281  points8BitPerChannel<4u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1282  return true;
1283  }
1284  }
1285 
1286  ocean_assert(false && "Invalid frame type!");
1287  return false;
1288 }
1289 
1290 
1291 template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1292 void Canvas::points8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vectors2& positions, const uint8_t* value, const unsigned int framePaddingElements)
1293 {
1294  static_assert(tChannels >= 1u, "Invalid channel number!");
1295  static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1296  static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1297 
1298  ocean_assert(frame != nullptr);
1299 
1300  if (value)
1301  {
1302  for (const Vector2& position : positions)
1303  {
1304  point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, value, FilterFactors<tSize>(), framePaddingElements);
1305  }
1306  }
1307  else
1308  {
1309  const uint8_t explicitValue[tChannels] = {0x00};
1310 
1311  for (const Vector2& position : positions)
1312  {
1313  point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, explicitValue, FilterFactors<tSize>(), framePaddingElements);
1314  }
1315  }
1316 }
1317 
1318 template <typename T, unsigned int tChannels>
1319 void Canvas::ellipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontalHalf, const unsigned int verticalHalf, const uint8_t* value, const unsigned int paddingElements)
1320 {
1321  static_assert(tChannels != 0u, "Invalid number of channels!");
1322 
1323  ocean_assert(frame);
1324  ocean_assert(verticalHalf > 0u);
1325  ocean_assert(horizontalHalf > 0u);
1326  ocean_assert(position.x() < width);
1327  ocean_assert(position.y() < height);
1328 
1329  const unsigned int frameStrideElements = width * tChannels + paddingElements;
1330 
1331  typedef typename DataType<uint8_t, tChannels>::Type PixelType;
1332  const uint8_t valueZero[tChannels] = {uint8_t(0)};
1333 
1334  const PixelType* const pixelValue = value == nullptr ? (PixelType*)valueZero : (PixelType*)value;
1335 
1336  // implicit form:
1337  // (x / a)^2 + (y / b)^2 == 1
1338  //
1339  // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1340 
1341  // We do not use the following calculation as the a single pixel would be visible at the north, west, south and east position of the ellipse:
1342  // const T a2 = sqr(horizontalHalf);
1343  // const T b2 = sqr(verticalHalf);
1344  // Instead we take the center between the real radius and the radius which is one pixel larger to overcome the single pixel issue
1345 
1346  const T a2 = (sqr(horizontalHalf) + sqr(horizontalHalf + 1u)) / 2u;
1347  const T b2 = (sqr(verticalHalf) + sqr(verticalHalf + 1u)) / 2u;
1348  const T ab2 = a2 * b2;
1349 
1350  for (unsigned int y = position.y(); y <= position.y() + verticalHalf; ++y)
1351  {
1352  unsigned int left = position.x();
1353  unsigned int right = position.x() + horizontalHalf + 1u;
1354 
1355  const T ySqra2 = T(sqr(y - position.y())) * a2;
1356 
1357  while (left + 1u < right)
1358  {
1359  ocean_assert(T(sqr(left - position.x())) * b2 + T(sqr(y - position.y())) * a2 <= ab2);
1360 
1361  const unsigned int mid = (left + right) / 2u;
1362 
1363  if (T(sqr(mid - position.x())) * b2 + ySqra2 <= ab2)
1364  {
1365  left = mid;
1366  }
1367  else
1368  {
1369  right = mid;
1370  }
1371  }
1372 
1373  ocean_assert(left + 1u == right);
1374  ocean_assert(T(sqr(left - position.x())) * b2 + T(sqr(y - position.y())) * a2 <= ab2);
1375  ocean_assert(T(sqr(right - position.x())) * b2 + T(sqr(y - position.y())) * a2 > ab2);
1376 
1377  const unsigned int frameLeft = max(0, int(2u * position.x() - left));
1378  const unsigned int frameRight = min(right, width);
1379 
1380  ocean_assert(frameLeft < width);
1381  ocean_assert(frameRight <= width);
1382  ocean_assert(frameLeft < frameRight);
1383 
1384  // top
1385  if (2u * position.y() >= y)
1386  {
1387  const unsigned int frameTop = 2u * position.y() - y;
1388  ocean_assert(frameTop < height);
1389 
1390  PixelType* pointer = (PixelType*)(frame + frameTop * frameStrideElements) + frameLeft;
1391  PixelType* const pointerEnd = pointer + (frameRight - frameLeft);
1392 
1393  while (pointer != pointerEnd)
1394  {
1395  *pointer++ = *pixelValue;
1396  }
1397  }
1398 
1399  // bottom
1400  if (y < height)
1401  {
1402  PixelType* pointer = (PixelType*)(frame + y * frameStrideElements) + frameLeft;
1403  PixelType* const pointerEnd = pointer + (frameRight - frameLeft);
1404 
1405  while (pointer != pointerEnd)
1406  {
1407  *pointer++ = *pixelValue;
1408  }
1409  }
1410  }
1411 }
1412 
1413 template <unsigned int tChannels>
1414 void Canvas::rotatedEllipse8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const unsigned int horizontalHalf, const unsigned int verticalHalf, const Scalar angle, const uint8_t* value, const unsigned int paddingElements)
1415 {
1416  static_assert(tChannels != 0u, "Invalid number of channels!");
1417 
1418  ocean_assert(frame);
1419  ocean_assert(position.x() < width);
1420  ocean_assert(position.y() < height);
1421 
1422  const unsigned int frameStrideElements = width * tChannels + paddingElements;
1423 
1424  typedef typename DataType<uint8_t, tChannels>::Type PixelType;
1425  const uint8_t valueZero[tChannels] = {0u};
1426 
1427  const PixelType* const pixelValue = value == nullptr ? (PixelType*)valueZero : (PixelType*)value;
1428 
1429  // implicit form:
1430  // (x / a)^2 + (y / b)^2 == 1
1431  //
1432  // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1433 
1434  const Scalar factorA = 1 / Scalar(sqr(horizontalHalf));
1435  const Scalar factorB = 1 / Scalar(sqr(verticalHalf));
1436 
1437  const SquareMatrix3 invertedRotation(Rotation(0, 0, 1, angle));
1438 
1439  const uint8_t radius = uint8_t(max(horizontalHalf, verticalHalf));
1440 
1441  for (unsigned int y = max(0, int(position.y() - radius)); y <= min(position.y() + radius, height); ++y)
1442  {
1443  for (unsigned int x = max(0, int(position.x() - radius)); x <= min(position.x() + radius, width); ++x)
1444  {
1445  const Vector3 position3(Scalar(position.x()) - Scalar(x), Scalar(position.y()) - Scalar(y), 0);
1446  Vector3 invertedPosition(invertedRotation * position3);
1447 
1448  if (Numeric::sqr(invertedPosition.x()) * factorA + Numeric::sqr(invertedPosition.y()) * factorB <= 1)
1449  {
1450  *((PixelType*)(frame + y * frameStrideElements) + x) = *pixelValue;
1451  }
1452  }
1453  }
1454 }
1455 
1456 template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1457 void Canvas::point8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& position, const uint8_t* value, const FilterFactors<tSize>& factors, const unsigned int framePaddingElements)
1458 {
1459  static_assert(tChannels >= 1u, "Invalid channel number!");
1460  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1461  static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1462 
1463  ocean_assert(frame != nullptr);
1464 
1465  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1466 
1467  // the remaining function expects PC_CENTER as pixel center so shifting the position in case the coordinate is provided as PC_TOP_LEFT
1468  const Vector2 shiftedPosition = tPixelCenter == PC_TOP_LEFT ? position + Vector2(Scalar(0.5), Scalar(0.5)) : position;
1469 
1470  const int left = int(Numeric::floor(shiftedPosition.x() - Scalar(0.5)));
1471  const int top = int(Numeric::floor(shiftedPosition.y() - Scalar(0.5)));
1472 
1473  const unsigned int xFactor = (unsigned int)((Scalar(left) + Scalar(1.5) - shiftedPosition.x()) * Scalar(128) + Scalar(0.5));
1474  const unsigned int yFactor = (unsigned int)((Scalar(top) + Scalar(1.5) - shiftedPosition.y()) * Scalar(128) + Scalar(0.5));
1475 
1476  ocean_assert(xFactor <= 128u && yFactor <= 128u);
1477 
1478  const unsigned int sqrMaximalFilter = factors.maximalFactor() * factors.maximalFactor();
1479 
1480  for (unsigned int y = 0u; y <= tSize; ++y)
1481  {
1482  const unsigned int yInFrame = top + int(y) - int(tSize / 2u);
1483 
1484  if (yInFrame < height)
1485  {
1486  for (unsigned int x = 0u; x <= tSize; ++x)
1487  {
1488  const unsigned int xInFrame = left + int(x) - int(tSize / 2u);
1489 
1490  if (xInFrame < width)
1491  {
1492  const unsigned int factor = (128u - yFactor) * factors.clampedFactor(int(y - 1u)) * (128u - xFactor) * factors.clampedFactor(int(x - 1u))
1493  + (128u - yFactor) * factors.clampedFactor(int(y - 1u)) * xFactor * factors.clampedFactor(x)
1494  + yFactor * factors.clampedFactor(y) * (128u - xFactor) * factors.clampedFactor(int(x - 1u))
1495  + yFactor * factors.clampedFactor(y) * xFactor * factors.clampedFactor(x);
1496 
1497  const unsigned int _factor = 16384 * sqrMaximalFilter - factor;
1498 
1499  uint8_t* const pixel = frame + yInFrame * frameStrideElements + xInFrame * tChannels;
1500 
1501  for (unsigned int n = 0u; n < tChannels; ++n)
1502  {
1503  pixel[n] = uint8_t((pixel[n] * _factor + value[n] * factor + (16384u * sqrMaximalFilter) / 2u) / (16384u * sqrMaximalFilter));
1504  }
1505  }
1506  }
1507  }
1508  }
1509 }
1510 
1511 template <unsigned int tChannels>
1512 void Canvas::fill8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const uint8_t* value, const unsigned int framePaddingElements)
1513 {
1514  static_assert(tChannels != 0u, "Invalid channel number!");
1515 
1516  ocean_assert(frame);
1517  ocean_assert(width >= 1u && height >= 1u);
1518 
1519  ocean_assert(position.x() < width && position.y() < height);
1520 
1521  typedef typename DataType<uint8_t, tChannels>::Type PixelType;
1522 
1523  const uint8_t zeroValue[tChannels] = {0u};
1524  const PixelType pixelValue = value ? *((PixelType*)value) : *((PixelType*)zeroValue);
1525 
1526  const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1527 
1528  const unsigned int offset = position.y() * frameStrideElements + position.x() * tChannels;
1529 
1530  // check whether the start position has the same color like the given replacement color
1531  if (*(const PixelType*)(frame + offset) == pixelValue)
1532  {
1533  return;
1534  }
1535 
1536  const PixelType areaPixelValue = *(const PixelType*)(frame + offset);
1537  *(PixelType*)(frame + offset) = pixelValue;
1538 
1539  // we use a vector and not a std::stack as the stack implementation is significant slower
1540  std::vector<PixelPosition> stack;
1541  stack.reserve((width * height) / 16u);
1542 
1543  // left
1544  if (position.x() != 0u && *((const PixelType*)(frame + offset) - 1) == areaPixelValue)
1545  {
1546  stack.push_back(position.west());
1547  }
1548 
1549  // right
1550  if (position.x() != width - 1u && *((const PixelType*)(frame + offset) + 1) == areaPixelValue)
1551  {
1552  stack.push_back(position.east());
1553  }
1554 
1555  // top
1556  if (position.y() != 0u && *((const PixelType*)(frame + offset - frameStrideElements)) == areaPixelValue)
1557  {
1558  stack.push_back(position.north());
1559  }
1560 
1561  // bottom
1562  if (position.y() != height - 1u && *((const PixelType*)(frame + offset + frameStrideElements)) == areaPixelValue)
1563  {
1564  stack.push_back(position.south());
1565  }
1566 
1567  while (!stack.empty())
1568  {
1569  const PixelPosition pixel(stack.back());
1570  stack.pop_back();
1571 
1572  const unsigned int testOffset = pixel.y() * frameStrideElements + pixel.x() * tChannels;
1573 
1574  ocean_assert(*(const PixelType*)(frame + testOffset) == areaPixelValue);
1575 
1576  *(PixelType*)(frame + testOffset) = pixelValue;
1577 
1578  // left
1579  if (pixel.x() != 0u && *((const PixelType*)(frame + testOffset) - 1) == areaPixelValue)
1580  {
1581  stack.push_back(pixel.west());
1582  }
1583 
1584  // right
1585  if (pixel.x() != width - 1u && *((const PixelType*)(frame + testOffset) + 1) == areaPixelValue)
1586  {
1587  stack.push_back(pixel.east());
1588  }
1589 
1590  // top
1591  if (pixel.y() != 0u && *((const PixelType*)(frame + testOffset - frameStrideElements)) == areaPixelValue)
1592  {
1593  stack.push_back(pixel.north());
1594  }
1595 
1596  // bottom
1597  if (pixel.y() != height - 1u && *((const PixelType*)(frame + testOffset + frameStrideElements)) == areaPixelValue)
1598  {
1599  stack.push_back(pixel.south());
1600  }
1601  }
1602 }
1603 
1604 template <unsigned int tSize>
1605 bool Canvas::polygon(Frame& frame, const Vector2* points, size_t numberPoints, const uint8_t* value, const bool closeLoop)
1606 {
1607  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1608 
1609  ocean_assert(frame.isValid());
1610 
1611  if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1612  {
1613  switch (frame.channels())
1614  {
1615  case 1u:
1616  polygon8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1617  return true;
1618 
1619  case 2u:
1620  polygon8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1621  return true;
1622 
1623  case 3u:
1624  polygon8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1625  return true;
1626 
1627  case 4u:
1628  polygon8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1629  return true;
1630  }
1631  }
1632 
1633  ocean_assert(false && "Invalid pixel format!");
1634  return false;
1635 }
1636 
1637 template <unsigned int tChannels, unsigned int tSize>
1638 void Canvas::polygon8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2* points, size_t numberPoints, const uint8_t* value, const bool closeLoop, const unsigned int framePaddingElements)
1639 {
1640  static_assert(tChannels >= 1u, "Invalid channel number!");
1641  static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1642 
1643  ocean_assert(frame != nullptr);
1644  ocean_assert(width >= 1u && height >= 1u);
1645 
1646  if (numberPoints >= 2)
1647  {
1648  for (size_t n = 1; n < numberPoints; ++n)
1649  {
1650  line8BitPerChannel<tChannels, tSize>(frame, width, height, points[n - 1], points[n], value, framePaddingElements);
1651  }
1652 
1653  if (numberPoints >= 3 && closeLoop)
1654  {
1655  line8BitPerChannel<tChannels, tSize>(frame, width, height, points[numberPoints - 1], points[0], value, framePaddingElements);
1656  }
1657  }
1658 }
1659 
1660 }
1661 
1662 }
1663 
1664 #endif // META_OCEAN_CV_CANVAS_H
This class implements bresenham line algorithms.
Definition: Bresenham.h:27
void findNext(int &x, int &y)
Applies one Bresenham step to find the next pixel.
static bool borderIntersection(const Line2 &line, const int leftBorder, const int topBorder, const int rightBorder, const int bottomBorder, int &x0, int &y0, int &x1, int &y1)
Computes the pixel-precise border intersection (the begin and end position) of a sub-pixel-precise 2D...
bool isValid() const
Returns whether this object holds a valid line.
Definition: Bresenham.h:162
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition: Canvas.h:47
static bool point(Frame &frame, const Vector2 &position, const PixelCenter pixelCenter, const unsigned int size, const uint8_t *value=nullptr)
Paints a point with sub-pixel accuracy.
This class implements a helper class that provides binomial filter parameters for a specific filter s...
Definition: Canvas.h:70
unsigned int maximalFactor() const
Returns the maximal (center) filter parameter for the specified filter size.
Definition: Canvas.h:830
unsigned int clampedFactor(const int index) const
Returns the filter factor for a specific index.
Definition: Canvas.h:819
unsigned int factor(const unsigned int index) const
Returns the filter factor for a specific index.
Definition: Canvas.h:811
FilterFactors()
Creates a new filter factor object.
Definition: Canvas.h:775
This class implements one character of a font for which each pixel has as size of at most 16x16.
Definition: Canvas.h:121
bool paint(Frame &frame, const int left, const int top, const uint8_t *foregroundColor, const uint8_t *backgroundColor=nullptr) const
Paints the character at the specific location in a given frame.
Frame frame(const FrameType::PixelFormat pixelFormat, const uint8_t *foregroundColor, const uint8_t *backgroundColor) const
Creates a new frame and paints the character in the frame.
Character()
Creates an invalid character object.
bool isValid() const
Returns whether this character holds valid data.
Character(const Frame &frame, const uint8_t *color)
Creates a new character from a given image in which the actual character is visible.
unsigned int height() const
Returns the height of this character in pixel.
unsigned int width() const
Returns the width of this character in pixel.
This class implements a standard font similar to a code-block like font.
Definition: Canvas.h:112
Font()
The protected constructor creating a new font.
Characters characters_
The characters of this font.
Definition: Canvas.h:222
bool drawText(Frame &frame, const std::string &text, const int left, const int top, const uint8_t *foregroundColor, const uint8_t *backgroundColor=nullptr) const
Paints a given text into a given frame using this font.
bool textExtent(const std::string &text, unsigned int &width, unsigned int &height) const
Returns the bounding box a given text will occupy in pixel space when using this font.
std::vector< Character > Characters
Definition of a vector holding characters.
Definition: Canvas.h:184
This class implements canvas functions.
Definition: Canvas.h:38
static bool drawText(Frame &frame, const std::string &text, const int left, const int top, const uint8_t *foregroundColor, const uint8_t *backgroundColor=nullptr)
Paints a given text into a given frame using the standard (code style) font supporting only one size.
static void point8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const Vector2 &position, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints a point with sub-pixel accuracy.
Definition: Canvas.h:1243
static const uint8_t * memoryBlock32Byte()
Returns a memory block to 32 bytes as a backup in case a requested color value does not exist for a s...
static bool line(Frame &frame, const int xStart, const int yStart, const int xEnd, const int yEnd, const uint8_t *value=nullptr)
Paints a line with specified start and end position with pixel accuracy.
static bool ellipse(Frame &frame, const PixelPosition &position, const unsigned int horizontal, const unsigned int vertical, const uint8_t *value=nullptr)
Paints an ellipse at a specified position with specified size.
static bool polygon(Frame &frame, const Vector2 *points, size_t numberPoints, const uint8_t *value=nullptr, const bool closeLoop=true)
Paints the outline of a polygon with sub-pixel accuracy.
Definition: Canvas.h:1605
static void polygon8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const Vector2 *points, size_t numberPoints, const uint8_t *value=nullptr, const bool closeLoop=true, const unsigned int framePaddingElements=0u)
Paints the outline of a polygon with sub-pixel accuracy.
Definition: Canvas.h:1638
static const uint8_t * green(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a green color.
static const uint8_t * yellow(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a yellow color.
static const uint8_t * white(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a white color.
static void lines8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const PixelPosition *positions, const unsigned int numberPositions, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints several lines with specified start and end positions with pixel accuracy.
Definition: Canvas.h:887
static void fill8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const PixelPosition &position, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Fills an image area with a given color, an recursive seed-fill-algorithm is implemented.
Definition: Canvas.h:1512
static const uint8_t * gray(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a gray color.
static void rotatedEllipse8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const PixelPosition &position, const unsigned int horizontalHalf, const unsigned int verticalHalf, const Scalar angle, const uint8_t *value, const unsigned int paddingElements=0u)
Paints a rotated elliptic region at a specified position with specified size.
Definition: Canvas.h:1414
static void ellipse8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const PixelPosition &position, const unsigned int horizontal, const unsigned int vertical, const uint8_t *value=nullptr, const unsigned int paddingElements=0u)
Paints an ellipse at a specified position with specified size.
Definition: Canvas.h:1131
static const uint8_t * red(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a red color.
static bool fill(Frame &frame, const PixelPosition &position, const uint8_t *value=nullptr)
Fills an image area with a given color, an recursive seed-fill-algorithm is implemented.
static bool rotatedEllipse(Frame &frame, const PixelPosition &position, const unsigned int horizontal, const unsigned int vertical, const Scalar angle, const uint8_t *value=nullptr)
Paints a rotated elliptic region at a specified position with specified size and rotation angle.
static bool points(Frame &frame, const Vectors2 &positions, const uint8_t *value=nullptr)
Paints points with sub-pixel accuracy.
Definition: Canvas.h:1257
static bool lines(Frame &frame, const PixelPosition *positions, const unsigned int numberPositions, const uint8_t *value=nullptr)
Paints several lines with specified start and end positions with pixel accuracy.
static bool textExtent(const std::string &text, unsigned int &width, unsigned int &height)
Returns the bounding box a given text will occupy in pixel space when using the standard font.
static void rectangle8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const int left, const int top, const unsigned int xSize, const unsigned int ySize, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints a rectangle at a specified position with specified size.
Definition: Canvas.h:1161
static void line8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const int xStart, const int yStart, const int xEnd, const int yEnd, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints a line with specified start and end position with pixel accuracy.
Definition: Canvas.h:836
static bool rectangle(Frame &frame, const int left, const int top, const unsigned int xSize, const unsigned int ySize, const uint8_t *value=nullptr)
Paints a rectangle at a specified position with specified size.
static const uint8_t * black(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a black color.
static const uint8_t * blue(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a blue color.
static void box8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const Box2 &box, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints a 2D axis aligned bounding box with sub-pixel accuracy.
Definition: Canvas.h:1118
static bool point(Frame &frame, const Vector2 &position, const uint8_t *value=nullptr)
Paints a point with sub-pixel accuracy.
Definition: Canvas.h:1208
static void points8BitPerChannel(uint8_t *frame, const unsigned int width, const unsigned int height, const Vectors2 &positions, const uint8_t *value=nullptr, const unsigned int framePaddingElements=0u)
Paints points with sub-pixel accuracy.
Definition: Canvas.h:1292
static bool box(Frame &frame, const Box2 &box, const uint8_t *value=nullptr)
Paints a 2D axis aligned bounding box with sub-pixel accuracy.
Definition: Canvas.h:1085
PixelPositionT< T > west() const
Returns the pixel position west to this position.
Definition: PixelPosition.h:561
PixelPositionT< T > north() const
Returns the pixel position north to this position.
Definition: PixelPosition.h:549
PixelPositionT< T > east() const
Returns the pixel position east to this position.
Definition: PixelPosition.h:585
T y() const
Returns the vertical coordinate position of this object.
Definition: PixelPosition.h:470
T x() const
Returns the horizontal coordinate position of this object.
Definition: PixelPosition.h:458
PixelPositionT< T > south() const
Returns the pixel position south to this position.
Definition: PixelPosition.h:573
Template class allowing to define an array of data types.
Definition: DataType.h:27
This class implements Ocean's image class.
Definition: Frame.h:1792
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition: Frame.h:4159
bool isValid() const
Returns whether this frame is valid.
Definition: Frame.h:4448
unsigned int paddingElements(const unsigned int planeIndex=0u) const
Returns the optional number of padding elements at the end of each row for a specific plane.
Definition: Frame.h:4042
PixelFormat
Definition of all pixel formats available in the Ocean framework.
Definition: Frame.h:183
@ FORMAT_RGB24
Pixel format with byte order RGB and 24 bits per pixel.
Definition: Frame.h:315
unsigned int width() const
Returns the width of the frame format in pixel.
Definition: Frame.h:3143
uint32_t numberPlanes() const
Returns the number of planes of the pixel format of this frame.
Definition: Frame.h:3183
@ DT_UNSIGNED_INTEGER_8
Unsigned 8 bit integer data type (uint8_t).
Definition: Frame.h:41
unsigned int height() const
Returns the height of the frame in pixel.
Definition: Frame.h:3148
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition: Frame.h:3173
DataType dataType() const
Returns the data type of the pixel format of this frame.
Definition: Frame.h:3163
This class implements an infinite line in 2D space.
Definition: Line2.h:83
static T floor(const T value)
Returns the largest integer value that is not greater than the given value.
Definition: Numeric.h:2026
static constexpr T sqr(const T value)
Returns the square of a given value.
Definition: Numeric.h:1495
static constexpr T binomialCoefficient(const T &n, const T &k)
Returns the binomial coefficient for two binomial parameters.
Definition: Numeric.h:1957
This template class is the base class for all singleton objects.
Definition: Singleton.h:71
const T & x() const noexcept
Returns the x value.
Definition: Vector2.h:698
const T & y() const noexcept
Returns the y value.
Definition: Vector2.h:710
T length() const
Returns the length of the vector.
Definition: Vector2.h:615
const T & y() const noexcept
Returns the y value.
Definition: Vector3.h:812
const T & x() const noexcept
Returns the x value.
Definition: Vector3.h:800
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition: base/Utilities.h:1029
PixelCenter
Definition of individual centers of pixels.
Definition: CV.h:117
@ PC_TOP_LEFT
The center of a pixel is in the upper-left corner of each pixel's square.
Definition: CV.h:133
@ PC_CENTER
The center of a pixel is located in the center of each pixel's square (with an offset of 0....
Definition: CV.h:150
RotationT< Scalar > Rotation
Definition of the Rotation object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION flag either with ...
Definition: Rotation.h:31
float Scalar
Definition of a scalar type.
Definition: Math.h:128
std::vector< Line2 > Lines2
Definition of a vector holding Line2 objects.
Definition: Line2.h:57
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition: FiniteLine2.h:57
std::vector< Vector2 > Vectors2
Definition of a vector holding Vector2 objects.
Definition: Vector2.h:64
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition: Vector2.h:21
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15