Ocean
Loading...
Searching...
No Matches
FrameInterpolatorBicubic.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_INTERPOLATOR_BICUBIC_H
9#define META_OCEAN_CV_FRAME_INTERPOLATOR_BICUBIC_H
10
11#include "ocean/cv/CV.h"
12
13#include "ocean/base/Frame.h"
14#include "ocean/base/Worker.h"
15
16#include "ocean/math/Numeric.h"
17
18namespace Ocean
19{
20
21namespace CV
22{
23
24/**
25 * This class implements a bicubic frame interpolator.
26 * @ingroup cv
27 */
28class OCEAN_CV_EXPORT FrameInterpolatorBicubic
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 * Resizes a given frame by a bicubic interpolation.
43 * The pixel format of the frame must be zipped with DT_UNSIGNED_INTEGER_8 as data type (e.g., FORMAT_Y8, FORMAT_RGB24, FORMAT_RGBA32, ...).
44 * @param frame The frame to resize, must be valid
45 * @param width The width of the resized frame in pixel, with range [1, infinity)
46 * @param height The height of the resized frame in pixel, with range [1, infinity)
47 * @param worker Optional worker object used for load distribution
48 * @return True, if the frame could be resized
49 */
50 static inline bool resize(Frame& frame, const unsigned int width, const unsigned int height, Worker* worker = nullptr);
51
52 /**
53 * Resizes a given frame by a bicubic interpolation.
54 * The pixel format of the frame must be zipped with DT_UNSIGNED_INTEGER_8 as data type (e.g., FORMAT_Y8, FORMAT_RGB24, FORMAT_RGBA32, ...).
55 * @param source The source frame to resize, must be valid
56 * @param target Resulting target frame with identical frame pixel format and pixel origin as the source frame, must be valid
57 * @param worker Optional worker object used for load distribution
58 * @return True, if the frame could be resized
59 */
60 static inline bool resize(const Frame& source, Frame& target, Worker* worker = nullptr);
61 };
62
63 /**
64 * Resizes a given frame by a bicubic interpolation.
65 * @param source The source frame buffer to resize, must be valid
66 * @param target The target frame buffer, must be valid
67 * @param sourceWidth Width of the source frame in pixel, with range [1, infinity)
68 * @param sourceHeight Height of the source frame in pixel, with range [1, infinity)
69 * @param targetWidth Width of the target frame in pixel, with range [1, infinity)
70 * @param targetHeight Height of the target frame in pixel, with range [1, infinity)
71 * @param format Pixel format of source and target frame
72 * @param sourcePaddingElements Number of padding elements used in the source frame, range: [0, infinity)
73 * @param targetPaddingElements Number of padding elements used in the target frame, range: [0, infinity)
74 * @param worker Optional worker object used for load distribution
75 * @return True, if the frame could be resized
76 */
77 static bool resize(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const FrameType::PixelFormat format, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
78
79 /**
80 * Resizes a given zipped frame by a bicubic interpolation.
81 * @param source The source frame buffer, must be valid
82 * @param target The target frame buffer, must be valid
83 * @param sourceWidth Width of the source frame in pixel, with range [1, infinity)
84 * @param sourceHeight Height of the source frame in pixel, with range [1, infinity)
85 * @param targetWidth Width of the target frame in pixel, with range [1, infinity)
86 * @param targetHeight Height of the target frame in pixel, with range [1, infinity)
87 * @param sourcePaddingElements Number of padding elements used in the source frame, range: [0, infinity)
88 * @param targetPaddingElements Number of padding elements used in the target frame, range: [0, infinity)
89 * @param worker Optional worker object to distribute the computation
90 * @tparam tChannels Number of frame channels, with range [1, infinity)
91 */
92 template <unsigned int tChannels>
93 static void resize8BitPerChannel(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker = nullptr);
94
95 private:
96
97 /**
98 * Resizes a subset of a given zipped frame by a horizontal bicubic interpolation only.
99 * @param source The source frame buffer to resize, with size (sourceWidth x sourceHeight)
100 * @param target Intermediate target frame buffer, with size (targetWidth x sourceHeight)
101 * @param sourceWidth Width of the source frame in pixel, with range [1, infinity)
102 * @param targetWidth Width of the target frame in pixel, with range [1, infinity)
103 * @param height The height of the source and target frame in pixel, with range [1, infinity)
104 * @param sourcePaddingElements Number of padding elements used in the source frame, range: [0, infinity)
105 * @param targetPaddingElements Number of padding elements used in the target frame, range: [0, infinity)
106 * @param firstRow First (including) row to convert, with range [0, height)
107 * @param numberRows Number of rows to convert, with range [1, height - firstRow]
108 * @tparam tChannels Number of frame channels, with range [1, infinity)
109 */
110 template <unsigned int tChannels>
111 static void resizeHorizontal8BitPerChannelSubset(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int targetWidth, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows);
112
113 /**
114 * Resizes a subset of a given zipped frame by a vertical bicubic interpolation only.
115 * @param source Resized and horizontal filtered source frame buffer, with size (targetWidth x sourceHeight)
116 * @param target The target frame buffer, with size (targetWidth x targetHeight)
117 * @param sourceHeight Height of the source frame in pixel, with range [1, infinity)
118 * @param targetHeight Height of the target frame in pixel, with range [1, infinity)
119 * @param width The width of the source and target frame in pixel, with range [1, infinity)
120 * @param sourcePaddingElements Number of padding elements used in the source frame, range: [0, infinity)
121 * @param targetPaddingElements Number of padding elements used in the target frame, range: [0, infinity)
122 * @param firstColumn First (including) column to convert, with range [0, width)
123 * @param numberColumns Number of columns to convert, with range [1, width - firstColumn]
124 * @tparam tChannels Number of frame channels, with range [1, infinity)
125 */
126 template <unsigned int tChannels>
127 static void resizeVertical8BitPerChannelSubset(const uint8_t* source, uint8_t* target, const unsigned int sourceHeight, const unsigned int targetHeight, const unsigned int width, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns);
128};
129
130inline bool FrameInterpolatorBicubic::Comfort::resize(Frame& frame, const unsigned int width, const unsigned int height, Worker* worker)
131{
132 ocean_assert(frame.isValid());
133 ocean_assert(width >= 1u && height >= 1u);
134
136 {
137 // we need a generic pixel format with unsigned char data type e.g., FORMAT_Y8, FORAT_RGB24, etc.
138 ocean_assert(false && "Invalid frame type!");
139 return false;
140 }
141
142 if (width == frame.width() && height == frame.height())
143 {
144 return true;
145 }
146
147 Frame target(FrameType(frame, width, height));
148
149 if (!Comfort::resize(frame, target, worker))
150 {
151 return false;
152 }
153
154 frame = std::move(target);
155 return true;
156}
157
158inline bool FrameInterpolatorBicubic::Comfort::resize(const Frame& source, Frame& target, Worker* worker)
159{
160 ocean_assert(source && target);
161
162 if (source.dataType() != FrameType::DT_UNSIGNED_INTEGER_8 || source.pixelFormat() != target.pixelFormat() || source.pixelOrigin() != target.pixelOrigin())
163 {
164 ocean_assert(false && "Invalid frame type!");
165 return false;
166 }
167
168 return FrameInterpolatorBicubic::resize(source.constdata<uint8_t>(), target.data<uint8_t>(), source.width(), source.height(), target.width(), target.height(), source.pixelFormat(), source.paddingElements(), target.paddingElements(), worker);
169}
170
171template <unsigned int tChannels>
172void FrameInterpolatorBicubic::resize8BitPerChannel(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker* worker)
173{
174 ocean_assert(source != nullptr && target != nullptr);
175 ocean_assert(sourceWidth != 0u && sourceHeight != 0u);
176 ocean_assert(targetWidth != 0u && targetHeight != 0u);
177
178 if (sourceWidth == targetWidth)
179 {
180 if (worker)
181 {
182 worker->executeFunction(Worker::Function::createStatic(&FrameInterpolatorBicubic::resizeVertical8BitPerChannelSubset<tChannels>, source, target, sourceHeight, targetHeight, targetWidth, sourcePaddingElements, targetPaddingElements, 0u, 0u), 0u, targetWidth);
183 }
184 else
185 {
186 resizeVertical8BitPerChannelSubset<tChannels>(source, target, sourceHeight, targetHeight, targetWidth, sourcePaddingElements, targetPaddingElements, 0u, targetWidth);
187 }
188 }
189 else if (sourceHeight == targetHeight)
190 {
191 if (worker)
192 {
193 worker->executeFunction(Worker::Function::createStatic(&FrameInterpolatorBicubic::resizeHorizontal8BitPerChannelSubset<tChannels>, source, target, sourceWidth, targetWidth, targetHeight, sourcePaddingElements, targetPaddingElements, 0u, 0u), 0u, sourceHeight);
194 }
195 else
196 {
197 resizeHorizontal8BitPerChannelSubset<tChannels>(source, target, sourceWidth, targetWidth, targetHeight, sourcePaddingElements, targetPaddingElements, 0u, targetHeight);
198 }
199 }
200 else
201 {
202 Frame intermediateFrame(FrameType(targetWidth, sourceHeight, FrameType::genericPixelFormat<FrameType::DT_UNSIGNED_INTEGER_8, tChannels>(), FrameType::ORIGIN_UPPER_LEFT));
203
204 if (worker)
205 {
206 worker->executeFunction(Worker::Function::createStatic(&FrameInterpolatorBicubic::resizeHorizontal8BitPerChannelSubset<tChannels>, source, intermediateFrame.data<uint8_t>(), sourceWidth, intermediateFrame.width(), sourceHeight, sourcePaddingElements, intermediateFrame.paddingElements(), 0u, 0u), 0u, sourceHeight);
207 worker->executeFunction(Worker::Function::createStatic(&FrameInterpolatorBicubic::resizeVertical8BitPerChannelSubset<tChannels>, intermediateFrame.constdata<uint8_t>(), target, intermediateFrame.height(), targetHeight, targetWidth, intermediateFrame.paddingElements(), targetPaddingElements, 0u, 0u), 0u, targetWidth);
208 }
209 else
210 {
211 resizeHorizontal8BitPerChannelSubset<tChannels>(source, intermediateFrame.data<uint8_t>(), sourceWidth, intermediateFrame.width(), sourceHeight, sourcePaddingElements, intermediateFrame.paddingElements(), 0u, sourceHeight);
212 resizeVertical8BitPerChannelSubset<tChannels>(intermediateFrame.constdata<uint8_t>(), target, intermediateFrame.height(), targetHeight, targetWidth, intermediateFrame.paddingElements(), targetPaddingElements, 0u, targetWidth);
213 }
214 }
215}
216
217template <unsigned int tChannels>
218void FrameInterpolatorBicubic::resizeHorizontal8BitPerChannelSubset(const uint8_t* source, uint8_t* target, const unsigned int sourceWidth, const unsigned int targetWidth, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
219{
220 static_assert(tChannels != 0u, "Invalid channel number!");
221
222 ocean_assert(source != nullptr && target != nullptr);
223 ocean_assert(sourceWidth != 0u && targetWidth != 0u);
224 ocean_assert(height != 0u);
225
226 ocean_assert_and_suppress_unused(firstRow + numberRows <= height, height);
227
228 const float targetToSourceX = float(sourceWidth) / float(targetWidth);
229
230 const unsigned int sourceStrideElements = sourceWidth * tChannels + sourcePaddingElements;
231 const unsigned int targetStrideElements = targetWidth * tChannels + targetPaddingElements;
232
233 const uint8_t* sourceRow = source + firstRow * sourceStrideElements;
234 uint8_t* targetElement = target + firstRow * targetStrideElements;
235
236 for (unsigned int y = firstRow; y < firstRow + numberRows; ++y)
237 {
238 for (unsigned int tx = 0; tx < targetWidth; ++tx)
239 {
240 const float sx = targetToSourceX * float(tx);
241
242 ocean_assert(sx >= 0.0f && sx <= float(sourceWidth));
243
244 const unsigned int sx1 = (unsigned int)(min(NumericF::floor(sx), float(sourceWidth - 1)));
245 ocean_assert(int(sx1) >= 0);
246
247 const unsigned int sx0 = (unsigned int)(max(0, int(sx1) - 1));
248 const unsigned int sx2 = min(sx1 + 1u, sourceWidth - 1u);
249 const unsigned int sx3 = min(sx2 + 1u, sourceWidth - 1u);
250
251 ocean_assert(sx >= float(sx1));
252 ocean_assert(sx1 >= sx0 && sx2 >= sx1 && sx3 >= sx2);
253
254 const float d = sx - float(sx1);
255
256 for (unsigned int n = 0u; n < tChannels; ++n)
257 {
258 const float color0 = sourceRow[sx0 * tChannels + n];
259 const float color1 = sourceRow[sx1 * tChannels + n];
260 const float color2 = sourceRow[sx2 * tChannels + n];
261 const float color3 = sourceRow[sx3 * tChannels + n];
262
263 float color = 0.166666666667f * color0 + 0.66666666667f * color1 + 0.166666666667f * color2;
264
266 {
267 color += (-0.166666666667f * color0 + 0.5f * color1 - 0.5f * color2 + 0.166666666667f * color3) * d * d * d
268 + (0.5f * color0 - 1.0f * color1 + 0.5f * color2) * d * d
269 + (-0.5f * color0 + 0.5f * color2) * d;
270 }
271
272 ocean_assert(NumericF::isInsideRange(0.0f, color, 256.0f));
273
274 *targetElement++ = uint8_t(color);
275 }
276 }
277
278 targetElement += targetPaddingElements;
279 sourceRow += sourceStrideElements;
280 }
281}
282
283template <unsigned int tChannels>
284void FrameInterpolatorBicubic::resizeVertical8BitPerChannelSubset(const uint8_t* source, uint8_t* target, const unsigned int sourceHeight, const unsigned int targetHeight, const unsigned int width, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns)
285{
286 static_assert(tChannels != 0u, "Invalid channel number!");
287
288 ocean_assert(source != nullptr && target != nullptr);
289 ocean_assert(sourceHeight != 0u && targetHeight != 0u);
290 ocean_assert(width != 0u);
291
292 ocean_assert(firstColumn + numberColumns <= width);
293
294 const float targetToSourceY = float(sourceHeight) / float(targetHeight);
295
296 const unsigned int sourceStrideElements = width * tChannels + sourcePaddingElements;
297 const unsigned int targetStrideElements = width * tChannels + targetPaddingElements;
298
299 uint8_t* targetColor = target + firstColumn * tChannels - 1u;
300
301 for (unsigned int ty = 0u; ty < targetHeight; ++ty)
302 {
303 const float sy = targetToSourceY * float(ty);
304
305 ocean_assert(sy >= 0.0f && sy <= float(sourceHeight));
306
307 const unsigned int sy1 = (unsigned int)(min(NumericF::floor(sy), float(sourceHeight - 1u)));
308 ocean_assert(int(sy1) >= 0);
309
310 const unsigned int sy0 = (unsigned int)(max(0, int(sy1) - 1));
311 const unsigned int sy2 = min(sy1 + 1u, sourceHeight - 1u);
312 const unsigned int sy3 = min(sy2 + 1u, sourceHeight - 1u);
313
314 ocean_assert(sy >= float(sy1));
315 ocean_assert(sy1 >= sy0 && sy2 >= sy1 && sy3 >= sy2);
316
317 const float d = sy - float(sy1);
318
319 const uint8_t* color0 = source + sy0 * sourceStrideElements + tChannels * firstColumn;
320 const uint8_t* color1 = source + sy1 * sourceStrideElements + tChannels * firstColumn;
321 const uint8_t* color2 = source + sy2 * sourceStrideElements + tChannels * firstColumn;
322 const uint8_t* color3 = source + sy3 * sourceStrideElements + tChannels * firstColumn;
323
324 for (unsigned int tx = firstColumn; tx < firstColumn + numberColumns; ++tx)
325 {
326 for (unsigned int n = 0u; n < tChannels; ++n)
327 {
328 float color = 0.166666666667f * float(color0[n]) + 0.66666666667f * float(color1[n]) + 0.166666666667f * float(color2[n]);
329
331 {
332 color += (-0.166666666667f * float(color0[n]) + 0.5f * float(color1[n]) - 0.5f * float(color2[n]) + 0.166666666667f * float(color3[n])) * d * d * d
333 + (0.5f * float(color0[n]) - 1.0f * float(color1[n]) + 0.5f * float(color2[n])) * d * d
334 + (-0.5f * float(color0[n]) + 0.5f * float(color2[n])) * d;
335 }
336
337 ocean_assert(color >= 0.0f && color < 256.0f);
338 *++targetColor = uint8_t(color);
339 }
340
341 color0 += tChannels;
342 color1 += tChannels;
343 color2 += tChannels;
344 color3 += tChannels;
345 }
346
347 targetColor += targetStrideElements - numberColumns * tChannels;
348 }
349}
350
351}
352
353}
354
355#endif // META_OCEAN_CV_FRAME_INTERPOLATOR_BICUBIC_H
The following comfort class provides comfortable functions simplifying prototyping applications but a...
Definition FrameInterpolatorBicubic.h:38
static bool resize(Frame &frame, const unsigned int width, const unsigned int height, Worker *worker=nullptr)
Resizes a given frame by a bicubic interpolation.
Definition FrameInterpolatorBicubic.h:130
This class implements a bicubic frame interpolator.
Definition FrameInterpolatorBicubic.h:29
static void resizeVertical8BitPerChannelSubset(const uint8_t *source, uint8_t *target, const unsigned int sourceHeight, const unsigned int targetHeight, const unsigned int width, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstColumn, const unsigned int numberColumns)
Resizes a subset of a given zipped frame by a vertical bicubic interpolation only.
Definition FrameInterpolatorBicubic.h:284
static bool resize(const uint8_t *source, uint8_t *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const FrameType::PixelFormat format, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Resizes a given frame by a bicubic interpolation.
static void resize8BitPerChannel(const uint8_t *source, uint8_t *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, Worker *worker=nullptr)
Resizes a given zipped frame by a bicubic interpolation.
Definition FrameInterpolatorBicubic.h:172
static void resizeHorizontal8BitPerChannelSubset(const uint8_t *source, uint8_t *target, const unsigned int sourceWidth, const unsigned int targetWidth, const unsigned int height, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements, const unsigned int firstRow, const unsigned int numberRows)
Resizes a subset of a given zipped frame by a horizontal bicubic interpolation only.
Definition FrameInterpolatorBicubic.h:218
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
This class implements Ocean's image class.
Definition Frame.h:1808
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:4248
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
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
unsigned int width() const
Returns the width of the frame format in pixel.
Definition Frame.h:3170
PixelOrigin pixelOrigin() const
Returns the pixel origin of the frame.
Definition Frame.h:3215
PixelFormat pixelFormat() const
Returns the pixel format of the frame.
Definition Frame.h:3180
@ ORIGIN_UPPER_LEFT
The first pixel lies in the upper left corner, the last pixel in the lower right corner.
Definition Frame.h:1050
@ 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
DataType dataType() const
Returns the data type of the pixel format of this frame.
Definition Frame.h:3190
static constexpr bool isInsideRange(const T lower, const T value, const T upper, const T epsilon=NumericT< T >::eps())
Returns whether a value lies between a given range up to a provided epsilon border.
Definition Numeric.h:2872
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 bool isNotEqualEps(const T value)
Returns whether a value is not smaller than or equal to a small epsilon.
Definition Numeric.h:2237
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