Ocean
Loading...
Searching...
No Matches
TestFrameInterpolatorNearestPixel.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_TEST_TESTCV_TEST_FRAME_INTERPOLATOR_NEAREST_PIXEL_H
9#define META_OCEAN_TEST_TESTCV_TEST_FRAME_INTERPOLATOR_NEAREST_PIXEL_H
10
12
13#include "ocean/base/Worker.h"
14
16
17namespace Ocean
18{
19
20namespace Test
21{
22
23namespace TestCV
24{
25
26/**
27 * This class implements a nearest pixel frame interpolator test.
28 * @ingroup testcv
29 */
30class OCEAN_TEST_CV_EXPORT TestFrameInterpolatorNearestPixel
31{
32 public:
33
34 /**
35 * Tests all nearest pixel interpolation filter functions.
36 * @param width The width of the test frame in pixel, with range [1, infinity)
37 * @param height The height of the test frame in pixel, with range [1, infinity)
38 * @param testDuration Number of seconds for each test, with range (0, infinity)
39 * @param worker The worker object to distribute the CPU load
40 * @return True, if succeeded
41 */
42 static bool test(const unsigned int width, const unsigned int height, const double testDuration, Worker& worker);
43
44 /**
45 * Test for affine image transformations.
46 * @param testDuration Number of seconds for each test, with range (0, infinity)
47 * @param worker The worker object to distribute the CPU load
48 * @return True, if succeeded
49 */
50 static bool testAffine(const double testDuration, Worker& worker);
51
52 /**
53 * Test for affine image transformations for varying frame dimensions and channel numbers.
54 * @param width The width of the frame in pixel, if this value is 0 (or `height`) it will be randomly selected in the range [1, 1920], range: [0, infinity)
55 * @param height The height of the frame in pixel, if the value is 0 (or `width`) it will be randomly selected in the range [1, 1080], range: [0, infinity)
56 * @param channels The number of frame channels, with range [1, infinity)
57 * @param testDuration Number of seconds for each test, with range (0, infinity)
58 * @param worker The worker object to distribute the CPU load
59 * @return True, if succeeded
60 */
61 static bool testAffine(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker& worker);
62
63 /**
64 * Tests the homography transformation function.
65 * @param testDuration Number of seconds for each test, with range (0, infinity)
66 * @param worker The worker object to distribute the CPU load
67 * @return True, if succeeded
68 * @tparam T The data type of each pixel element, e.g., 'uint8_t', 'float'
69 */
70 template <typename T>
71 static bool testHomography(const double testDuration, Worker& worker);
72
73 /**
74 * Tests the homography transformation function for a given frame dimension and channel number.
75 * @param width The width of the frame in pixel, with range [1, infinity)
76 * @param height The height of the frame in pixel, with range [1, infinity)
77 * @param channels The number of frame channels, with range [1, infinity)
78 * @param testDuration Number of seconds for each test, with range (0, infinity)
79 * @param worker The worker object to distribute the CPU load
80 * @return True, if succeeded
81 * @tparam T The data type of each pixel element, e.g., 'uint8_t', 'float'
82 */
83 template <typename T>
84 static bool testHomography(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker& worker);
85
86 /**
87 * Tests the homography transformation function defining a binary mask for known and unknown image content.
88 * @param testDuration Number of seconds for each test, with range (0, infinity)
89 * @param worker The worker object to distribute the CPU load
90 * @return True, if succeeded
91 */
92 static bool testHomographyMask(const double testDuration, Worker& worker);
93
94 /**
95 * Tests the homography transformation function (with binary mask defining known and unknown image content) for a given frame dimension and channel number.
96 * @param width The width of the frame in pixel, with range [1, infinity)
97 * @param height The height of the frame in pixel, with range [1, infinity)
98 * @param channels The number of frame channels, with range [1, 4]
99 * @param testDuration Number of seconds for each test, with range (0, infinity)
100 * @param worker The worker object to distribute the CPU load
101 * @return True, if succeeded
102 */
103 static bool testHomographyMask(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker& worker);
104
105 /**
106 * Tests the resize function.
107 * @param testDuration Number of seconds for each test, with range (0, infinity)
108 * @param worker The worker object to distribute the CPU load
109 * @return True, if succeeded
110 */
111 static bool testResize(const double testDuration, Worker& worker);
112
113 /**
114 * Tests the resize function for a given frame dimension and channel number.
115 * @param sourceWidth Width of the source frame in pixel, with range [1, infinity)
116 * @param sourceHeight Height of the source frame in pixel, with range [1, infinity)
117 * @param targetWidth Width of the target frame in pixel, with range [1, infinity)
118 * @param targetHeight Height of the target frame in pixel, with range [1, infinity)
119 * @param testDuration Number of seconds for each test, with range (0, infinity)
120 * @param worker The worker object to distribute the CPU load
121 * @return True, if succeeded
122 * @tparam T The data type of each elements, e.g., 'unsigned char', 'float'
123 * @tparam tChannels The number of channels the frames have, with range [1, infinity)
124 */
125 template <typename T, unsigned int tChannels>
126 static bool testResize(const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const double testDuration, Worker& worker);
127
128 /**
129 * Tests the special case resize function for image resolutions from 400x400 to 224x224.
130 * @param testDuration Number of seconds for each test, with range (0, infinity)
131 * @return True, if succeeded
132 */
133 static bool testSpecialCasesResize400x400To224x224_8BitPerChannel(const double testDuration);
134
135 /**
136 * Tests the frame transformation function applying a lookup table.
137 * @param width The width of the test frame in pixel, with range [1, infinity)
138 * @param height The height of the test frame in pixel, with range [1, infinity)
139 * @param testDuration Number of seconds for each test, with range (0, infinity)
140 * @param worker The worker object to distribute the CPU load
141 * @return True, if succeeded
142 * @tparam tOffset True, to use an offset transformation; False, to use an absolute transformation
143 */
144 template <bool tOffset>
145 static bool testTransform(const unsigned int width, const unsigned int height, const double testDuration, Worker& worker);
146
147 /**
148 * Tests the frame mask transformation function applying a lookup table.
149 * @param width The width of the test frame in pixel, with range [1, infinity)
150 * @param height The height of the test frame in pixel, with range [1, infinity)
151 * @param testDuration Number of seconds for each test, with range (0, infinity)
152 * @param worker The worker object to distribute the CPU load
153 * @return True, if succeeded
154 * @tparam tOffset True, to use an offset transformation; False, to use an absolute transformation
155 */
156 template <bool tOffset>
157 static bool testTransformMask(const unsigned int width, const unsigned int height, const double testDuration, Worker& worker);
158
159 /**
160 * Tests the 90 degree rotate function.
161 * @param testDuration Number of seconds for each test, with range (0, infinity)
162 * @param worker The worker object to distribute the CPU load
163 * @return True, if succeeded
164 */
165 static bool testRotate90(const double testDuration, Worker& worker);
166
167 /**
168 * Tests the 90 degree rotate function for a specific frame size and number of channels
169 * @param width The width of the test frame in pixels, range: [1, infinity)
170 * @param height The height of the test frame in pixels, range: [1, infinity)
171 * @param testDuration Number of seconds for each test, with range (0, infinity)
172 * @param worker The worker object to distribute the CPU load
173 * @return True, if succeeded
174 * @tparam TElementType The data type of each elements, e.g., 'unsigned char', 'float'
175 * @tparam tChannels The number of channels the frames have, with range [1, infinity)
176 */
177 template <typename TElementType, unsigned int tChannels>
178 static bool testRotate90(const unsigned int width, const unsigned int height, const double testDuration, Worker& worker);
179
180 /**
181 * Validation function for the nearest-neighbor interpolation of 2D homogeneous image transformations (+ constant background color for unknown image content).
182 * @param frame Pointer to the source frame, must be valid
183 * @param frameWidth Width of the source frame, range: [0, infinity)
184 * @param frameHeight Height of the source frame, range: [0, infinity)
185 * @param framePaddingElements The number of padding elements at the end of each source frame row, in elements, with range [0, infinity)
186 * @param interpolatedFrame Pointer to the target frame, must be valid
187 * @param interpolatedFrameWidth Width of the target frame, range: [0, infinity)
188 * @param interpolatedFrameHeight Height of the target frame, range: [0, infinity)
189 * @param interpolatedFramePaddingElements The number of padding elements at the end of each target frame row, in elements, with range [0, infinity)
190 * @param channels Number of channels in both, the source and the target frame, range: [1, infinity) * @param homography The 2D homogeneous image transformation that has been used to interpolate/warp the frame, transforming points defined in the interpolatedFrame to the source frame, i.e. pointFrame = transformation * pointInterpolatedFrame, must not be singular
191 * @param backgroundColor The background color for all pixels for which no valid source pixel exists, one for each frame channel, must be valid
192 * @param interpolatedFrameOrigin The origin of the interpolated frame defining the global position of the interpolated frame's pixel coordinate (0, 0), with range (-infinity, infinity)x(-infinity, infinity)
193 * @param maximalAbsError If specified, will hold the maximum absolute error measured
194 * @param averageAbsError If specified, will hold the average of all absolute pixel errors
195 * @param groundtruth If specified, the result of the validation (which is used as ground truth) will be stored at the specified pointer location, note: memory must be allocated (same size and frame type as the input frames)
196 * @tparam T The data type of each pixel element
197 */
198 template <typename T>
199 static void validateHomography(const T* frame, const unsigned int frameWidth, const unsigned int frameHeight, const unsigned int framePaddingElements, const T* interpolatedFrame, const unsigned int interpolatedFrameWidth, const unsigned int interpolatedFrameHeight, const unsigned int interpolatedFramePaddingElements, const unsigned int channels, const SquareMatrix3& homography, const T* backgroundColor, const CV::PixelPositionI& interpolatedFrameOrigin, double* maximalAbsError = nullptr, double* averageAbsError = nullptr, T* groundtruth = nullptr);
200
201 /**
202 * Validates a resized frame.
203 * @param source The source frame which has been resized, must be valid
204 * @param target The target frame to validate, must be valid
205 * @param sourceWidth Width of the source frame in pixel, with range [1, infinity)
206 * @param sourceHeight Height of the source frame in pixel, with range [1, infinity)
207 * @param targetWidth Width of the target frame in pixel, with range [1, infinity)
208 * @param targetHeight Height of the target frame in pixel, with range [1, infinity)
209 * @param channels The number of frame channels, with range [1, infinity)
210 * @param sourcePaddingElements The optional number of padding elements at the end of each row of the source frame, in elements, with range [0, infinity)
211 * @param targetPaddingElements The optional number of padding elements at the end of each row of the target frame, in elements, with range [0, infinity)
212 * @return True, if succeeded
213 * @tparam T The data type of each element e.g., 'unsigned char', 'float'
214 */
215 template <typename T>
216 static bool validateResizedFrame(const T* source, const T* target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int channels, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements);
217
218 /**
219 * Validates the frame transformation function applying a lookup table.
220 * @param frame The frame which will be transformed, must be valid
221 * @param target The target which has received the transformed frame, must be valid
222 * @param lookupTable The lookup table which has been used to transform the image
223 * @param borderColor The border color which has been used, must be valid
224 * @return True, if succeeded
225 * @tparam tOffset True, to use an offset transformation; False, to use an absolute transformation
226 */
227 template <bool tOffset>
228 static bool validateTransformation(const Frame& frame, const Frame& target, const CV::FrameInterpolatorNearestPixel::LookupTable& lookupTable, const uint8_t* borderColor);
229
230 /**
231 * Validates the frame mask transformation function applying a lookup table.
232 * @param frame The frame which will be transformed, must be valid
233 * @param target The target which has received the transformed frame, must be valid
234 * @param targetMask The target mask which has received the mask of the transformed frame, must be valid
235 * @param lookupTable The lookup table which has been used to transform the image
236 * @param maskValue The pixel value of a mask pixel with corresponding source pixel, with range [0, 255]
237 * @return True, if succeeded
238 * @tparam tOffset True, to use an offset transformation; False, to use an absolute transformation
239 */
240 template <bool tOffset>
241 static bool validateTransformationMask(const Frame& frame, const Frame& target, const Frame& targetMask, const CV::FrameInterpolatorNearestPixel::LookupTable& lookupTable, const uint8_t maskValue);
242
243 /**
244 * Validates the 90 degree rotate function.
245 * @param frame The original frame, must be valid
246 * @param channels The number of data channels the frame has, with range [1, infinity)
247 * @param width The width of the original frame in pixel, with range [1, infinity)
248 * @param height The height of the original frame in pixel, with range [1, infinity)
249 * @param clockwise The clockwise rotated frame to be checked, must be valid
250 * @param counterClockwise The counter clockwise frame to be checked, must be valid
251 * @param framePaddingElements Optional number of padding elements at the end of each frame row, in elements, range: [0, infinity)
252 * @param clockwisePaddingElements Optional number of padding elements at the end of each clockwise row, in elements, range: [0, infinity)
253 * @param counterClockwisePaddingElements Optional number of padding elements at the end of each clockwise row, in elements, range: [0, infinity)
254 * @return True, if succeeded
255 * @tparam TElementType The data type of each channel data
256 */
257 template <typename TElementType>
258 static bool validateRotate90(const TElementType* frame, const unsigned int channels, const unsigned int width, const unsigned int height, const TElementType* clockwise, const TElementType* counterClockwise, const unsigned int framePaddingElements, const unsigned int clockwisePaddingElements, const unsigned int counterClockwisePaddingElements);
259
260 protected:
261
262 /**
263 * Validates the homography interpolation function (using a binary mask to define known and unknown image content).
264 * @param inputFrame The frame which will be interpolated based on the homography, must be valid
265 * @param outputFrame The interpolated/warped frame to be validated, width same pixel format and pixel origin as 'frame, must be valid
266 * @param outputMask The binary mask corresponding to the interpolated/warped frame specifying known and unknown image content, a mask value of 0xFF defined known image content, 0x00 defines unknown image content, with same pixel origin and frame resolution as 'outputFrame'
267 * @param input_H_output The homography transforming output to input points, must be valid
268 * @param outputFrameOrigin The origin of the interpolated frame defining the global position of the interpolated frame's pixel coordinate (0, 0), with range (-infinity, infinity)x(-infinity, infinity)
269 * @return True, if the interpolation is correct
270 */
271 static bool validateHomographyMask8BitPerChannel(const Frame& inputFrame, const Frame& outputFrame, const Frame& outputMask, const SquareMatrix3& input_H_output, const CV::PixelPositionI& outputFrameOrigin);
272};
273
274template <typename T>
275void TestFrameInterpolatorNearestPixel::validateHomography(const T* frame, const unsigned int frameWidth, const unsigned int frameHeight, const unsigned int framePaddingElements, const T* interpolatedFrame, const unsigned int interpolatedFrameWidth, const unsigned int interpolatedFrameHeight, const unsigned int interpolatedFramePaddingElements, const unsigned int channels, const SquareMatrix3& homography, const T* backgroundColor, const CV::PixelPositionI& interpolatedFrameOrigin, double* maximalAbsError, double* averageAbsError, T* groundtruth)
276{
277 ocean_assert(frame != nullptr && interpolatedFrame != nullptr);
278 ocean_assert(frameWidth != 0u && frameHeight != 0u);
279 ocean_assert(interpolatedFrameWidth != 0u && interpolatedFrameHeight != 0u);
280 ocean_assert(channels != 0u);
281 ocean_assert(!homography.isSingular());
282 ocean_assert(backgroundColor != nullptr);
283
284 double sumAbsError = 0.0;
285 double maxAbsError = 0.0;
286 unsigned long long measurements = 0ull;
287
288 for (unsigned int y = 0u; y < interpolatedFrameHeight; ++y)
289 {
290 for (unsigned int x = 0u; x < interpolatedFrameWidth; ++x)
291 {
292 const T* const interpolatedPixel = interpolatedFrame + (interpolatedFrameWidth * y + x) * channels + y * interpolatedFramePaddingElements;
293
294 const Vector2 outputPosition = Vector2(Scalar(x) + Scalar(interpolatedFrameOrigin.x()), Scalar(y) + Scalar(interpolatedFrameOrigin.y()));
295 const Vector2 inputPosition = homography * outputPosition;
296
297 const int inputXI = Numeric::round32(inputPosition.x());
298 const int inputYI = Numeric::round32(inputPosition.y());
299
300 // Ignore the border pixels because background and foreground can be mixed differently here
301 if (inputXI == -1 || inputXI == 0 || inputXI == (int)(frameWidth - 1u) || inputXI == (int)frameWidth || inputYI == -1 || inputYI == 0 || inputYI == (int)(frameHeight - 1u) || inputYI == (int)(frameHeight))
302 {
303 continue;
304 }
305
306 const unsigned int inputX = (unsigned int)inputXI;
307 const unsigned int inputY = (unsigned int)inputYI;
308
309 if (inputX < frameWidth && inputY < frameHeight)
310 {
311 const unsigned int nearestNeighborIndex = (inputY * frameWidth + inputX) * channels + inputY * framePaddingElements;
312
313 for (unsigned int n = 0u; n < channels; ++n)
314 {
315 if (groundtruth)
316 {
317 *groundtruth = frame[nearestNeighborIndex + n];
318 groundtruth++;
319 }
320
321 const double interpolatedPixelD = double(interpolatedPixel[n]);
322 const double framePixelD = double(frame[nearestNeighborIndex + n]);
323 const double absError = NumericD::abs(interpolatedPixelD - framePixelD);
324
325 sumAbsError += absError;
326
327 if (absError > maxAbsError)
328 {
329 maxAbsError = absError;
330 }
331
332 measurements++;
333 }
334 }
335 else
336 {
337 for (unsigned int n = 0u; n < channels; ++n)
338 {
339 if (groundtruth)
340 {
341 *groundtruth = backgroundColor[n];
342 groundtruth++;
343 }
344
345 const double absError = NumericD::abs(double(interpolatedPixel[n]) - double(backgroundColor[n]));
346
347 sumAbsError += absError;
348
349 if (absError > maxAbsError)
350 {
351 maxAbsError = absError;
352 }
353
354 measurements++;
355 }
356 }
357 }
358 }
359
360 if (averageAbsError)
361 {
362 ocean_assert(measurements != 0ull);
363 *averageAbsError = sumAbsError / double(measurements);
364 }
365
366 if (maximalAbsError)
367 {
368 *maximalAbsError = maxAbsError;
369 }
370}
371
372} // namespace TestCV
373
374} // namespace Test
375
376} // namespace Ocean
377
378#endif // META_OCEAN_TEST_TESTCV_TEST_FRAME_INTERPOLATOR_NEAREST_PIXEL_H
This class implements a 2D pixel position with pixel precision.
Definition PixelPosition.h:65
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
This class implements Ocean's image class.
Definition Frame.h:1808
This class implements a 2D lookup object with values at the bins' corners defining the individual loo...
Definition Lookup2.h:636
static T abs(const T value)
Returns the absolute value of a given value.
Definition Numeric.h:1220
static constexpr int32_t round32(const T value)
Returns the rounded 32 bit integer value of a given value.
Definition Numeric.h:2064
bool isSingular() const
Returns whether this matrix is singular (and thus cannot be inverted).
Definition SquareMatrix3.h:1341
This class implements a nearest pixel frame interpolator test.
Definition TestFrameInterpolatorNearestPixel.h:31
static bool testResize(const double testDuration, Worker &worker)
Tests the resize function.
static bool testAffine(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker &worker)
Test for affine image transformations for varying frame dimensions and channel numbers.
static bool testResize(const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const double testDuration, Worker &worker)
Tests the resize function for a given frame dimension and channel number.
static bool testHomography(const double testDuration, Worker &worker)
Tests the homography transformation function.
static bool validateRotate90(const TElementType *frame, const unsigned int channels, const unsigned int width, const unsigned int height, const TElementType *clockwise, const TElementType *counterClockwise, const unsigned int framePaddingElements, const unsigned int clockwisePaddingElements, const unsigned int counterClockwisePaddingElements)
Validates the 90 degree rotate function.
static bool validateHomographyMask8BitPerChannel(const Frame &inputFrame, const Frame &outputFrame, const Frame &outputMask, const SquareMatrix3 &input_H_output, const CV::PixelPositionI &outputFrameOrigin)
Validates the homography interpolation function (using a binary mask to define known and unknown imag...
static bool testTransform(const unsigned int width, const unsigned int height, const double testDuration, Worker &worker)
Tests the frame transformation function applying a lookup table.
static bool testTransformMask(const unsigned int width, const unsigned int height, const double testDuration, Worker &worker)
Tests the frame mask transformation function applying a lookup table.
static bool testHomographyMask(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker &worker)
Tests the homography transformation function (with binary mask defining known and unknown image conte...
static void validateHomography(const T *frame, const unsigned int frameWidth, const unsigned int frameHeight, const unsigned int framePaddingElements, const T *interpolatedFrame, const unsigned int interpolatedFrameWidth, const unsigned int interpolatedFrameHeight, const unsigned int interpolatedFramePaddingElements, const unsigned int channels, const SquareMatrix3 &homography, const T *backgroundColor, const CV::PixelPositionI &interpolatedFrameOrigin, double *maximalAbsError=nullptr, double *averageAbsError=nullptr, T *groundtruth=nullptr)
Validation function for the nearest-neighbor interpolation of 2D homogeneous image transformations (+...
Definition TestFrameInterpolatorNearestPixel.h:275
static bool testRotate90(const double testDuration, Worker &worker)
Tests the 90 degree rotate function.
static bool validateTransformationMask(const Frame &frame, const Frame &target, const Frame &targetMask, const CV::FrameInterpolatorNearestPixel::LookupTable &lookupTable, const uint8_t maskValue)
Validates the frame mask transformation function applying a lookup table.
static bool testHomography(const unsigned int width, const unsigned int height, const unsigned int channels, const double testDuration, Worker &worker)
Tests the homography transformation function for a given frame dimension and channel number.
static bool validateResizedFrame(const T *source, const T *target, const unsigned int sourceWidth, const unsigned int sourceHeight, const unsigned int targetWidth, const unsigned int targetHeight, const unsigned int channels, const unsigned int sourcePaddingElements, const unsigned int targetPaddingElements)
Validates a resized frame.
static bool testHomographyMask(const double testDuration, Worker &worker)
Tests the homography transformation function defining a binary mask for known and unknown image conte...
static bool test(const unsigned int width, const unsigned int height, const double testDuration, Worker &worker)
Tests all nearest pixel interpolation filter functions.
static bool testAffine(const double testDuration, Worker &worker)
Test for affine image transformations.
static bool validateTransformation(const Frame &frame, const Frame &target, const CV::FrameInterpolatorNearestPixel::LookupTable &lookupTable, const uint8_t *borderColor)
Validates the frame transformation function applying a lookup table.
static bool testRotate90(const unsigned int width, const unsigned int height, const double testDuration, Worker &worker)
Tests the 90 degree rotate function for a specific frame size and number of channels.
static bool testSpecialCasesResize400x400To224x224_8BitPerChannel(const double testDuration)
Tests the special case resize function for image resolutions from 400x400 to 224x224.
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
This class implements a worker able to distribute function calls over different threads.
Definition Worker.h:33
float Scalar
Definition of a scalar type.
Definition Math.h:129
VectorT2< Scalar > Vector2
Definition of a 2D vector.
Definition Vector2.h:28
The namespace covering the entire Ocean framework.
Definition Accessor.h:15