Ocean
FrameEnlarger.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_FRAME_ENLARGER_H
9 #define META_OCEAN_CV_FRAME_ENLARGER_H
10 
11 #include "ocean/cv/CV.h"
12 #include "ocean/cv/FrameBlender.h"
13 
14 #include "ocean/base/DataType.h"
15 #include "ocean/base/Frame.h"
16 #include "ocean/base/Worker.h"
17 
18 namespace Ocean
19 {
20 
21 namespace CV
22 {
23 
24 /**
25  * This class implements functions to enlarge/up-sample frames.
26  * @ingroup cv
27  */
28 class OCEAN_CV_EXPORT FrameEnlarger
29 {
30  public:
31 
32  /**
33  * The following comfort class provides comfortable functions simplifying prototyping applications but also increasing binary size of the resulting applications.
34  * Best practice is to avoid using these functions if binary size matters,<br>
35  * as for every comfort function a corresponding function exists with specialized functionality not increasing binary size significantly.<br>
36  */
37  class OCEAN_CV_EXPORT Comfort
38  {
39  public:
40 
41  /**
42  * Adds a border to the given frame while all new pixels will receive a specified border color.
43  * @param source The source frame to be extended with a border, must be valid
44  * @param target The target frame receiving the extended frame, will be set to the correct pixel format and frame dimension
45  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
46  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
47  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
48  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
49  * @param color The border color to be used for the new border pixels, one value for each channel, must be valid
50  * @return True, if succeeded
51  */
52  static bool addBorder(const Frame& source, Frame& target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const void* color);
53 
54  /**
55  * Adds a border to the given frame while all new pixels will receive a specified border color.
56  * @param frame The frame to be extended by a border, must be valid
57  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
58  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
59  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
60  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
61  * @param color The border color to be used for the new border pixels, one value for each channel, must be valid
62  * @return True, if succeeded
63  */
64  static inline bool addBorder(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const void* color);
65 
66  /**
67  * Adds a border to the given frame.
68  * The color of the border pixels are defined by the nearest pixels of the original frame.
69  * @param source The source frame to be extended with a border, must be valid
70  * @param target The target frame receiving the extended frame, will be set to the correct pixel format and frame dimension
71  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
72  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
73  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
74  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
75  * @return True, if succeeded
76  */
77  static bool addBorderNearestPixel(const Frame& source, Frame& target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom);
78 
79  /**
80  * Adds a border to the given frame.
81  * The color of the border pixels are defined by the nearest pixels of the original frame.
82  * @param frame The frame to be extended by a border, must be valid
83  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
84  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
85  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
86  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
87  * @return True, if succeeded
88  */
89  static inline bool addBorderNearestPixel(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom);
90 
91  /**
92  * Adds a border to the given frame by mirroring the frame border (and border neighbor) pixels.
93  * @param source The source frame to be extended with a border, must be valid
94  * @param target The target frame receiving the extended frame, will be set to the correct pixel format and frame dimension
95  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, frame.width()]
96  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, frame.height()]
97  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, frame.width()]
98  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, frame.height()]
99  * @return True, if succeeded
100  */
101  static bool addBorderMirrored(const Frame& source, Frame& target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom);
102 
103  /**
104  * Adds a border to the given frame by mirroring the frame border (and border neighbor) pixels.
105  * @param frame The frame to be extended by a border, must be valid
106  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, frame.width()]
107  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, frame.height()]
108  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, frame.width()]
109  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, frame.height()]
110  * @return True, if succeeded
111  */
112  static inline bool addBorderMirrored(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom);
113 
114  /**
115  * Doubles the size of a given frame by a pixel repeating upsampling.
116  * @param source The source (and untouched) frame to be upsized, must be valid
117  * @param target The target frame receiving the upsized frame, will be set to the correct pixel format and frame dimension
118  * @param worker Optional worker object to distribute the computation
119  * @return True, if succeeded
120  */
121  static bool multiplyByTwo(const Frame& source, Frame& target, Worker* worker = nullptr);
122 
123  /**
124  * Adds a transparent border to a given frame.
125  * The color of the transparent border pixels are taken from the nearest image pixel.<br>
126  * @param source The source frame which will be extended with a transparent border
127  * @param target Resulting target frame with transparent border
128  * @param leftBorder Size of the left frame border in pixel, with range [0, infinity)
129  * @param topBorder Size of the top frame border in pixel, with range [0, infinity)
130  * @param rightBorder Size of the right frame border in pixel, with range [0, infinity)
131  * @param bottomBorder Size of the bottom frame border in pixel, with range [0, infinity)
132  * @return True, if succeeded
133  * @tparam tTransparentIs0xFF True, if 0xFF is interpreted as fully transparent
134  */
135  template <bool tTransparentIs0xFF>
136  static bool addTransparentBorder(const Frame& source, Frame& target, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder);
137 
138  /**
139  * Adds a transparent border to a given frame.
140  * The color of the transparent border pixels are taken from the nearest image pixel.<br>
141  * @param frame The frame which will be extended with a transparent border
142  * @param leftBorder Size of the left frame border in pixel, with range [0, infinity)
143  * @param topBorder Size of the top frame border in pixel, with range [0, infinity)
144  * @param rightBorder Size of the right frame border in pixel, with range [0, infinity)
145  * @param bottomBorder Size of the bottom frame border in pixel, with range [0, infinity)
146  * @return True, if succeeded
147  * @tparam tTransparentIs0xFF True, if 0xFF is interpreted as fully transparent
148  */
149  template <bool tTransparentIs0xFF>
150  static bool addTransparentBorder(Frame& frame, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder);
151  };
152 
153  /**
154  * Adds a transparent border to a given frame.
155  * The color of the transparent border pixels are taken from the nearest image pixel.<br>
156  * @param source The source frame which will be extended with a transparent border
157  * @param target Resulting target frame with transparent border
158  * @param width The width of the source frame in pixel, with range [1, infinity)
159  * @param height The height of the source frame in pixel, with range [1, infinity)
160  * @param leftBorder Size of the left frame border in pixel, with range [1, infinity)
161  * @param topBorder Size of the top frame border in pixel, with range [1, infinity)
162  * @param rightBorder Size of the right frame border in pixel, with range [1, infinity)
163  * @param bottomBorder Size of the bottom frame border in pixel, with range [1, infinity)
164  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
165  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
166  * @tparam tChannelsWithAlpha Number of channels in the source frame (including the alpha channel)
167  * @tparam tAlphaAtFront True, if the alpha channel is in the front of the data channels
168  * @tparam tSourceHasAlpha True, if not only the source frame holds an alpha channel but also the target frame, however values in a target alpha channel will be untouched
169  * @tparam tTransparentIs0xFF True, if 0xFF is interpreted as fully transparent
170  */
171  template <unsigned int tChannelsWithAlpha, bool tAlphaAtFront, bool tSourceHasAlpha, bool tTransparentIs0xFF>
172  static void addTransparentBorder8BitPerChannel(const unsigned char* source, unsigned char* target, const unsigned int width, const unsigned int height, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements);
173 
174  /**
175  * Adds a border to a given frame while all new pixels will receive a specified border color/value.
176  * @param source The source image to be extended, must be valid
177  * @param target The target image receiving the extended frame, with resolution (sourceWidth + borderSizeLeft + borderSizeRight)x(sourceHeight + borderSizeTop + borderSizeBottom), must be valid
178  * @param sourceWidth Width of the original source image in pixel, with range [1, infinity)
179  * @param sourceHeight Height of the original source image in pixel, with range [1, infinity)
180  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
181  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
182  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
183  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
184  * @param color Border color/value to be used for the new border pixels, must be tChannels values
185  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
186  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
187  * @tparam T The data type of a pixel channel
188  * @tparam tChannels The number of data channels, with range [1, infinity)
189  */
190  template <typename T, unsigned int tChannels>
191  static void addBorder(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const T* color, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements);
192 
193  /**
194  * Adds a border to a given frame while the color of the border pixels are defined by the nearest pixels of the original frame.
195  * @param source The source image to be extended, must be valid
196  * @param target The target image receiving the extended frame, with resolution (sourceWidth + borderSizeLeft + borderSizeRight)x(sourceHeight + borderSizeTop + borderSizeBottom), must be valid
197  * @param sourceWidth Width of the original source image in pixel, with range [1, infinity)
198  * @param sourceHeight Height of the original source image in pixel, with range [1, infinity)
199  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, infinity)
200  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, infinity)
201  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, infinity)
202  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, infinity)
203  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
204  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
205  * @tparam T The data type of a pixel channel
206  * @tparam tChannels The number of data channels, with range [1, infinity)
207  */
208  template <typename T, unsigned int tChannels>
209  static void addBorderNearestPixel(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements);
210 
211  /**
212  * Adds a border to a given frame by mirroring the frame's content.
213  * @param source The source image to be extended, must be valid
214  * @param target The target image receiving the extended frame, with resolution (sourceWidth + borderSizeLeft + borderSizeRight)x(sourceHeight + borderSizeTop + borderSizeBottom), must be valid
215  * @param sourceWidth Width of the original source image in pixel, with range [1, infinity)
216  * @param sourceHeight Height of the original source image in pixel, with range [1, infinity)
217  * @param borderSizeLeft The size of the border at the left image boundary, in pixel, with range [0, sourceWidth]
218  * @param borderSizeTop The size of the border at the top image boundary, in pixel, with range [0, sourceHeight]
219  * @param borderSizeRight The size of the border at the right image boundary, in pixel, with range [0, sourceWidth]
220  * @param borderSizeBottom The size of the border at the bottom image boundary, in pixel, with range [0, sourceHeight]
221  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
222  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
223  * @tparam T The data type of a pixel channel
224  * @tparam tChannels The number of data channels, with range [1, infinity)
225  */
226  template <typename T, unsigned int tChannels>
227  static void addBorderMirrored(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements);
228 
229  /**
230  * Doubles the size of a given frame by a pixel repeating upsampling.
231  * @param source Buffer of the source frame to be upsampled
232  * @param target Buffer of the target frame receiving the upsampled frame
233  * @param targetWidth Width of the target buffer in pixel, with range [2, infinity) and targetWidth / 2 == sourceWidth
234  * @param targetHeight Height of the target buffer in pixel, with range [2, infinity) and targetHeight / 2 == sourceHeight
235  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
236  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
237  * @param worker Optional worker object to distribute the computation
238  * @tparam T The data type of a pixel channel
239  * @tparam tChannels The number of data channels, with range [1, infinity)
240  */
241  template <typename T, unsigned int tChannels>
242  static void multiplyByTwo(const T* source, T* target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
243 
244  private:
245 
246  /**
247  * Doubles a subset of a given frame by a pixel repeating upsampling.
248  * @param source Buffer of the source frame to be upsampled
249  * @param target Buffer of the target frame receiving the upsampled frame
250  * @param targetWidth Width of the target buffer in pixel, with range [2, infinity) and targetWidth / 2 == sourceWidth
251  * @param targetHeight Height of the target buffer in pixel, with range [2, infinity) and targetHeight / 2 == sourceHeight
252  * @param sourcePaddingElements The number of padding elements at the end of each source row, in elements, with range [0, infinity)
253  * @param targetPaddingElements The number of padding elements at the end of each target row, in elements, with range [0, infinity)
254  * @param firstTargetRow First target row to be handled, with range [0, targetHeight)
255  * @param numberTargetRows Number of target rows to be handled, with range [1, targetHeight]
256  * @tparam T The data type of a pixel channel
257  * @tparam tChannels The number of data channels, with range [1, infinity)
258  */
259  template <typename T, unsigned int tChannels>
260  static void multiplyByTwoSubset(const T* source, T* target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstTargetRow, const unsigned int numberTargetRows);
261 };
262 
263 inline bool FrameEnlarger::Comfort::addBorder(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const void* color)
264 {
265  ocean_assert(frame.isValid());
266  ocean_assert(color != nullptr);
267 
268  Frame tmpFrame;
269  if (!addBorder(frame, tmpFrame, borderSizeLeft, borderSizeTop, borderSizeRight, borderSizeBottom, color))
270  {
271  return false;
272  }
273 
274  tmpFrame.setTimestamp(frame.timestamp());
275  tmpFrame.setRelativeTimestamp(frame.relativeTimestamp());
276 
277  frame = std::move(tmpFrame);
278  return true;
279 }
280 
281 bool FrameEnlarger::Comfort::addBorderNearestPixel(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom)
282 {
283  ocean_assert(frame.isValid());
284 
285  Frame tmpFrame;
286  if (!addBorderNearestPixel(frame, tmpFrame, borderSizeLeft, borderSizeTop, borderSizeRight, borderSizeBottom))
287  {
288  return false;
289  }
290 
291  tmpFrame.setTimestamp(frame.timestamp());
292  tmpFrame.setRelativeTimestamp(frame.relativeTimestamp());
293 
294  frame = std::move(tmpFrame);
295  return true;
296 }
297 
298 bool FrameEnlarger::Comfort::addBorderMirrored(Frame& frame, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom)
299 {
300  ocean_assert(frame.isValid());
301 
302  Frame tmpFrame;
303  if (!addBorderMirrored(frame, tmpFrame, borderSizeLeft, borderSizeTop, borderSizeRight, borderSizeBottom))
304  {
305  return false;
306  }
307 
308  tmpFrame.setTimestamp(frame.timestamp());
309  tmpFrame.setRelativeTimestamp(frame.relativeTimestamp());
310 
311  frame = std::move(tmpFrame);
312  return true;
313 }
314 
315 
316 template <typename T, unsigned int tChannels>
317 void FrameEnlarger::addBorder(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const T* color, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
318 {
319  static_assert(tChannels >= 1u, "Invalid channel number!");
320 
321  ocean_assert(source != nullptr && target != nullptr);
322  ocean_assert(sourceWidth != 0u && sourceHeight != 0u);
323 
324  typedef typename DataType<T, tChannels>::Type PixelType;
325  static_assert(sizeof(PixelType) == sizeof(T) * tChannels, "Invalid pixel type!");
326 
327  const unsigned int targetWidth = sourceWidth + borderSizeLeft + borderSizeRight;
328 
329  const unsigned int sourceStrideElements = sourceWidth * tChannels + sourcePaddingElements;
330  const unsigned int targetStrideElements = targetWidth * tChannels + targetPaddingElements;
331 
332  const PixelType borderColorPixel = *((const PixelType*)color);
333 
334  if (borderSizeTop != 0u)
335  {
336  // top border rows
337 
338  // first row
339  for (unsigned int n = 0u; n < targetWidth; ++n)
340  {
341  ((PixelType*)target)[n] = borderColorPixel;
342  }
343 
344  // following top borders
345  for (unsigned int y = 1u; y < borderSizeTop; ++y)
346  {
347  memcpy(target + y * targetStrideElements, target, targetWidth * sizeof(PixelType));
348  }
349  }
350 
351  for (unsigned int y = 0u; y < sourceHeight; ++y)
352  {
353  const PixelType* sourcePixel = (const PixelType*)(source + y * sourceStrideElements);
354  PixelType* targetPixel = (PixelType*)(target + (borderSizeTop + y) * targetStrideElements);
355 
356  if (borderSizeTop == 0u)
357  {
358  for (unsigned int n = 0u; n < borderSizeLeft; ++n)
359  {
360  targetPixel[n] = borderColorPixel;
361  }
362  }
363  else
364  {
365  // left
366  memcpy(targetPixel, target, borderSizeLeft * sizeof(PixelType));
367  }
368 
369  targetPixel += borderSizeLeft;
370 
371  // center
372  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
373 
374  targetPixel += sourceWidth;
375  sourcePixel += sourceWidth;
376 
377  if (borderSizeTop == 0u)
378  {
379  for (unsigned int n = 0u; n < borderSizeRight; ++n)
380  {
381  targetPixel[n] = borderColorPixel;
382  }
383  }
384  else
385  {
386  // right
387  memcpy(targetPixel, target, borderSizeRight * sizeof(PixelType));
388  }
389  }
390 
391  if (borderSizeBottom != 0u)
392  {
393  PixelType* targetPixel = (PixelType*)(target + (borderSizeTop + sourceHeight) * targetStrideElements);
394 
395  // first row
396  for (unsigned int n = 0u; n < targetWidth; ++n)
397  {
398  targetPixel[n] = borderColorPixel;
399  }
400 
401  // following top borders
402  for (unsigned int y = 1u; y < borderSizeBottom; ++y)
403  {
404  memcpy(target + (borderSizeTop + sourceHeight + y) * targetStrideElements, targetPixel, targetWidth * sizeof(PixelType));
405  }
406  }
407 }
408 
409 template <typename T, unsigned int tChannels>
410 void FrameEnlarger::addBorderNearestPixel(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
411 {
412  static_assert(tChannels >= 1u, "Invalid channel number!");
413 
414  ocean_assert(source != nullptr && target != nullptr);
415  ocean_assert(sourceWidth != 0u && sourceHeight != 0u);
416 
417  typedef typename DataType<T, tChannels>::Type PixelType;
418  static_assert(sizeof(PixelType) == sizeof(T) * tChannels, "Invalid pixel type!");
419 
420  const unsigned int targetWidth = sourceWidth + borderSizeLeft + borderSizeRight;
421 
422  const unsigned int sourceStrideElements = sourceWidth * tChannels + sourcePaddingElements;
423  const unsigned int targetStrideElements = targetWidth * tChannels + targetPaddingElements;
424 
425  const PixelType* sourcePixel = (const PixelType*)source;
426  PixelType* targetPixel = (PixelType*)target;
427 
428  if (borderSizeTop != 0u)
429  {
430  // top border rows
431  for (unsigned int x = 0u; x < borderSizeLeft; ++x)
432  {
433  targetPixel[x] = *sourcePixel;
434  }
435 
436  targetPixel += borderSizeLeft;
437 
438  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
439  targetPixel += sourceWidth;
440 
441  for (unsigned int x = 0u; x < borderSizeRight; ++x)
442  {
443  targetPixel[x] = sourcePixel[sourceWidth - 1u];
444  }
445 
446  targetPixel += borderSizeRight;
447 
448  // following top borders
449  for (unsigned int y = 1u; y < borderSizeTop; ++y)
450  {
451  memcpy(target + y * targetStrideElements, target, targetWidth * sizeof(PixelType));
452  }
453  }
454 
455  // middle rows
456  for (unsigned int y = 0u; y < sourceHeight; ++y)
457  {
458  sourcePixel = (const PixelType*)(source + y * sourceStrideElements);
459  targetPixel = (PixelType*)(target + (borderSizeTop + y) * targetStrideElements);
460 
461  // left border columns
462  for (unsigned int x = 0u; x < borderSizeLeft; ++x)
463  {
464  targetPixel[x] = *sourcePixel;
465  }
466 
467  targetPixel += borderSizeLeft;
468 
469  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
470 
471  targetPixel += sourceWidth;
472  sourcePixel += sourceWidth - 1u;
473 
474  // right border columns
475  for (unsigned int x = 0u; x < borderSizeRight; ++x)
476  {
477  targetPixel[x] = *sourcePixel;
478  }
479  }
480 
481  if (borderSizeBottom != 0u)
482  {
483  sourcePixel = (const PixelType*)(source + (sourceHeight - 1u) * sourceStrideElements);
484  targetPixel = (PixelType*)(target + (borderSizeTop + sourceHeight) * targetStrideElements);
485 
486  // first bottom row
487  for (unsigned int x = 0u; x < borderSizeLeft; ++x)
488  {
489  targetPixel[x] = *sourcePixel;
490  }
491 
492  targetPixel += borderSizeLeft;
493 
494  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
495  targetPixel += sourceWidth;
496 
497  for (unsigned int x = 0u; x < borderSizeRight; ++x)
498  {
499  targetPixel[x] = sourcePixel[sourceWidth - 1u];
500  }
501 
502  // following top borders
503  const unsigned int targetHeight = sourceHeight + borderSizeTop + borderSizeBottom;
504 
505  targetPixel = (PixelType*)(target + (targetHeight - borderSizeBottom) * targetStrideElements);
506 
507  for (unsigned int y = targetHeight - borderSizeBottom + 1u; y < targetHeight; ++y)
508  {
509  memcpy(target + y * targetStrideElements,targetPixel, targetWidth * sizeof(PixelType));
510  }
511  }
512 }
513 
514 template <typename T, unsigned int tChannels>
515 void FrameEnlarger::addBorderMirrored(const T* source, T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
516 {
517  static_assert(tChannels >= 1u, "Invalid channel number!");
518 
519  ocean_assert(source != nullptr && target != nullptr);
520  ocean_assert(sourceWidth != 0u && sourceHeight != 0u);
521  ocean_assert(borderSizeLeft <= sourceWidth && borderSizeRight <= sourceWidth);
522  ocean_assert(borderSizeTop <= sourceHeight && borderSizeBottom <= sourceHeight);
523 
524  typedef typename DataType<T, tChannels>::Type PixelType;
525  static_assert(sizeof(PixelType) == sizeof(T) * tChannels, "Invalid pixel type!");
526 
527  const unsigned int targetWidth = sourceWidth + borderSizeLeft + borderSizeRight;
528 
529  const unsigned int sourceStrideElements = sourceWidth * tChannels + sourcePaddingElements;
530  const unsigned int targetStrideElements = targetWidth * tChannels + targetPaddingElements;
531 
532  // top rows
533 
534  for (unsigned int y = 0u; y < borderSizeTop; ++y)
535  {
536  const PixelType* sourcePixel = (const PixelType*)(source + (borderSizeTop - y - 1u) * sourceStrideElements);
537  PixelType* targetPixel = (PixelType*)(target + y * targetStrideElements);
538 
539  // left
540  for (unsigned int n = 0u; n < borderSizeLeft; ++n)
541  {
542  targetPixel[n] = *(sourcePixel + borderSizeLeft - n - 1u);
543  }
544 
545  targetPixel += borderSizeLeft;
546 
547  // middle
548  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
549 
550  targetPixel += sourceWidth;
551  sourcePixel += sourceWidth;
552 
553  // right
554  for (unsigned int n = 0u; n < borderSizeRight; ++n)
555  {
556  targetPixel[n] = *(sourcePixel - n - 1u);
557  }
558  }
559 
560  // middle rows
561 
562  for (unsigned int y = 0u; y < sourceHeight; ++y)
563  {
564  const PixelType* sourcePixel = (const PixelType*)(source + y * sourceStrideElements);
565  PixelType* targetPixel = (PixelType*)(target + (borderSizeTop + y) * targetStrideElements);
566 
567  // left
568  for (unsigned int n = 0u; n < borderSizeLeft; ++n)
569  {
570  targetPixel[n] = *(sourcePixel + borderSizeLeft - n - 1u);
571  }
572 
573  targetPixel += borderSizeLeft;
574 
575  // middle
576  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
577 
578  targetPixel += sourceWidth;
579  sourcePixel += sourceWidth;
580 
581  // right
582  for (unsigned int n = 0u; n < borderSizeRight; ++n)
583  {
584  targetPixel[n] = *(sourcePixel - n - 1u);
585  }
586  }
587 
588  for (unsigned int y = 0u; y < borderSizeBottom; ++y)
589  {
590  const PixelType* sourcePixel = (const PixelType*)(source + (sourceHeight - y - 1u) * sourceStrideElements);
591  PixelType* targetPixel = (PixelType*)(target + (borderSizeTop + sourceHeight + y) * targetStrideElements);
592 
593  // left
594  for (unsigned int n = 0u; n < borderSizeLeft; ++n)
595  {
596  targetPixel[n] = *(sourcePixel + borderSizeLeft - n - 1u);
597  }
598 
599  targetPixel += borderSizeLeft;
600 
601  // middle
602  memcpy(targetPixel, sourcePixel, sourceWidth * sizeof(PixelType));
603 
604  targetPixel += sourceWidth;
605  sourcePixel += sourceWidth;
606 
607  // right
608  for (unsigned int n = 0u; n < borderSizeRight; ++n)
609  {
610  targetPixel[n] = *(sourcePixel - n - 1u);
611  }
612  }
613 }
614 
615 template <bool tTransparentIs0xFF>
616 bool FrameEnlarger::Comfort::addTransparentBorder(const Frame& source, Frame& target, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder)
617 {
618  ocean_assert(source);
619 
620  if (leftBorder == 0u && topBorder == 0u && rightBorder == 0u && bottomBorder == 0u)
621  {
622  target = source;
623  return true;
624  }
625 
626  if (source.numberPlanes() == 1u)
627  {
629 
630  const bool sourceHasAlpha = FrameType::formatHasAlphaChannel(source.pixelFormat());
631 
632  if (sourceHasAlpha)
633  {
634  targetPixelFormat = source.pixelFormat();
635  }
637  {
638  targetPixelFormat = target.pixelFormat();
639  }
640  else
641  {
642  targetPixelFormat = FrameType::formatAddAlphaChannel(source.pixelFormat());
643  }
644 
645  if (!target.set(FrameType(source.width() + leftBorder + rightBorder, source.height() + topBorder + bottomBorder, targetPixelFormat, source.pixelOrigin()), false /*forceOwner*/, true /*forceWritable*/))
646  {
647  ocean_assert(false && "This should never happen!");
648  return false;
649  }
650 
651  ocean_assert(target && FrameType::formatHasAlphaChannel(target.pixelFormat()));
652 
653  if (!target)
654  {
655  return false;
656  }
657 
658  bool alphaAtBack = false;
659  const bool tmpResult = FrameType::formatHasAlphaChannel(target.pixelFormat(), &alphaAtBack);
660  ocean_assert_and_suppress_unused(tmpResult, tmpResult);
661 
662  switch (target.channels())
663  {
664  case 2u:
665  {
666  if (alphaAtBack)
667  {
668  if (sourceHasAlpha)
669  {
670  addTransparentBorder8BitPerChannel<2u, false, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
671  }
672  else
673  {
674  addTransparentBorder8BitPerChannel<2u, false, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
675  }
676  }
677  else
678  {
679  if (sourceHasAlpha)
680  {
681  addTransparentBorder8BitPerChannel<2u, true, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
682  }
683  else
684  {
685  addTransparentBorder8BitPerChannel<2u, true, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
686  }
687  }
688 
689  return true;
690  }
691 
692  case 3u:
693  {
694  if (alphaAtBack)
695  {
696  if (sourceHasAlpha)
697  {
698  addTransparentBorder8BitPerChannel<3u, false, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
699  }
700  else
701  {
702  addTransparentBorder8BitPerChannel<3u, false, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
703  }
704  }
705  else
706  {
707  if (sourceHasAlpha)
708  {
709  addTransparentBorder8BitPerChannel<3u, true, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
710  }
711  else
712  {
713  addTransparentBorder8BitPerChannel<3u, true, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
714  }
715  }
716 
717  return true;
718  }
719 
720  case 4u:
721  {
722  if (alphaAtBack)
723  {
724  if (sourceHasAlpha)
725  {
726  addTransparentBorder8BitPerChannel<4u, false, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
727  }
728  else
729  {
730  addTransparentBorder8BitPerChannel<4u, false, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
731  }
732  }
733  else
734  {
735  if (sourceHasAlpha)
736  {
737  addTransparentBorder8BitPerChannel<4u, true, true, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
738  }
739  else
740  {
741  addTransparentBorder8BitPerChannel<4u, true, false, tTransparentIs0xFF>(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), leftBorder, topBorder, rightBorder, bottomBorder, source.paddingElements(), target.paddingElements());
742  }
743  }
744 
745  return true;
746  }
747 
748  default:
749  ocean_assert(false && "Missing implementation");
750  break;
751  }
752  }
753 
754  return false;
755 }
756 
757 template <bool tTransparentIs0xFF>
758 bool FrameEnlarger::Comfort::addTransparentBorder(Frame& frame, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder)
759 {
760  ocean_assert(frame.isValid());
761 
762  Frame tmpFrame;
763  if (!addTransparentBorder<tTransparentIs0xFF>(frame, tmpFrame, leftBorder, topBorder, rightBorder, bottomBorder))
764  {
765  return false;
766  }
767 
768  tmpFrame.setTimestamp(frame.timestamp());
769  tmpFrame.setRelativeTimestamp(frame.relativeTimestamp());
770 
771  frame = std::move(tmpFrame);
772  return true;
773 }
774 
775 template <unsigned int tChannelsWithAlpha, bool tAlphaAtFront, bool tSourceHasAlpha, bool tTransparentIs0xFF>
776 void FrameEnlarger::addTransparentBorder8BitPerChannel(const unsigned char* source, unsigned char* target, const unsigned int width, const unsigned int height, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
777 {
778  ocean_assert(source && target);
779 
780  typedef typename DataType<uint8_t, tChannelsWithAlpha - 1u>::Type TypeWithoutAlpha;
781 
782  if (topBorder != 0u)
783  {
784  // first row, left block: use the color values of the top left pixel of the source frame
785  for (unsigned int x = 0u; x < leftBorder; ++x)
786  {
787  *(TypeWithoutAlpha*)(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
788  *(TypeWithoutAlpha*)(source + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
789 
790  *(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
791  }
792 
793  // first row, center block: use the color values of the top row of the source frame
794  for (unsigned int x = 0u; x < width; ++x)
795  {
796  *(TypeWithoutAlpha*)(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
797  *(TypeWithoutAlpha*)(source + x * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
798 
799  *(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
800  }
801 
802  // first row, right block: use the color values of the top right pixel of the source frame
803  for (unsigned int x = 0u; x < rightBorder; ++x)
804  {
805  *(TypeWithoutAlpha*)(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
806  *(TypeWithoutAlpha*)(source + (width - 1u) * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
807 
808  *(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
809  }
810 
811  // the remaining rows of the top border are copies of the first row
812  for (unsigned int y = 1u; y < topBorder; ++y)
813  {
814  memcpy(target + y * (width + leftBorder + rightBorder) * tChannelsWithAlpha + targetPaddingElements, target, (width + leftBorder + rightBorder) * tChannelsWithAlpha);
815  }
816 
817  // next row
818  target += topBorder * (tChannelsWithAlpha * (width + leftBorder + rightBorder) + targetPaddingElements);
819  }
820 
821 
822  for (unsigned int y = 0u; y < height; ++y)
823  {
824  // left border
825  for (unsigned int x = 0u; x < leftBorder; ++x)
826  {
827  *(TypeWithoutAlpha*)(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
828  *(TypeWithoutAlpha*)(source + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
829 
830  *(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
831  }
832 
833  // center block
834  if constexpr (tSourceHasAlpha)
835  {
836  memcpy(target + leftBorder * tChannelsWithAlpha, source, width * tChannelsWithAlpha);
837  }
838  else
839  {
840  for (unsigned int x = 0u; x < width; ++x)
841  {
842  *(TypeWithoutAlpha*)(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
843  *(TypeWithoutAlpha*)(source + x * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
844 
845  *(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullOpaque8Bit<tTransparentIs0xFF>();
846  }
847  }
848 
849  // right border
850  for (unsigned int x = 0u; x < rightBorder; ++x)
851  {
852  *(TypeWithoutAlpha*)(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
853  *(TypeWithoutAlpha*)(source + (width - 1u) * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
854 
855  *(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
856  }
857 
858  // next row
859  source += FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() * width + sourcePaddingElements;
860  target += tChannelsWithAlpha * (width + leftBorder + rightBorder) + targetPaddingElements;
861  }
862 
863  if (bottomBorder != 0u)
864  {
865  // we need the last row of the source frame
866  source -= FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() * width + sourcePaddingElements;
867 
868  // first row of bottom border, left block: use the color values of the bottom left pixel of the source frame
869  for (unsigned int x = 0u; x < leftBorder; ++x)
870  {
871  *(TypeWithoutAlpha*)(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
872  *(TypeWithoutAlpha*)(source + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
873 
874  *(target + x * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
875  }
876 
877  // first row of the bottom border, center block: use the color values of the top row of the source frame
878  for (unsigned int x = 0u; x < width; ++x)
879  {
880  *(TypeWithoutAlpha*)(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
881  *(TypeWithoutAlpha*)(source + x * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
882 
883  *(target + (x + leftBorder) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
884  }
885 
886  // first row of the bottom border, right block: use the color values of the top right pixel of the source frame
887  for (unsigned int x = 0u; x < rightBorder; ++x)
888  {
889  *(TypeWithoutAlpha*)(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::data()) =
890  *(TypeWithoutAlpha*)(source + (width - 1u) * FrameBlender::FrameChannels<tSourceHasAlpha>::template channels<tChannelsWithAlpha>() + FrameBlender::SourceOffset<tAlphaAtFront>::template data<tSourceHasAlpha>());
891 
892  *(target + (x + leftBorder + width) * tChannelsWithAlpha + FrameBlender::SourceOffset<tAlphaAtFront>::template alpha<tChannelsWithAlpha>()) = FrameBlender::fullTransparent8Bit<tTransparentIs0xFF>();
893  }
894 
895  // the remaining rows of the bottom border are copies of the first row
896  for (unsigned int y = 1u; y < bottomBorder; ++y)
897  {
898  memcpy(target + y * (width + leftBorder + rightBorder) * tChannelsWithAlpha + targetPaddingElements, target, (width + leftBorder + rightBorder) * tChannelsWithAlpha);
899  }
900  }
901 }
902 
903 template <typename T, unsigned int tChannels>
904 void FrameEnlarger::multiplyByTwo(const T* source, T* target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
905 {
906  ocean_assert(targetWidth >= 2u && targetHeight >= 2u);
907 
908  if (worker)
909  {
910  worker->executeFunction(Worker::Function::createStatic(&FrameEnlarger::multiplyByTwoSubset<T, tChannels>, source, target, targetWidth, targetHeight, sourcePaddingElements, targetPaddingElements, 0u, 0u), 0u, targetHeight);
911  }
912  else
913  {
914  multiplyByTwoSubset<T, tChannels>(source, target, targetWidth, targetHeight, sourcePaddingElements, targetPaddingElements, 0u, targetHeight);
915  }
916 }
917 
918 template <typename T, unsigned int tChannels>
919 void FrameEnlarger::multiplyByTwoSubset(const T* source, T* target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstTargetRow, const unsigned int numberTargetRows)
920 {
921  ocean_assert(targetWidth >= 2u && targetHeight >= 2u);
922 
923  ocean_assert(source && target);
924  ocean_assert(firstTargetRow + numberTargetRows <= targetHeight);
925 
926  const unsigned int sourceWidth = targetWidth / 2u;
927  const unsigned int sourceHeight = targetHeight / 2u;
928  ocean_assert(sourceWidth >= 1u && sourceHeight >= 1u);
929 
930  const unsigned int sourceStrideElements = sourceWidth * tChannels + sourcePaddingElements;
931  const unsigned int targetStrideElements = targetWidth * tChannels + targetPaddingElements;
932 
933  typedef typename DataType<T, tChannels>::Type PixelType;
934 
935  // check whether no extra right column handling is necessary
936  if (targetWidth % 2u == 0u)
937  {
938  for (unsigned int targetRowIndex = firstTargetRow; targetRowIndex < (firstTargetRow + numberTargetRows); ++targetRowIndex)
939  {
940  const PixelType* sourcePixel = (const PixelType*)(source + min(targetRowIndex / 2u, sourceHeight - 1u) * sourceStrideElements);
941 
942  PixelType* targetPixel = (PixelType*)(target + targetRowIndex * targetStrideElements);
943 
944  const PixelType* const targetRowEnd = targetPixel + targetWidth;
945 
946  while (targetPixel != targetRowEnd)
947  {
948  ocean_assert(targetPixel < targetRowEnd);
949 
950  *targetPixel++ = *sourcePixel;
951 
952  ocean_assert(targetPixel < targetRowEnd);
953 
954  *targetPixel++ = *sourcePixel++;
955  }
956  }
957  }
958  else
959  {
960  ocean_assert((targetWidth - 1u) % 2u == 0u);
961 
962  for (unsigned int targetRowIndex = firstTargetRow; targetRowIndex < (firstTargetRow + numberTargetRows); ++targetRowIndex)
963  {
964  const PixelType* sourcePixel = (const PixelType*)(source + min(targetRowIndex / 2u, sourceHeight - 1u) * sourcePaddingElements);
965  --sourcePixel;
966 
967  PixelType* targetPixel = (PixelType*)(target + targetRowIndex * targetStrideElements);
968 
969  const PixelType* const targetRowEnd = targetPixel + targetWidth - 1u;
970 
971  while (targetPixel != targetRowEnd)
972  {
973  ocean_assert(targetPixel < targetRowEnd);
974 
975  *targetPixel++ = *++sourcePixel;
976 
977  ocean_assert(targetPixel < targetRowEnd);
978 
979  *targetPixel++ = *sourcePixel;
980  }
981 
982  // special handling for the last column
983  *targetPixel++ = *sourcePixel;
984  }
985  }
986 }
987 
988 }
989 
990 }
991 
992 #endif // META_OCEAN_CV_FRAME_ENLARGER_H
Helper class allowing to determine the number of channels of a frame.
Definition: FrameBlender.h:117
Helper class allowing to determine the offset that is necessary to access the alpha channel.
Definition: FrameBlender.h:60
static constexpr unsigned int data()
Returns the offset that is applied to access the first data channel.
Definition: FrameBlender.h:1160
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition: FrameEnlarger.h:38
static bool addBorder(const Frame &source, Frame &target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const void *color)
Adds a border to the given frame while all new pixels will receive a specified border color.
static bool addTransparentBorder(const Frame &source, Frame &target, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder)
Adds a transparent border to a given frame.
Definition: FrameEnlarger.h:616
static bool multiplyByTwo(const Frame &source, Frame &target, Worker *worker=nullptr)
Doubles the size of a given frame by a pixel repeating upsampling.
static bool addBorderMirrored(const Frame &source, Frame &target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom)
Adds a border to the given frame by mirroring the frame border (and border neighbor) pixels.
static bool addBorderNearestPixel(const Frame &source, Frame &target, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom)
Adds a border to the given frame.
This class implements functions to enlarge/up-sample frames.
Definition: FrameEnlarger.h:29
static void multiplyByTwoSubset(const T *source, T *target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstTargetRow, const unsigned int numberTargetRows)
Doubles a subset of a given frame by a pixel repeating upsampling.
Definition: FrameEnlarger.h:919
static void addTransparentBorder8BitPerChannel(const unsigned char *source, unsigned char *target, const unsigned int width, const unsigned int height, const unsigned int leftBorder, const unsigned int topBorder, const unsigned int rightBorder, const unsigned int bottomBorder, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
Adds a transparent border to a given frame.
Definition: FrameEnlarger.h:776
static void addBorderMirrored(const T *source, T *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
Adds a border to a given frame by mirroring the frame's content.
Definition: FrameEnlarger.h:515
static void addBorder(const T *source, T *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const T *color, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
Adds a border to a given frame while all new pixels will receive a specified border color/value.
Definition: FrameEnlarger.h:317
static void addBorderNearestPixel(const T *source, T *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int borderSizeLeft, const unsigned int borderSizeTop, const unsigned int borderSizeRight, const unsigned int borderSizeBottom, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
Adds a border to a given frame while the color of the border pixels are defined by the nearest pixels...
Definition: FrameEnlarger.h:410
static void multiplyByTwo(const T *source, T *target, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Doubles the size of a given frame by a pixel repeating upsampling.
Definition: FrameEnlarger.h:904
static Caller< void > createStatic(typename StaticFunctionPointerMaker< void, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass, NullClass >::Type function)
Creates a new caller container for a static function with no function parameter.
Definition: Caller.h:2876
Template class allowing to define an array of data types.
Definition: DataType.h:27
This class implements Ocean's image class.
Definition: Frame.h:1760
const T * constdata(const unsigned int planeIndex=0u) const
Returns a pointer to the read-only pixel data of a specific plane.
Definition: Frame.h:4136
void setRelativeTimestamp(const Timestamp &relative)
Sets the relative timestamp of this frame.
Definition: Frame.h:4121
T * data(const unsigned int planeIndex=0u)
Returns a pointer to the pixel data of a specific plane.
Definition: Frame.h:4127
bool isValid() const
Returns whether this frame is valid.
Definition: Frame.h:4416
void setTimestamp(const Timestamp &timestamp)
Sets the timestamp of this frame.
Definition: Frame.h:4116
bool set(const FrameType &frameType, const bool forceOwner, const bool forceWritable=false, const Indices32 &planePaddingElements=Indices32(), const Timestamp &timestamp=Timestamp(false), bool *reallocated=nullptr)
Sets a new frame type for this frame.
const Timestamp & timestamp() const
Returns the timestamp of this frame.
Definition: Frame.h:4106
const Timestamp & relativeTimestamp() const
Returns the relative timestamp of this frame.
Definition: Frame.h:4111
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:4010
Definition of a frame type composed by the frame dimension, pixel format and pixel origin.
Definition: Frame.h:30
PixelFormat
Definition of all pixel formats available in the Ocean framework.
Definition: Frame.h:183
@ FORMAT_UNDEFINED
Undefined pixel format.
Definition: Frame.h:187
unsigned int width() const
Returns the width of the frame format in pixel.
Definition: Frame.h:3111
PixelOrigin pixelOrigin() const
Returns the pixel origin of the frame.
Definition: Frame.h:3156
uint32_t numberPlanes() const
Returns the number of planes of the pixel format of this frame.
Definition: Frame.h:3151
static PixelFormat formatRemoveAlphaChannel(const PixelFormat pixelFormat)
Removes an alpha channel from a given pixel format.
static bool formatHasAlphaChannel(const PixelFormat pixelFormat, bool *isLastChannel=nullptr)
Returns whether a given pixel format holds an alpha channel.
PixelFormat pixelFormat() const
Returns the pixel format of the frame.
Definition: Frame.h:3121
unsigned int height() const
Returns the height of the frame in pixel.
Definition: Frame.h:3116
unsigned int channels() const
Returns the number of individual channels the frame has.
Definition: Frame.h:3141
static PixelFormat formatAddAlphaChannel(const PixelFormat pixelFormat, const bool lastChannel=true)
Adds an alpha channel to a given pixel format.
This class implements a worker able to distribute function calls over different threads.
Definition: Worker.h:33
bool executeFunction(const Function &function, const unsigned int first, const unsigned int size, const unsigned int firstIndex=(unsigned int)(-1), const unsigned int sizeIndex=(unsigned int)(-1), const unsigned int minimalIterations=1u, const unsigned int threadIndex=(unsigned int)(-1))
Executes a callback function separable by two function parameters.
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15
Default definition of a type with tBytes bytes.
Definition: DataType.h:32