Ocean
Loading...
Searching...
No Matches
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"
16
17#include "ocean/cv/Bresenham.h"
19
20#include "ocean/math/Box2.h"
22#include "ocean/math/Line2.h"
23#include "ocean/math/Rotation.h"
25#include "ocean/math/Vector3.h"
26
27namespace Ocean
28{
29
30namespace CV
31{
32
33/**
34 * This class implements canvas functions.
35 * @ingroup cv
36 */
37class 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, then 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 painting 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 painting 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 using Characters = std::vector<Character>;
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 painting 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 */
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 painting 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 an 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
774template <unsigned int tFilterSize>
776{
777 static_assert(tFilterSize % 2u == 1u, "Invalid aliasing direction filter size.");
778
779 // the filter factors are symmetric, let's calculate only the first half of the factors (including the center factor)
780
781 if constexpr (tFilterSize <= 5u)
782 {
783 for (unsigned int k = 0u; k <= tFilterSize / 2; ++k)
784 {
785 factors_[k] = NumericT<unsigned int>::binomialCoefficient(tFilterSize - 1u, k);
786 }
787 }
788 else
789 {
790 for (unsigned int k = 0u; k <= tFilterSize / 2u; ++k)
791 {
792 if (k < 5u / 2u)
793 {
794 factors_[k] = NumericT<unsigned int>::binomialCoefficient(5u - 1u, k);
795 }
796 else
797 {
798 factors_[k] = NumericT<unsigned int>::binomialCoefficient(5u - 1u, 5u / 2u);
799 }
800 }
801 }
802
803 // let's copy the first half of the factors to the second half of the factors
804
805 for (unsigned int k = tFilterSize / 2u + 1u; k < tFilterSize; ++k)
806 {
807 factors_[k] = factors_[tFilterSize - k - 1u];
808 }
809
810 maximalFactor_ = factors_[tFilterSize / 2u];
811}
812
813template <unsigned int tFilterSize>
814inline unsigned int Canvas::FilterFactors<tFilterSize>::factor(const unsigned int index) const
815{
816 ocean_assert(index < tFilterSize);
817
818 return factors_[index];
819}
820
821template <unsigned int tFilterSize>
822inline unsigned int Canvas::FilterFactors<tFilterSize>::clampedFactor(const int index) const
823{
824 if (index < 0 || index >= int(tFilterSize))
825 {
826 return 0u;
827 }
828
829 return factors_[index];
830}
831
832template <unsigned int tFilterSize>
834{
835 return maximalFactor_;
836}
837
838template <unsigned int tChannels>
839void 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)
840{
841 static_assert(tChannels >= 1u, "Invalid channel number!");
842
843 ocean_assert(frame != nullptr);
844 ocean_assert(width != 0u && height != 0u);
845
846 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
847
848 const uint8_t zeroValue[tChannels] = {0u};
849 const uint8_t* const color = value ? value : zeroValue;
850
851 int x = int(xStart);
852 int y = int(yStart);
853
854 Bresenham bresenham(x, y, int(xEnd), int(yEnd));
855
856 if (bresenham.isValid())
857 {
858 do
859 {
860 if ((unsigned int)x < width && (unsigned int)y < height)
861 {
862 uint8_t* const pixel = frame + y * frameStrideElements + x * tChannels;
863
864 for (unsigned int n = 0u; n < tChannels; ++n)
865 {
866 pixel[n] = color[n];
867 }
868 }
869
870 bresenham.findNext(x, y);
871 }
872 while (x != int(xEnd) || y != int(yEnd));
873 }
874
875 // end point
876 ocean_assert(x == int(xEnd) || y == int(yEnd));
877
878 if ((unsigned int)x < width && (unsigned int)y < height)
879 {
880 uint8_t* const pixel = frame + y * frameStrideElements + x * tChannels;
881
882 for (unsigned int n = 0u; n < tChannels; ++n)
883 {
884 pixel[n] = color[n];
885 }
886 }
887}
888
889template <unsigned int tChannels>
890void 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)
891{
892 static_assert(tChannels >= 1u, "Invalid channel number!");
893
894 ocean_assert(frame != nullptr);
895 ocean_assert(width != 0u && height != 0u);
896
897 if (numberPositions == 0u)
898 {
899 return;
900 }
901
902 ocean_assert(positions != nullptr);
903
904 for (unsigned int n = 0u; n < numberPositions - 1u; n += 2u)
905 {
906 ocean_assert(n + 1u < numberPositions);
907 line8BitPerChannel<tChannels>(frame, width, height, positions[n].x(), positions[n].y(), positions[n + 1].x(), positions[n + 1].y(), value, framePaddingElements);
908 }
909}
910
911template <unsigned int tSize>
912bool Canvas::line(Frame& frame, const Scalar xStart, const Scalar yStart, const Scalar xEnd, const Scalar yEnd, const uint8_t* value)
913{
914 return line<tSize>(frame, Vector2(xStart, yStart), Vector2(xEnd, yEnd), value);
915}
916
917template <unsigned int tChannels, unsigned int tSize>
918void 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)
919{
920 line8BitPerChannel<tChannels, tSize>(frame, width, height, Vector2(xStart, yStart), Vector2(xEnd, yEnd), value, framePaddingElements);
921}
922
923template <unsigned int tSize>
924bool Canvas::line(Frame& frame, const Vector2& start, const Vector2& end, const uint8_t* value)
925{
926 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
927
928 ocean_assert(frame);
929
930 if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
931 {
932 switch (frame.channels())
933 {
934 case 1u:
935 line8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
936 return true;
937
938 case 2u:
939 line8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
940 return true;
941
942 case 3u:
943 line8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
944 return true;
945
946 case 4u:
947 line8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), start, end, value, frame.paddingElements());
948 return true;
949
950 default:
951 break;
952 }
953 }
954
955 ocean_assert(false && "Invalid frame type!");
956 return false;
957}
958
959template <unsigned int tChannels, unsigned int tSize>
960void 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)
961{
962 static_assert(tChannels >= 1u, "Invalid channel number!");
963 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
964
965 ocean_assert(frame != nullptr);
966
967 const Vector2 direction(end - start);
968 const Scalar length = direction.length();
969
970 const uint8_t zeroValue[tChannels] = {0x00};
971 const uint8_t* const color = value ? value : zeroValue;
972
973 if (length < 1)
974 {
975 point8BitPerChannel<tChannels, tSize, PC_CENTER>(frame, width, height, start, color, FilterFactors<tSize>(), framePaddingElements);
976 }
977 else
978 {
979 const Vector2 step = direction / length;
980
981 for (unsigned int n = 0u; n <= (unsigned int)(length); ++n)
982 {
983 const Vector2 position(start + step * Scalar(n));
984
985 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))
986 {
987 point8BitPerChannel<tChannels, tSize, PC_CENTER>(frame, width, height, position, color, FilterFactors<tSize>(), framePaddingElements);
988 }
989 }
990 }
991}
992
993template <unsigned int tSize>
994bool Canvas::line(Frame& frame, const FiniteLine2& line, const uint8_t* value)
995{
996 return Canvas::line<tSize>(frame, line.point0(), line.point1(), value);
997}
998
999template <unsigned int tSize>
1000inline bool Canvas::lines(Frame& frame, const FiniteLines2& lines, const uint8_t* value)
1001{
1002 for (const FiniteLine2& line : lines)
1003 {
1004 if (!Canvas::line<tSize>(frame, line, value))
1005 {
1006 return false;
1007 }
1008 }
1009
1010 return true;
1011}
1012
1013template <unsigned int tChannels, unsigned int tSize>
1014void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const FiniteLine2& line, const uint8_t* value, const unsigned int framePaddingElements)
1015{
1016 static_assert(tChannels >= 1u, "Invalid channel number!");
1017 static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1018
1019 ocean_assert(frame != nullptr);
1020 ocean_assert(width >= 1u && height >= 1u);
1021 ocean_assert(line.isValid());
1022
1023 Canvas::line8BitPerChannel<tChannels, tSize>(frame, width, height, line.point0(), line.point1(), value, framePaddingElements);
1024}
1025
1026template <unsigned int tSize>
1027bool Canvas::line(Frame& frame, const Line2& line, const uint8_t* value)
1028{
1029 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1030
1031 ocean_assert(frame.isValid());
1032
1033 if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1034 {
1035 switch (frame.channels())
1036 {
1037 case 1u:
1038 line8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1039 return true;
1040
1041 case 2u:
1042 line8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1043 return true;
1044
1045 case 3u:
1046 line8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1047 return true;
1048
1049 case 4u:
1050 line8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), line, value, frame.paddingElements());
1051 return true;
1052
1053 default:
1054 break;
1055 }
1056 }
1057
1058 ocean_assert(false && "Invalid frame type!");
1059 return false;
1060}
1061
1062template <unsigned int tSize>
1063inline bool Canvas::lines(Frame& frame, const Lines2& lines, const uint8_t* value)
1064{
1065 for (const Line2& line : lines)
1066 {
1067 if (!Canvas::line<tSize>(frame, line, value))
1068 {
1069 return false;
1070 }
1071 }
1072
1073 return true;
1074}
1075
1076template <unsigned int tChannels, unsigned int tSize>
1077void Canvas::line8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Line2& line, const uint8_t* value, const unsigned int framePaddingElements)
1078{
1079 static_assert(tChannels >= 1u, "Invalid channel number!");
1080 static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1081
1082 ocean_assert(frame != nullptr);
1083 ocean_assert(width >= 1u && height >= 1u);
1084 ocean_assert(line.isValid());
1085
1086 Scalar x0, y0, x1, y1;
1087 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))
1088 {
1089 line8BitPerChannel<tChannels, tSize>(frame, width, height, x0, y0, x1, y1, value, framePaddingElements);
1090 }
1091}
1092
1093template <unsigned int tSize>
1094bool Canvas::box(Frame& frame, const Box2& box, const uint8_t* value)
1095{
1096 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1097
1098 ocean_assert(frame.isValid());
1099
1100 if (frame.numberPlanes() == 1u && frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8)
1101 {
1102 switch (frame.channels())
1103 {
1104 case 1u:
1105 box8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1106 return true;
1107
1108 case 2u:
1109 box8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1110 return true;
1111
1112 case 3u:
1113 box8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1114 return true;
1115
1116 case 4u:
1117 box8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), box, value, frame.paddingElements());
1118 return true;
1119
1120 default:
1121 break;
1122 }
1123 }
1124
1125 ocean_assert(false && "Invalid frame type!");
1126 return false;
1127}
1128
1129template <unsigned int tChannels, unsigned int tSize>
1130void Canvas::box8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Box2& box, const uint8_t* value, const unsigned int paddingElements)
1131{
1132 ocean_assert(frame != nullptr);
1133 ocean_assert(width >= 1u && height >= 1u);
1134 ocean_assert(box.isValid());
1135
1136 line8BitPerChannel<tChannels, tSize>(frame, width, height, box.left(), box.top(), box.left(), box.bottom(), value, paddingElements);
1137 line8BitPerChannel<tChannels, tSize>(frame, width, height, box.left(), box.bottom(), box.right(), box.bottom(), value, paddingElements);
1138 line8BitPerChannel<tChannels, tSize>(frame, width, height, box.right(), box.bottom(), box.right(), box.top(), value, paddingElements);
1139 line8BitPerChannel<tChannels, tSize>(frame, width, height, box.right(), box.top(), box.left(), box.top(), value, paddingElements);
1140}
1141
1142template <unsigned int tChannels>
1143void 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)
1144{
1145 ocean_assert(frame);
1146 ocean_assert(position.x() < width);
1147 ocean_assert(position.y() < height);
1148
1149 ocean_assert(horizontal >= 3u);
1150 ocean_assert(vertical >= 3u);
1151 ocean_assert(horizontal % 2u == 1u);
1152 ocean_assert(vertical % 2u == 1u);
1153
1154 // implicit form:
1155 // (x / a)^2 + (y / b)^2 == 1
1156 //
1157 // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1158
1159 const unsigned int horizontalHalf = horizontal >> 1u;
1160 const unsigned int verticalHalf = vertical >> 1u;
1161
1162 if (horizontalHalf < 199u && verticalHalf < 199u)
1163 {
1164 ellipse8BitPerChannel<unsigned int, tChannels>(frame, width, height, position, horizontalHalf, verticalHalf, value, paddingElements);
1165 }
1166 else
1167 {
1168 ellipse8BitPerChannel<unsigned long long, tChannels>(frame, width, height, position, horizontalHalf, verticalHalf, value, paddingElements);
1169 }
1170}
1171
1172template <unsigned int tChannels>
1173void 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)
1174{
1175 static_assert(tChannels != 0u, "Invalid channel number!");
1176
1177 ocean_assert(frame != 0u);
1178 ocean_assert(width >= 1u && height >= 1u);
1179
1180 const int clampedLeft = max(0, left);
1181 const int clampedTop = max(0, top);
1182
1183 const int clampedRightEnd = min(left + int(xSize), int(width)); // exclusive
1184 const int clampedBottomEnd = min(top + int(ySize), int(height));
1185
1186 if (clampedRightEnd <= clampedLeft || clampedBottomEnd <= clampedTop)
1187 {
1188 // we are entirely outside the frame
1189 return;
1190 }
1191
1192 using PixelType = typename DataType<uint8_t, tChannels>::Type;
1193
1194 const uint8_t black[tChannels] = {0u};
1195 const PixelType pixelValue = value ? *(const PixelType*)value : *(const PixelType*)black;
1196
1197 const unsigned int clampedWidth = (unsigned int)(clampedRightEnd - clampedLeft);
1198 const unsigned int clampedHeight = (unsigned int)(clampedBottomEnd - clampedTop);
1199
1200 ocean_assert(clampedWidth <= xSize);
1201 ocean_assert(clampedHeight <= ySize);
1202
1203 ocean_assert(clampedLeft + clampedWidth <= width);
1204 ocean_assert(clampedTop + clampedHeight <= height);
1205
1206 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1207
1208 for (unsigned int y = clampedTop; y < clampedTop + clampedHeight; ++y)
1209 {
1210 PixelType* const rowLeft = (PixelType*)(frame + y * frameStrideElements) + clampedLeft;
1211
1212 for (unsigned int x = 0u; x < clampedWidth; ++x)
1213 {
1214 rowLeft[x] = pixelValue;
1215 }
1216 }
1217}
1218
1219template <unsigned int tSize, PixelCenter tPixelCenter>
1220bool Canvas::point(Frame& frame, const Vector2& position, const uint8_t* value)
1221{
1222 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1223 static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1224
1225 ocean_assert(frame);
1226
1227 if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1228 {
1229 switch (frame.channels())
1230 {
1231 case 1u:
1232 point8BitPerChannel<1u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1233 return true;
1234
1235 case 2u:
1236 point8BitPerChannel<2u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1237 return true;
1238
1239 case 3u:
1240 point8BitPerChannel<3u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1241 return true;
1242
1243 case 4u:
1244 point8BitPerChannel<4u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), position, value, frame.paddingElements());
1245 return true;
1246
1247 default:
1248 break;
1249 }
1250 }
1251
1252 ocean_assert(false && "Invalid frame type!");
1253 return false;
1254}
1255
1256
1257template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1258void Canvas::point8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vector2& position, const uint8_t* value, const unsigned int framePaddingElements)
1259{
1260 static_assert(tChannels >= 1u, "Invalid channel number!");
1261 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1262 static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1263
1264 ocean_assert(frame != nullptr);
1265
1266 const uint8_t explicitValue[tChannels] = {0x00};
1267
1268 point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, value ? value : explicitValue, FilterFactors<tSize>(), framePaddingElements);
1269}
1270
1271template <unsigned int tSize, PixelCenter tPixelCenter>
1272bool Canvas::points(Frame& frame, const Vectors2& positions, const uint8_t* value)
1273{
1274 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1275 static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1276
1277 ocean_assert(frame);
1278
1279 if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1280 {
1281 switch (frame.channels())
1282 {
1283 case 1u:
1284 points8BitPerChannel<1u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1285 return true;
1286
1287 case 2u:
1288 points8BitPerChannel<2u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1289 return true;
1290
1291 case 3u:
1292 points8BitPerChannel<3u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1293 return true;
1294
1295 case 4u:
1296 points8BitPerChannel<4u, tSize, tPixelCenter>(frame.data<uint8_t>(), frame.width(), frame.height(), positions, value, frame.paddingElements());
1297 return true;
1298
1299 default:
1300 break;
1301 }
1302 }
1303
1304 ocean_assert(false && "Invalid frame type!");
1305 return false;
1306}
1307
1308
1309template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1310void Canvas::points8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const Vectors2& positions, const uint8_t* value, const unsigned int framePaddingElements)
1311{
1312 static_assert(tChannels >= 1u, "Invalid channel number!");
1313 static_assert(tSize % 2u == 1u, "Invalid size parameter!");
1314 static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1315
1316 ocean_assert(frame != nullptr);
1317
1318 if (value)
1319 {
1320 for (const Vector2& position : positions)
1321 {
1322 point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, value, FilterFactors<tSize>(), framePaddingElements);
1323 }
1324 }
1325 else
1326 {
1327 const uint8_t explicitValue[tChannels] = {0x00};
1328
1329 for (const Vector2& position : positions)
1330 {
1331 point8BitPerChannel<tChannels, tSize, tPixelCenter>(frame, width, height, position, explicitValue, FilterFactors<tSize>(), framePaddingElements);
1332 }
1333 }
1334}
1335
1336template <typename T, unsigned int tChannels>
1337void 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)
1338{
1339 static_assert(tChannels != 0u, "Invalid number of channels!");
1340
1341 ocean_assert(frame);
1342 ocean_assert(verticalHalf > 0u);
1343 ocean_assert(horizontalHalf > 0u);
1344 ocean_assert(position.x() < width);
1345 ocean_assert(position.y() < height);
1346
1347 const unsigned int frameStrideElements = width * tChannels + paddingElements;
1348
1349 using PixelType = typename DataType<uint8_t, tChannels>::Type;
1350 const uint8_t valueZero[tChannels] = {uint8_t(0)};
1351
1352 const PixelType* const pixelValue = value == nullptr ? (PixelType*)valueZero : (PixelType*)value;
1353
1354 // implicit form:
1355 // (x / a)^2 + (y / b)^2 == 1
1356 //
1357 // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1358
1359 // 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:
1360 // const T a2 = sqr(horizontalHalf);
1361 // const T b2 = sqr(verticalHalf);
1362 // Instead we take the center between the real radius and the radius which is one pixel larger to overcome the single pixel issue
1363
1364 const T a2 = (sqr(horizontalHalf) + sqr(horizontalHalf + 1u)) / 2u;
1365 const T b2 = (sqr(verticalHalf) + sqr(verticalHalf + 1u)) / 2u;
1366 const T ab2 = a2 * b2;
1367
1368 for (unsigned int y = position.y(); y <= position.y() + verticalHalf; ++y)
1369 {
1370 unsigned int left = position.x();
1371 unsigned int right = position.x() + horizontalHalf + 1u;
1372
1373 const T ySqra2 = T(sqr(y - position.y())) * a2;
1374
1375 while (left + 1u < right)
1376 {
1377 ocean_assert(T(sqr(left - position.x())) * b2 + T(sqr(y - position.y())) * a2 <= ab2);
1378
1379 const unsigned int mid = (left + right) / 2u;
1380
1381 if (T(sqr(mid - position.x())) * b2 + ySqra2 <= ab2)
1382 {
1383 left = mid;
1384 }
1385 else
1386 {
1387 right = mid;
1388 }
1389 }
1390
1391 ocean_assert(left + 1u == right);
1392 ocean_assert(T(sqr(left - position.x())) * b2 + T(sqr(y - position.y())) * a2 <= ab2);
1393 ocean_assert(T(sqr(right - position.x())) * b2 + T(sqr(y - position.y())) * a2 > ab2);
1394
1395 const unsigned int frameLeft = max(0, int(2u * position.x() - left));
1396 const unsigned int frameRight = min(right, width);
1397
1398 ocean_assert(frameLeft < width);
1399 ocean_assert(frameRight <= width);
1400 ocean_assert(frameLeft < frameRight);
1401
1402 // top
1403 if (2u * position.y() >= y)
1404 {
1405 const unsigned int frameTop = 2u * position.y() - y;
1406 ocean_assert(frameTop < height);
1407
1408 PixelType* pointer = (PixelType*)(frame + frameTop * frameStrideElements) + frameLeft;
1409 PixelType* const pointerEnd = pointer + (frameRight - frameLeft);
1410
1411 while (pointer != pointerEnd)
1412 {
1413 *pointer++ = *pixelValue;
1414 }
1415 }
1416
1417 // bottom
1418 if (y < height)
1419 {
1420 PixelType* pointer = (PixelType*)(frame + y * frameStrideElements) + frameLeft;
1421 PixelType* const pointerEnd = pointer + (frameRight - frameLeft);
1422
1423 while (pointer != pointerEnd)
1424 {
1425 *pointer++ = *pixelValue;
1426 }
1427 }
1428 }
1429}
1430
1431template <unsigned int tChannels>
1432void 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)
1433{
1434 static_assert(tChannels != 0u, "Invalid number of channels!");
1435
1436 ocean_assert(frame);
1437 ocean_assert(position.x() < width);
1438 ocean_assert(position.y() < height);
1439
1440 const unsigned int frameStrideElements = width * tChannels + paddingElements;
1441
1442 using PixelType = typename DataType<uint8_t, tChannels>::Type;
1443 const uint8_t valueZero[tChannels] = {0u};
1444
1445 const PixelType* const pixelValue = value == nullptr ? (PixelType*)valueZero : (PixelType*)value;
1446
1447 // implicit form:
1448 // (x / a)^2 + (y / b)^2 == 1
1449 //
1450 // x^2 * b^2 + y^2 * a^2 == a^2 * b^2
1451
1452 const Scalar factorA = 1 / Scalar(sqr(horizontalHalf));
1453 const Scalar factorB = 1 / Scalar(sqr(verticalHalf));
1454
1455 const SquareMatrix3 invertedRotation(Rotation(0, 0, 1, angle));
1456
1457 const uint8_t radius = uint8_t(max(horizontalHalf, verticalHalf));
1458
1459 for (unsigned int y = max(0, int(position.y() - radius)); y <= min(position.y() + radius, height); ++y)
1460 {
1461 for (unsigned int x = max(0, int(position.x() - radius)); x <= min(position.x() + radius, width); ++x)
1462 {
1463 const Vector3 position3(Scalar(position.x()) - Scalar(x), Scalar(position.y()) - Scalar(y), 0);
1464 Vector3 invertedPosition(invertedRotation * position3);
1465
1466 if (Numeric::sqr(invertedPosition.x()) * factorA + Numeric::sqr(invertedPosition.y()) * factorB <= 1)
1467 {
1468 *((PixelType*)(frame + y * frameStrideElements) + x) = *pixelValue;
1469 }
1470 }
1471 }
1472}
1473
1474template <unsigned int tChannels, unsigned int tSize, PixelCenter tPixelCenter>
1475void 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)
1476{
1477 static_assert(tChannels >= 1u, "Invalid channel number!");
1478 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1479 static_assert(tPixelCenter == PC_TOP_LEFT || tPixelCenter == PC_CENTER, "Invalid pixel center!");
1480
1481 ocean_assert(frame != nullptr);
1482
1483 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1484
1485 // the remaining function expects PC_CENTER as pixel center so shifting the position in case the coordinate is provided as PC_TOP_LEFT
1486 const Vector2 shiftedPosition = tPixelCenter == PC_TOP_LEFT ? position + Vector2(Scalar(0.5), Scalar(0.5)) : position;
1487
1488 const int left = int(Numeric::floor(shiftedPosition.x() - Scalar(0.5)));
1489 const int top = int(Numeric::floor(shiftedPosition.y() - Scalar(0.5)));
1490
1491 const unsigned int xFactor = (unsigned int)((Scalar(left) + Scalar(1.5) - shiftedPosition.x()) * Scalar(128) + Scalar(0.5));
1492 const unsigned int yFactor = (unsigned int)((Scalar(top) + Scalar(1.5) - shiftedPosition.y()) * Scalar(128) + Scalar(0.5));
1493
1494 ocean_assert(xFactor <= 128u && yFactor <= 128u);
1495
1496 const unsigned int sqrMaximalFilter = factors.maximalFactor() * factors.maximalFactor();
1497
1498 for (unsigned int y = 0u; y <= tSize; ++y)
1499 {
1500 const unsigned int yInFrame = top + int(y) - int(tSize / 2u);
1501
1502 if (yInFrame < height)
1503 {
1504 for (unsigned int x = 0u; x <= tSize; ++x)
1505 {
1506 const unsigned int xInFrame = left + int(x) - int(tSize / 2u);
1507
1508 if (xInFrame < width)
1509 {
1510 const unsigned int factor = (128u - yFactor) * factors.clampedFactor(int(y - 1u)) * (128u - xFactor) * factors.clampedFactor(int(x - 1u))
1511 + (128u - yFactor) * factors.clampedFactor(int(y - 1u)) * xFactor * factors.clampedFactor(x)
1512 + yFactor * factors.clampedFactor(y) * (128u - xFactor) * factors.clampedFactor(int(x - 1u))
1513 + yFactor * factors.clampedFactor(y) * xFactor * factors.clampedFactor(x);
1514
1515 const unsigned int _factor = 16384 * sqrMaximalFilter - factor;
1516
1517 uint8_t* const pixel = frame + yInFrame * frameStrideElements + xInFrame * tChannels;
1518
1519 for (unsigned int n = 0u; n < tChannels; ++n)
1520 {
1521 pixel[n] = uint8_t((pixel[n] * _factor + value[n] * factor + (16384u * sqrMaximalFilter) / 2u) / (16384u * sqrMaximalFilter));
1522 }
1523 }
1524 }
1525 }
1526 }
1527}
1528
1529template <unsigned int tChannels>
1530void Canvas::fill8BitPerChannel(uint8_t* frame, const unsigned int width, const unsigned int height, const PixelPosition& position, const uint8_t* value, const unsigned int framePaddingElements)
1531{
1532 static_assert(tChannels != 0u, "Invalid channel number!");
1533
1534 ocean_assert(frame);
1535 ocean_assert(width >= 1u && height >= 1u);
1536
1537 ocean_assert(position.x() < width && position.y() < height);
1538
1539 using PixelType = typename DataType<uint8_t, tChannels>::Type;
1540
1541 const uint8_t zeroValue[tChannels] = {0u};
1542 const PixelType pixelValue = value ? *((PixelType*)value) : *((PixelType*)zeroValue);
1543
1544 const unsigned int frameStrideElements = width * tChannels + framePaddingElements;
1545
1546 const unsigned int offset = position.y() * frameStrideElements + position.x() * tChannels;
1547
1548 // check whether the start position has the same color like the given replacement color
1549 if (*(const PixelType*)(frame + offset) == pixelValue)
1550 {
1551 return;
1552 }
1553
1554 const PixelType areaPixelValue = *(const PixelType*)(frame + offset);
1555 *(PixelType*)(frame + offset) = pixelValue;
1556
1557 // we use a vector and not a std::stack as the stack implementation is significantly slower
1558 std::vector<PixelPosition> stack;
1559 stack.reserve((width * height) / 16u);
1560
1561 // left
1562 if (position.x() != 0u && *((const PixelType*)(frame + offset) - 1) == areaPixelValue)
1563 {
1564 stack.push_back(position.west());
1565 }
1566
1567 // right
1568 if (position.x() != width - 1u && *((const PixelType*)(frame + offset) + 1) == areaPixelValue)
1569 {
1570 stack.push_back(position.east());
1571 }
1572
1573 // top
1574 if (position.y() != 0u && *((const PixelType*)(frame + offset - frameStrideElements)) == areaPixelValue)
1575 {
1576 stack.push_back(position.north());
1577 }
1578
1579 // bottom
1580 if (position.y() != height - 1u && *((const PixelType*)(frame + offset + frameStrideElements)) == areaPixelValue)
1581 {
1582 stack.push_back(position.south());
1583 }
1584
1585 while (!stack.empty())
1586 {
1587 const PixelPosition pixel(stack.back());
1588 stack.pop_back();
1589
1590 const unsigned int testOffset = pixel.y() * frameStrideElements + pixel.x() * tChannels;
1591
1592 ocean_assert(*(const PixelType*)(frame + testOffset) == areaPixelValue);
1593
1594 *(PixelType*)(frame + testOffset) = pixelValue;
1595
1596 // left
1597 if (pixel.x() != 0u && *((const PixelType*)(frame + testOffset) - 1) == areaPixelValue)
1598 {
1599 stack.push_back(pixel.west());
1600 }
1601
1602 // right
1603 if (pixel.x() != width - 1u && *((const PixelType*)(frame + testOffset) + 1) == areaPixelValue)
1604 {
1605 stack.push_back(pixel.east());
1606 }
1607
1608 // top
1609 if (pixel.y() != 0u && *((const PixelType*)(frame + testOffset - frameStrideElements)) == areaPixelValue)
1610 {
1611 stack.push_back(pixel.north());
1612 }
1613
1614 // bottom
1615 if (pixel.y() != height - 1u && *((const PixelType*)(frame + testOffset + frameStrideElements)) == areaPixelValue)
1616 {
1617 stack.push_back(pixel.south());
1618 }
1619 }
1620}
1621
1622template <unsigned int tSize>
1623bool Canvas::polygon(Frame& frame, const Vector2* points, size_t numberPoints, const uint8_t* value, const bool closeLoop)
1624{
1625 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1626
1627 ocean_assert(frame.isValid());
1628
1629 if (frame.dataType() == FrameType::DT_UNSIGNED_INTEGER_8 && frame.numberPlanes() == 1u)
1630 {
1631 switch (frame.channels())
1632 {
1633 case 1u:
1634 polygon8BitPerChannel<1u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1635 return true;
1636
1637 case 2u:
1638 polygon8BitPerChannel<2u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1639 return true;
1640
1641 case 3u:
1642 polygon8BitPerChannel<3u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1643 return true;
1644
1645 case 4u:
1646 polygon8BitPerChannel<4u, tSize>(frame.data<uint8_t>(), frame.width(), frame.height(), points, numberPoints, value, closeLoop);
1647 return true;
1648
1649 default:
1650 break;
1651 }
1652 }
1653
1654 ocean_assert(false && "Invalid pixel format!");
1655 return false;
1656}
1657
1658template <unsigned int tChannels, unsigned int tSize>
1659void 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)
1660{
1661 static_assert(tChannels >= 1u, "Invalid channel number!");
1662 static_assert(tSize % 2u == 1u, "Invalid size parameter.");
1663
1664 ocean_assert(frame != nullptr);
1665 ocean_assert(width >= 1u && height >= 1u);
1666
1667 if (numberPoints >= 2)
1668 {
1669 for (size_t n = 1; n < numberPoints; ++n)
1670 {
1671 line8BitPerChannel<tChannels, tSize>(frame, width, height, points[n - 1], points[n], value, framePaddingElements);
1672 }
1673
1674 if (numberPoints >= 3 && closeLoop)
1675 {
1676 line8BitPerChannel<tChannels, tSize>(frame, width, height, points[numberPoints - 1], points[0], value, framePaddingElements);
1677 }
1678 }
1679}
1680
1681}
1682
1683}
1684
1685#endif // META_OCEAN_CV_CANVAS_H
This class implements Bresenham's 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:161
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:833
unsigned int clampedFactor(const int index) const
Returns the filter factor for a specific index.
Definition Canvas.h:822
unsigned int factor(const unsigned int index) const
Returns the filter factor for a specific index.
Definition Canvas.h:814
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 const uint8_t * white(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a white color.
static const uint8_t * blue(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a blue color.
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:1258
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 const uint8_t * green(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a green color.
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:1623
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:1659
static const uint8_t * black(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a black 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 * gray(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a gray color.
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 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:890
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:1530
static const uint8_t * red(const FrameType::PixelFormat pixelFormat=FrameType::FORMAT_RGB24)
Returns the color values for a red 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:1432
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:1143
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:1272
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:1173
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:839
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 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:1130
static bool point(Frame &frame, const Vector2 &position, const uint8_t *value=nullptr)
Paints a point with sub-pixel accuracy.
Definition Canvas.h:1220
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:1310
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:1094
PixelPositionT< T > west() const
Returns the pixel position west to this position.
Definition PixelPosition.h:558
PixelPositionT< T > north() const
Returns the pixel position north to this position.
Definition PixelPosition.h:546
PixelPositionT< T > east() const
Returns the pixel position east to this position.
Definition PixelPosition.h:582
T y() const
Returns the vertical coordinate position of this object.
Definition PixelPosition.h:468
T x() const
Returns the horizontal coordinate position of this object.
Definition PixelPosition.h:456
PixelPositionT< T > south() const
Returns the pixel position south to this position.
Definition PixelPosition.h:570
This class implements Ocean's image class.
Definition Frame.h:1879
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition Frame.h:4323
bool isValid() const
Returns whether this frame is valid.
Definition Frame.h:4612
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:4206
PixelFormat
Definition of all pixel formats available in the Ocean framework.
Definition Frame.h:183
unsigned int width() const
Returns the width of the frame format in pixel.
Definition Frame.h:3241
uint32_t numberPlanes() const
Returns the number of planes of the pixel format of this frame.
Definition Frame.h:3281
@ 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:3246
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition Frame.h:3271
DataType dataType() const
Returns the data type of the pixel format of this frame.
Definition Frame.h:3261
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:2035
static constexpr T sqr(const T value)
Returns the square of a given value.
Definition Numeric.h:1499
static constexpr T binomialCoefficient(const T &n, const T &k)
Returns the binomial coefficient for two binomial parameters.
Definition Numeric.h:1966
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:710
const T & y() const noexcept
Returns the y value.
Definition Vector2.h:722
T length() const
Returns the length of the vector.
Definition Vector2.h:627
const T & y() const noexcept
Returns the y value.
Definition Vector3.h:824
const T & x() const noexcept
Returns the x value.
Definition Vector3.h:812
unsigned int sqr(const char value)
Returns the square value of a given value.
Definition base/Utilities.h:1099
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
std::vector< Vector2 > Vectors2
Definition of a vector holding Vector2 objects.
Definition Vector2.h:64
float Scalar
Definition of a scalar type.
Definition Math.h:129
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition Vector2.h:28
RotationT< Scalar > Rotation
Definition of the Rotation object, depending on the OCEAN_MATH_USE_SINGLE_PRECISION flag either with ...
Definition Rotation.h:32
std::vector< FiniteLine2 > FiniteLines2
Definition of a vector holding FiniteLine2 objects.
Definition FiniteLine2.h:57
std::vector< Line2 > Lines2
Definition of a vector holding Line2 objects.
Definition Line2.h:57
The namespace covering the entire Ocean framework.
Definition Accessor.h:15
Default definition of a type with tBytes bytes.
Definition DataType.h:32