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