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