8 #ifndef META_OCEAN_CV_ADVANCED_ADVANCED_FRAME_INTERPOLATOR_BILINEAR_NEON_H
9 #define META_OCEAN_CV_ADVANCED_ADVANCED_FRAME_INTERPOLATOR_BILINEAR_NEON_H
13 #if defined(OCEAN_HARDWARE_NEON_VERSION) && OCEAN_HARDWARE_NEON_VERSION >= 10
40 template <
unsigned int tChannels>
55 template <
unsigned int tPatchSize>
56 static inline void interpolateSquarePatch8BitPerChannel(
const uint8_t* imageTopLeft,
const unsigned int imageStrideElements, uint8_t* buffer,
const unsigned int factorRight,
const unsigned int factorBottom);
74 template <
unsigned int tChannels,
unsigned int tPatchSize, PixelCenter tPixelCenter = PC_TOP_LEFT,
typename TScalar = Scalar>
75 static inline void interpolateSquarePatch8BitPerChannel(
const uint8_t*
const image,
const unsigned int width,
const unsigned int imagePaddingElements, uint8_t* buffer,
const VectorT2<TScalar>& position);
79 template <
unsigned int tPatchSize>
82 ocean_assert(imageTopLeft !=
nullptr && buffer !=
nullptr);
83 ocean_assert(imageStrideElements >= 1u * tPatchSize);
85 ocean_assert(factorRight <= 128u && factorBottom <= 128u);
87 const unsigned int factorLeft = 128u - factorRight;
88 const unsigned int factorTop = 128u - factorBottom;
90 constexpr
unsigned int blocks15 = tPatchSize / 15u;
91 constexpr
unsigned int remainingAfterBlocks15 = tPatchSize % 15u;
93 constexpr
bool partialBlock15 = remainingAfterBlocks15 > 10u;
94 constexpr
unsigned int remainingAfterPartialBlock15 = partialBlock15 ? 0u : remainingAfterBlocks15;
96 constexpr
bool block7 = remainingAfterPartialBlock15 >= 7u;
97 constexpr
unsigned int remainingAfterBlock7 = remainingAfterPartialBlock15 % 7u;
99 constexpr
bool partialBlock7 = remainingAfterBlock7 >= 3u;
100 constexpr
unsigned int remainingAfterPartialBlock7 = partialBlock7 ? 0u : remainingAfterBlock7;
102 constexpr
unsigned int blocks1 = remainingAfterPartialBlock7;
105 const uint8x8_t factorsLeftRight_u_8x8 = vreinterpret_u8_u16(vdup_n_u16(uint16_t(factorLeft | (factorRight << 8u))));
107 const uint32x4_t factorsTop_u_32x4 = vdupq_n_u32(factorTop);
108 const uint32x4_t factorsBottom_u_32x4 = vdupq_n_u32(factorBottom);
110 for (
unsigned int y = 0u; y < tPatchSize; ++y)
112 for (
unsigned int x = 0u; x < blocks15; ++x)
114 const uint8x16_t top_u_8x16 = vld1q_u8(imageTopLeft);
115 const uint8x16_t bottom_u_8x16 = vld1q_u8(imageTopLeft + imageStrideElements);
118 const uint8x16_t topB_u_8x16 = vextq_u8(top_u_8x16, vreinterpretq_u8_u32(factorsTop_u_32x4), 1);
119 const uint8x16_t bottomB_u_8x16 = vextq_u8(bottom_u_8x16, vreinterpretq_u8_u32(factorsTop_u_32x4), 1);
123 const uint32x4_t topLowA_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(top_u_8x16), factorsLeftRight_u_8x8));
124 const uint32x4_t bottomLowA_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(bottom_u_8x16), factorsLeftRight_u_8x8));
127 const uint32x4_t topLowB_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(topB_u_8x16), factorsLeftRight_u_8x8));
128 const uint32x4_t bottomLowB_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(bottomB_u_8x16), factorsLeftRight_u_8x8));
131 const uint32x4_t topHighA_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(top_u_8x16), factorsLeftRight_u_8x8));
132 const uint32x4_t bottomHighA_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(bottom_u_8x16), factorsLeftRight_u_8x8));
135 const uint32x4_t topHighB_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(topB_u_8x16), factorsLeftRight_u_8x8));
136 const uint32x4_t bottomHighB_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(bottomB_u_8x16), factorsLeftRight_u_8x8));
140 const uint16x4_t resultLowA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topLowA_u_32x4, factorsTop_u_32x4), bottomLowA_u_32x4, factorsBottom_u_32x4), 14);
141 const uint16x4_t resultHighA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topHighA_u_32x4, factorsTop_u_32x4), bottomHighA_u_32x4, factorsBottom_u_32x4), 14);
143 const uint16x4_t resultLowB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topLowB_u_32x4, factorsTop_u_32x4), bottomLowB_u_32x4, factorsBottom_u_32x4), 14);
144 const uint16x4_t resultHighB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topHighB_u_32x4, factorsTop_u_32x4), bottomHighB_u_32x4, factorsBottom_u_32x4), 14);
146 const uint16x8_t resultA_u_16x8 = vcombine_u16(resultLowA_u_16x4, resultHighA_u_16x4);
147 const uint16x8_t resultB_u_16x8 = vcombine_u16(resultLowB_u_16x4, resultHighB_u_16x4);
150 const uint8x16_t result_u_8x16 = vreinterpretq_u8_u16(vsliq_n_u16(resultA_u_16x8, resultB_u_16x8, 8));
153 const bool isLastBlock = (y + 1u == tPatchSize) && (x + 1u == blocks15) && (!block7 && !partialBlock7 && blocks1 == 0u);
157 uint8_t tempBuffer[16];
158 vst1q_u8(tempBuffer, result_u_8x16);
160 memcpy(buffer, &tempBuffer, 15);
164 vst1q_u8(buffer, result_u_8x16);
171 if constexpr (partialBlock15)
173 ocean_assert(!block7 && !partialBlock7 && blocks1 == 0u);
175 uint8x16_t top_u_8x16;
176 uint8x16_t bottom_u_8x16;
178 if (y < tPatchSize - 1u)
180 top_u_8x16 = vld1q_u8(imageTopLeft);
181 bottom_u_8x16 = vld1q_u8(imageTopLeft + imageStrideElements);
185 constexpr
unsigned int overlapping = 16u - (remainingAfterBlocks15 + 1u);
187 top_u_8x16 = vld1q_u8(imageTopLeft - overlapping);
188 bottom_u_8x16 = vld1q_u8(imageTopLeft + imageStrideElements - overlapping);
190 top_u_8x16 = vextq_u8(top_u_8x16, vreinterpretq_u8_u32(factorsTop_u_32x4), overlapping);
191 bottom_u_8x16 = vextq_u8(bottom_u_8x16, vreinterpretq_u8_u32(factorsTop_u_32x4), overlapping);
195 const uint8x16_t topB_u_8x16 = vextq_u8(top_u_8x16, top_u_8x16, 1);
196 const uint8x16_t bottomB_u_8x16 = vextq_u8(bottom_u_8x16, bottom_u_8x16, 1);
200 const uint32x4_t topLowA_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(top_u_8x16), factorsLeftRight_u_8x8));
201 const uint32x4_t bottomLowA_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(bottom_u_8x16), factorsLeftRight_u_8x8));
204 const uint32x4_t topLowB_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(topB_u_8x16), factorsLeftRight_u_8x8));
205 const uint32x4_t bottomLowB_u_32x4 = vpaddlq_u16(vmull_u8(vget_low_u8(bottomB_u_8x16), factorsLeftRight_u_8x8));
208 const uint32x4_t topHighA_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(top_u_8x16), factorsLeftRight_u_8x8));
209 const uint32x4_t bottomHighA_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(bottom_u_8x16), factorsLeftRight_u_8x8));
212 const uint32x4_t topHighB_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(topB_u_8x16), factorsLeftRight_u_8x8));
213 const uint32x4_t bottomHighB_u_32x4 = vpaddlq_u16(vmull_u8(vget_high_u8(bottomB_u_8x16), factorsLeftRight_u_8x8));
217 const uint16x4_t resultLowA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topLowA_u_32x4, factorsTop_u_32x4), bottomLowA_u_32x4, factorsBottom_u_32x4), 14);
218 const uint16x4_t resultHighA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topHighA_u_32x4, factorsTop_u_32x4), bottomHighA_u_32x4, factorsBottom_u_32x4), 14);
220 const uint16x4_t resultLowB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topLowB_u_32x4, factorsTop_u_32x4), bottomLowB_u_32x4, factorsBottom_u_32x4), 14);
221 const uint16x4_t resultHighB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topHighB_u_32x4, factorsTop_u_32x4), bottomHighB_u_32x4, factorsBottom_u_32x4), 14);
223 const uint16x8_t resultA_u_16x8 = vcombine_u16(resultLowA_u_16x4, resultHighA_u_16x4);
224 const uint16x8_t resultB_u_16x8 = vcombine_u16(resultLowB_u_16x4, resultHighB_u_16x4);
227 const uint8x16_t result_u_8x16 = vreinterpretq_u8_u16(vsliq_n_u16(resultA_u_16x8, resultB_u_16x8, 8));
229 ocean_assert(!block7 && !partialBlock7 && blocks1 == 0u);
230 const bool isLastBlock = y + 1u == tPatchSize;
234 uint8_t tempBuffer[16];
235 vst1q_u8(tempBuffer, result_u_8x16);
237 memcpy(buffer, &tempBuffer, remainingAfterBlocks15);
241 vst1q_u8(buffer, result_u_8x16);
244 imageTopLeft += remainingAfterBlocks15;
245 buffer += remainingAfterBlocks15;
248 if constexpr (block7)
250 const uint8x8_t top_u_8x8 = vld1_u8(imageTopLeft);
251 const uint8x8_t bottom_u_8x8 = vld1_u8(imageTopLeft + imageStrideElements);
254 const uint8x8_t topB_u_8x8 = vext_u8(top_u_8x8, factorsLeftRight_u_8x8, 1);
255 const uint8x8_t bottomB_u_8x8 = vext_u8(bottom_u_8x8, factorsLeftRight_u_8x8, 1);
259 const uint32x4_t topA_u_32x4 = vpaddlq_u16(vmull_u8(top_u_8x8, factorsLeftRight_u_8x8));
260 const uint32x4_t bottomA_u_32x4 = vpaddlq_u16(vmull_u8(bottom_u_8x8, factorsLeftRight_u_8x8));
263 const uint32x4_t topB_u_32x4 = vpaddlq_u16(vmull_u8(topB_u_8x8, factorsLeftRight_u_8x8));
264 const uint32x4_t bottomB_u_32x4 = vpaddlq_u16(vmull_u8(bottomB_u_8x8, factorsLeftRight_u_8x8));
268 const uint16x4_t resultA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topA_u_32x4, factorsTop_u_32x4), bottomA_u_32x4, factorsBottom_u_32x4), 14);
269 const uint16x4_t resultB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topB_u_32x4, factorsTop_u_32x4), bottomB_u_32x4, factorsBottom_u_32x4), 14);
273 const uint8x8_t result_u_8x8 = vreinterpret_u8_u16(vsli_n_u16(resultA_u_16x4, resultB_u_16x4, 8));
275 const bool isLastBlock = (y + 1u == tPatchSize) && (!partialBlock7 && blocks1 == 0u);
279 uint8_t tempBuffer[8];
280 vst1_u8(tempBuffer, result_u_8x8);
282 memcpy(buffer, &tempBuffer, 7);
286 vst1_u8(buffer, result_u_8x8);
293 if constexpr (partialBlock7)
295 ocean_assert(blocks1 == 0u);
298 uint8x8_t bottom_u_8x8;
300 if (y < tPatchSize - 1u)
302 top_u_8x8 = vld1_u8(imageTopLeft);
303 bottom_u_8x8 = vld1_u8(imageTopLeft + imageStrideElements);
307 constexpr
unsigned int overlapping = 8u - (remainingAfterBlock7 + 1u);
309 top_u_8x8 = vld1_u8(imageTopLeft - overlapping);
310 bottom_u_8x8 = vld1_u8(imageTopLeft + imageStrideElements - overlapping);
312 top_u_8x8 = vext_u8(top_u_8x8, factorsLeftRight_u_8x8, overlapping);
313 bottom_u_8x8 = vext_u8(bottom_u_8x8, factorsLeftRight_u_8x8, overlapping);
318 const uint8x8_t topB_u_8x8 = vext_u8(top_u_8x8, factorsLeftRight_u_8x8, 1);
319 const uint8x8_t bottomB_u_8x8 = vext_u8(bottom_u_8x8, factorsLeftRight_u_8x8, 1);
323 const uint32x4_t topA_u_32x4 = vpaddlq_u16(vmull_u8(top_u_8x8, factorsLeftRight_u_8x8));
324 const uint32x4_t bottomA_u_32x4 = vpaddlq_u16(vmull_u8(bottom_u_8x8, factorsLeftRight_u_8x8));
327 const uint32x4_t topB_u_32x4 = vpaddlq_u16(vmull_u8(topB_u_8x8, factorsLeftRight_u_8x8));
328 const uint32x4_t bottomB_u_32x4 = vpaddlq_u16(vmull_u8(bottomB_u_8x8, factorsLeftRight_u_8x8));
332 const uint16x4_t resultA_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topA_u_32x4, factorsTop_u_32x4), bottomA_u_32x4, factorsBottom_u_32x4), 14);
333 const uint16x4_t resultB_u_16x4 = vrshrn_n_u32(vmlaq_u32(vmulq_u32(topB_u_32x4, factorsTop_u_32x4), bottomB_u_32x4, factorsBottom_u_32x4), 14);
337 const uint8x8_t result_u_8x8 = vreinterpret_u8_u16(vsli_n_u16(resultA_u_16x4, resultB_u_16x4, 8));
339 ocean_assert(blocks1 == 0u);
340 const bool isLastBlock = y + 1u == tPatchSize;
344 uint8_t tempBuffer[8];
345 vst1_u8(tempBuffer, result_u_8x8);
347 memcpy(buffer, &tempBuffer, remainingAfterBlock7);
351 vst1_u8(buffer, result_u_8x8);
354 imageTopLeft += remainingAfterBlock7;
355 buffer += remainingAfterBlock7;
358 if constexpr (blocks1 != 0u)
360 const unsigned int factorTopLeft = factorTop * factorLeft;
361 const unsigned int factorTopRight = factorTop * factorRight;
363 const unsigned int factorBottomLeft = factorBottom * factorLeft;
364 const unsigned int factorBottomRight = factorBottom * factorRight;
366 const uint8_t*
const imageBottomLeft = imageTopLeft + imageStrideElements;
368 for (
unsigned int n = 0u; n < blocks1; ++n)
370 buffer[n] = uint8_t((imageTopLeft[n] * factorTopLeft + imageTopLeft[1u + n] * factorTopRight + imageBottomLeft[n] * factorBottomLeft + imageBottomLeft[1u + n] * factorBottomRight + 8192u) / 16384u);
373 imageTopLeft += blocks1;
377 imageTopLeft += imageStrideElements - tPatchSize;
381 template <
unsigned int tChannels>
382 template <
unsigned int tPatchSize>
385 ocean_assert(imageTopLeft !=
nullptr && buffer !=
nullptr);
386 ocean_assert(imageStrideElements >= 1u * tPatchSize);
388 ocean_assert(factorRight <= 128u && factorBottom <= 128u);
390 const unsigned int factorLeft = 128u - factorRight;
391 const unsigned int factorTop = 128u - factorBottom;
393 const unsigned int factorTopLeft = factorTop * factorLeft;
394 const unsigned int factorTopRight = factorTop * factorRight;
396 const unsigned int factorBottomLeft = factorBottom * factorLeft;
397 const unsigned int factorBottomRight = factorBottom * factorRight;
399 const uint8_t* imageBottomLeft = imageTopLeft + imageStrideElements;
401 for (
unsigned int y = 0u; y < tPatchSize; ++y)
403 for (
unsigned int x = 0u; x < tPatchSize; ++x)
405 for (
unsigned int n = 0u; n < tChannels; ++n)
407 buffer[n] = uint8_t((imageTopLeft[n] * factorTopLeft + imageTopLeft[tChannels + n] * factorTopRight + imageBottomLeft[n] * factorBottomLeft + imageBottomLeft[tChannels + n] * factorBottomRight + 8192u) / 16384u);
410 imageTopLeft += tChannels;
411 imageBottomLeft += tChannels;
416 imageTopLeft += imageStrideElements - tChannels * tPatchSize;
417 imageBottomLeft += imageStrideElements - tChannels * tPatchSize;
421 template <
unsigned int tChannels,
unsigned int tPatchSize, PixelCenter tPixelCenter,
typename TScalar>
424 static_assert(tChannels >= 1u,
"Invalid channel number!");
425 static_assert(tPatchSize % 2u == 1u,
"Invalid patch size!");
427 ocean_assert(image !=
nullptr && buffer !=
nullptr);
428 ocean_assert(tPatchSize + 1u <= width);
430 ocean_assert(tPatchSize >= 5u);
432 constexpr
unsigned int tPatchSize_2 = tPatchSize / 2u;
434 const unsigned int imageStrideElements = width * tChannels + imagePaddingElements;
438 ocean_assert(shiftedPosition.
x() >= TScalar(tPatchSize_2) && shiftedPosition.
y() >= TScalar(tPatchSize_2));
439 ocean_assert(shiftedPosition.
x() < TScalar(width - tPatchSize_2 - 1u));
441 const unsigned int left = (
unsigned int)(shiftedPosition.
x()) - tPatchSize_2;
442 const unsigned int top = (
unsigned int)(shiftedPosition.
y()) - tPatchSize_2;
444 ocean_assert(left + tPatchSize < width);
446 const TScalar tx = shiftedPosition.
x() - TScalar(
int(shiftedPosition.
x()));
447 ocean_assert(tx >= TScalar(0) && tx <= TScalar(1));
448 const unsigned int factorRight = (
unsigned int)(tx * TScalar(128) + TScalar(0.5));
450 const TScalar ty = shiftedPosition.
y() - TScalar(
int(shiftedPosition.
y()));
451 ocean_assert(ty >= 0 && ty <= 1);
452 const unsigned int factorBottom = (
unsigned int)(ty * TScalar(128) + TScalar(0.5));
454 const uint8_t*
const imageTopLeft = image + top * imageStrideElements + left * tChannels;
This class allows to specialize functions for individual channels.
Definition: AdvancedFrameInterpolatorBilinearNEON.h:42
static void interpolateSquarePatch8BitPerChannel(const uint8_t *imageTopLeft, const unsigned int imageStrideElements, uint8_t *buffer, const unsigned int factorRight, const unsigned int factorBottom)
Interpolates the content of a square image patch with sub-pixel accuracy inside a given image and sto...
Definition: AdvancedFrameInterpolatorBilinearNEON.h:383
This class implements advanced bilinear frame interpolation functions using NEON extensions.
Definition: AdvancedFrameInterpolatorBilinearNEON.h:33
static void interpolateSquarePatch8BitPerChannel(const uint8_t *const image, const unsigned int width, const unsigned int imagePaddingElements, uint8_t *buffer, const VectorT2< TScalar > &position)
Interpolates the content of a square image patch with sub-pixel accuracy inside a given image and sto...
Definition: AdvancedFrameInterpolatorBilinearNEON.h:422
This class implements a vector with two elements.
Definition: Vector2.h:96
const T & x() const noexcept
Returns the x value.
Definition: Vector2.h:698
const T & y() const noexcept
Returns the y value.
Definition: Vector2.h:710
@ PC_TOP_LEFT
The center of a pixel is in the upper-left corner of each pixel's square.
Definition: CV.h:133
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15