From 3d6ea3f8584bcf8aec8ebabd622d0ca39502efb6 Mon Sep 17 00:00:00 2001 From: Richard Wells Date: Tue, 26 Nov 2024 11:12:19 +0000 Subject: [PATCH] Implement remap_s16 for u16. Repurposes existing u8 implementations of remap_s16 for Neon and SVE2, and makes them work for source type u16. --- CHANGELOG.md | 4 +- adapters/opencv/kleidicv_hal.cpp | 17 ++- benchmark/benchmark.cpp | 13 ++ conformity/opencv/test_remap.cpp | 1 + doc/functionality.md | 2 +- doc/opencv.md | 6 +- kleidicv/include/kleidicv/kleidicv.h | 9 ++ kleidicv/include/kleidicv/transform/remap.h | 9 +- kleidicv/src/transform/remap_api.cpp | 4 + kleidicv/src/transform/remap_neon.cpp | 20 ++- kleidicv/src/transform/remap_sc.h | 79 ++++++---- kleidicv/src/transform/remap_sve2.cpp | 7 +- .../include/kleidicv_thread/kleidicv_thread.h | 11 ++ kleidicv_thread/src/kleidicv_thread.cpp | 21 +++ scripts/benchmark/benchmarks.txt | 1 + test/api/test_remap.cpp | 136 +++++++++++------- test/api/test_thread.cpp | 14 ++ test/api/test_warp_perspective.cpp | 8 +- 18 files changed, 256 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e8807ac0..ac4a4bfff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,9 @@ This changelog aims to follow the guiding principles of ### Added - Implementation of Rotate 90 degrees clockwise. -- Remap function with nearest neighbour and fixed-point interpolation for 8-bit inputs. +- Remap implementations + - Nearest neighbour, for replicated borders with 1-channel u8 and u16 inputs. + - Fixed-point interpolation, for replicated borders with 1-channel u8 input. - WarpPerspective implementation - Nearest and Linear interpolation method, for replicated borders and 1-channel u8 input. diff --git a/adapters/opencv/kleidicv_hal.cpp b/adapters/opencv/kleidicv_hal.cpp index 4c57b0857..b62f736bc 100644 --- a/adapters/opencv/kleidicv_hal.cpp +++ b/adapters/opencv/kleidicv_hal.cpp @@ -1310,14 +1310,23 @@ int remap_s16(int src_type, const uchar *src_data, size_t src_step, return CV_HAL_ERROR_NOT_IMPLEMENTED; } - auto border_value = get_border_value(border_value_f64); - auto mt = get_multithreading(); if (src_type == CV_8UC1) { + auto border_value = get_border_value(border_value_f64); return convert_error(kleidicv_thread_remap_s16_u8( - src_data, src_step, static_cast(src_width), - static_cast(src_height), dst_data, dst_step, + reinterpret_cast(src_data), src_step, + static_cast(src_width), static_cast(src_height), + reinterpret_cast(dst_data), dst_step, + static_cast(dst_width), static_cast(dst_height), + CV_MAT_CN(src_type), mapxy, mapxy_step, kleidicv_border_type, + border_value.data(), mt)); + } else if (src_type == CV_16UC1) { + auto border_value = get_border_value(border_value_f64); + return convert_error(kleidicv_thread_remap_s16_u16( + reinterpret_cast(src_data), src_step, + static_cast(src_width), static_cast(src_height), + reinterpret_cast(dst_data), dst_step, static_cast(dst_width), static_cast(dst_height), CV_MAT_CN(src_type), mapxy, mapxy_step, kleidicv_border_type, border_value.data(), mt)); diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 94cff9f28..2bab77141 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -639,6 +639,19 @@ BENCH_REMAP_S16(remap_s16_u8_identity, remap_s16_u8, get_identity_mapxy, 1, KLEIDICV_BORDER_TYPE_REPLICATE, uint8_t); +BENCH_REMAP_S16(remap_s16_u16_random, remap_s16_u16, get_random_mapxy, + 1, KLEIDICV_BORDER_TYPE_REPLICATE, uint16_t); + +BENCH_REMAP_S16(remap_s16_u16_blend, remap_s16_u16, get_blend_mapxy, 1, + KLEIDICV_BORDER_TYPE_REPLICATE, uint16_t); + +BENCH_REMAP_S16(remap_s16_u16_flip, remap_s16_u16, get_flip_mapxy, 1, + KLEIDICV_BORDER_TYPE_REPLICATE, uint16_t); + +BENCH_REMAP_S16(remap_s16_u16_identity, remap_s16_u16, + get_identity_mapxy, 1, KLEIDICV_BORDER_TYPE_REPLICATE, + uint16_t); + template static void remap_s16point5(Function f, MapFunc mf, size_t channels, kleidicv_border_type_t border_type, diff --git a/conformity/opencv/test_remap.cpp b/conformity/opencv/test_remap.cpp index fea0f7a3f..0455d6773 100644 --- a/conformity/opencv/test_remap.cpp +++ b/conformity/opencv/test_remap.cpp @@ -135,6 +135,7 @@ std::vector& remap_tests_get() { // clang-format off static std::vector tests = { TEST("RemapS16 uint8", (test_remap_s16), (exec_remap_s16)), + TEST("RemapS16 uint16", (test_remap_s16), (exec_remap_s16)), TEST("RemapS16Point5 uint8", (test_remap_s16point5), (exec_remap_s16point5)), }; // clang-format on diff --git a/doc/functionality.md b/doc/functionality.md index 3271c47ff..f2bf16266 100644 --- a/doc/functionality.md +++ b/doc/functionality.md @@ -95,7 +95,7 @@ See `doc/opencv.md` for details of the functionality available in OpenCV. # Remap | | u8 | u16 | |--------------------------------------------|-----|-----| -| Remap int16 coordinates | x | | +| Remap int16 coordinates | x | x | | Remap int16+uint16 fixed-point coordinates | x | | # WarpPerspective diff --git a/doc/opencv.md b/doc/opencv.md index 020406e17..a6f1d2fb8 100644 --- a/doc/opencv.md +++ b/doc/opencv.md @@ -211,8 +211,10 @@ Geometrically transforms the `src` image by taking the pixels specified by the c Notes on parameters: * `src.step` - must be less than 2^16 * `element size` * `src.width`, `src_height` - must not be bigger than 2^15 -* `src.depth()` - only supports `CV_8U` depth and 1 channel. -* `borderMode` - only supports `BORDER_REPLICATE`. +* `src.depth()` + * Supports `CV_8U` and `CV_16U` depths and 1 channel when prodiving only an integer map (`map1`). + * Supports `CV_8U` depth and 1 channel when providing integer + fractional maps (`map1` and `map2`). +* `borderMode` - only supports `BORDER_REPLICATE`. \ Supported map configurations: * `map1` is 16SC2: channel #1 is x coordinate (column) and channel #2 is y (row) * supported `interpolation`: `INTER_NEAREST` only diff --git a/kleidicv/include/kleidicv/kleidicv.h b/kleidicv/include/kleidicv/kleidicv.h index 454fa7b00..1133718ea 100644 --- a/kleidicv/include/kleidicv/kleidicv.h +++ b/kleidicv/include/kleidicv/kleidicv.h @@ -1800,6 +1800,15 @@ KLEIDICV_API_DECLARATION(kleidicv_remap_s16_u8, const uint8_t *src, kleidicv_border_type_t border_type, const uint8_t *border_value); +/// @copydoc kleidicv_remap_s16_u8 +KLEIDICV_API_DECLARATION(kleidicv_remap_s16_u16, const uint16_t *src, + size_t src_stride, size_t src_width, size_t src_height, + uint16_t *dst, size_t dst_stride, size_t dst_width, + size_t dst_height, size_t channels, + const int16_t *mapxy, size_t mapxy_stride, + kleidicv_border_type_t border_type, + const uint16_t *border_value); + #ifndef DOXYGEN /// Internal - not part of the public API and its direct use is not supported. /// Functionality is similar to @ref kleidicv_remap_s16_u8 , the difference is diff --git a/kleidicv/include/kleidicv/transform/remap.h b/kleidicv/include/kleidicv/transform/remap.h index 97f3f0d55..204766006 100644 --- a/kleidicv/include/kleidicv/transform/remap.h +++ b/kleidicv/include/kleidicv/transform/remap.h @@ -17,12 +17,13 @@ inline bool remap_s16_is_implemented( size_t src_stride, size_t src_width, size_t src_height, size_t dst_width, kleidicv_border_type_t border_type, size_t channels) KLEIDICV_STREAMING_COMPATIBLE { - if constexpr (std::is_same::value) { - return (src_stride <= std::numeric_limits::max() && + if constexpr (std::is_same::value || + std::is_same::value) { + return (src_stride / sizeof(T) <= std::numeric_limits::max() && + dst_width >= 8 && src_width <= std::numeric_limits::max() + 1 && src_height <= std::numeric_limits::max() + 1 && - dst_width >= 8 && border_type == KLEIDICV_BORDER_TYPE_REPLICATE && - channels == 1); + border_type == KLEIDICV_BORDER_TYPE_REPLICATE && channels == 1); } else { return false; } diff --git a/kleidicv/src/transform/remap_api.cpp b/kleidicv/src/transform/remap_api.cpp index 52dda6203..5df6feb1c 100644 --- a/kleidicv/src/transform/remap_api.cpp +++ b/kleidicv/src/transform/remap_api.cpp @@ -10,6 +10,10 @@ KLEIDICV_MULTIVERSION_C_API(kleidicv_remap_s16_u8, &kleidicv::neon::remap_s16, &kleidicv::sve2::remap_s16, nullptr); +KLEIDICV_MULTIVERSION_C_API(kleidicv_remap_s16_u16, + &kleidicv::neon::remap_s16, + &kleidicv::sve2::remap_s16, nullptr); + KLEIDICV_MULTIVERSION_C_API( kleidicv_remap_s16point5_u8, &kleidicv::neon::remap_s16point5, &kleidicv::sve2::remap_s16point5, diff --git a/kleidicv/src/transform/remap_neon.cpp b/kleidicv/src/transform/remap_neon.cpp index 43de2d561..1a799cf9e 100644 --- a/kleidicv/src/transform/remap_neon.cpp +++ b/kleidicv/src/transform/remap_neon.cpp @@ -11,19 +11,16 @@ namespace kleidicv::neon { template -class RemapS16; - -template <> -class RemapS16 { +class RemapS16 { public: - using ScalarType = uint8_t; using MapVecTraits = neon::VecTraits; using MapVectorType = typename MapVecTraits::VectorType; using MapVector2Type = typename MapVecTraits::Vector2Type; RemapS16(Rows src_rows, size_t src_width, size_t src_height) : src_rows_{src_rows}, - v_src_stride_{vdupq_n_u16(static_cast(src_rows_.stride()))}, + v_src_element_stride{vdupq_n_u16( + static_cast(src_rows_.stride() / sizeof(ScalarType)))}, v_xmax_{vdupq_n_s16(static_cast(src_width - 1))}, v_ymax_{vdupq_n_s16(static_cast(src_height - 1))} {} @@ -36,17 +33,17 @@ class RemapS16 { vmaxq_s16(vdupq_n_s16(0), vminq_s16(xy.val[0], v_xmax_))); uint16x8_t y = vreinterpretq_u16_s16( vmaxq_s16(vdupq_n_s16(0), vminq_s16(xy.val[1], v_ymax_))); - // Calculate offsets from coordinates (y * stride + x) + // Calculate offsets from coordinates (y * stride/sizeof(ScalarType) + x) uint32x4_t indices_low = vmlal_u16(vmovl_u16(vget_low_u16(x)), vget_low_u16(y), - vget_low_u16(v_src_stride_)); + vget_low_u16(v_src_element_stride)); // Copy pixels from source dst[0] = src_rows_[vgetq_lane_u32(indices_low, 0)]; dst[1] = src_rows_[vgetq_lane_u32(indices_low, 1)]; dst[2] = src_rows_[vgetq_lane_u32(indices_low, 2)]; dst[3] = src_rows_[vgetq_lane_u32(indices_low, 3)]; uint32x4_t indices_high = - vmlal_high_u16(vmovl_high_u16(x), y, v_src_stride_); + vmlal_high_u16(vmovl_high_u16(x), y, v_src_element_stride); dst[4] = src_rows_[vgetq_lane_u32(indices_high, 0)]; dst[5] = src_rows_[vgetq_lane_u32(indices_high, 1)]; dst[6] = src_rows_[vgetq_lane_u32(indices_high, 2)]; @@ -66,10 +63,10 @@ class RemapS16 { private: Rows src_rows_; - uint16x8_t v_src_stride_; + uint16x8_t v_src_element_stride; int16x8_t v_xmax_; int16x8_t v_ymax_; -}; // end of class RemapS16 +}; // end of class RemapS16 template kleidicv_error_t remap_s16(const T *src, size_t src_stride, size_t src_width, @@ -261,6 +258,7 @@ kleidicv_error_t remap_s16point5( kleidicv_border_type_t border_type, const type *border_value) KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16(uint8_t); +KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16(uint16_t); #define KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16Point5(type) \ template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t remap_s16point5( \ diff --git a/kleidicv/src/transform/remap_sc.h b/kleidicv/src/transform/remap_sc.h index 58e18c905..af88303ea 100644 --- a/kleidicv/src/transform/remap_sc.h +++ b/kleidicv/src/transform/remap_sc.h @@ -8,7 +8,9 @@ #include #include +#include #include +#include #include #include @@ -20,12 +22,8 @@ namespace KLEIDICV_TARGET_NAMESPACE { #if !KLEIDICV_TARGET_SME2 template -class RemapS16; - -template <> -class RemapS16 { +class RemapS16 { public: - using ScalarType = uint8_t; using MapVecTraits = VecTraits; using MapVectorType = typename MapVecTraits::VectorType; using MapVector2Type = typename MapVecTraits::Vector2Type; @@ -34,14 +32,18 @@ class RemapS16 { svuint16_t& v_src_stride, MapVectorType& v_x_max, MapVectorType& v_y_max) : src_rows_{src_rows}, - v_src_stride_{v_src_stride}, + v_src_element_stride{v_src_stride}, v_xmax_{v_x_max}, v_ymax_{v_y_max} { - v_src_stride_ = svdup_u16(src_rows.stride()); + v_src_element_stride = svdup_u16(src_rows.stride() / sizeof(ScalarType)); v_xmax_ = svdup_s16(static_cast(src_width - 1)); v_ymax_ = svdup_s16(static_cast(src_height - 1)); } + void transform_pixels(svuint32_t offsets_b, svbool_t pg_b, + svuint32_t offsets_t, svbool_t pg_t, + Columns dst, svbool_t pg_dst); + void process_row(size_t width, Columns mapxy, Columns dst) { svuint32_t offsets_b, offsets_t; @@ -53,9 +55,14 @@ class RemapS16 { svmax_x(pg, svzero, svmin_x(pg, svget2(xy, 0), v_xmax_))); svuint16_t y = svreinterpret_u16_s16( svmax_x(pg, svzero, svmin_x(pg, svget2(xy, 1), v_ymax_))); - // Calculate offsets from coordinates (y * stride + x) - offsets_b = svmlalb_u32(svmovlb_u32(x), y, v_src_stride_); - offsets_t = svmlalt_u32(svmovlt_u32(x), y, v_src_stride_); + // Calculate offsets from coordinates (y * stride/sizeof(ScalarType) + x) + offsets_b = svmlalb_u32(svmovlb_u32(x), y, v_src_element_stride); + offsets_t = svmlalt_u32(svmovlt_u32(x), y, v_src_element_stride); + // Account for the size of the source type when calculating offset + if constexpr (std::is_same::value) { + offsets_b = svlsl_n_u32_x(pg, offsets_b, 1); + offsets_t = svlsl_n_u32_x(pg, offsets_t, 1); + } }; svbool_t pg_all16 = MapVecTraits::svptrue(); @@ -65,14 +72,7 @@ class RemapS16 { load_offsets(pg); svbool_t pg_b = svwhilelt_b32(int64_t{0}, (step + 1) / 2); svbool_t pg_t = svwhilelt_b32(int64_t{0}, step / 2); - // Copy pixels from source - svuint32_t result_b = - svldnt1ub_gather_u32offset_u32(pg_b, &src_rows_[0], offsets_b); - svuint32_t result_t = - svldnt1ub_gather_u32offset_u32(pg_t, &src_rows_[0], offsets_t); - svuint16_t result = svtrn1_u16(svreinterpret_u16_u32(result_b), - svreinterpret_u16_u32(result_t)); - svst1b_u16(pg, &dst[0], result); + transform_pixels(offsets_b, pg_b, offsets_t, pg_t, dst, pg); mapxy += step; dst += step; }; @@ -80,14 +80,7 @@ class RemapS16 { // NOTE: gather load is not available in streaming mode auto gather_load_full_vector_path = [&](ptrdiff_t step) { load_offsets(pg_all16); - // Copy pixels from source - svuint32_t result_b = - svldnt1ub_gather_u32offset_u32(pg_all32, &src_rows_[0], offsets_b); - svuint32_t result_t = - svldnt1ub_gather_u32offset_u32(pg_all32, &src_rows_[0], offsets_t); - svuint16_t result = svtrn1_u16(svreinterpret_u16_u32(result_b), - svreinterpret_u16_u32(result_t)); - svst1b_u16(pg_all16, &dst[0], result); + transform_pixels(offsets_b, pg_all32, offsets_t, pg_all32, dst, pg_all16); mapxy += step; dst += step; }; @@ -104,10 +97,40 @@ class RemapS16 { private: Rows src_rows_; - svuint16_t& v_src_stride_; + svuint16_t& v_src_element_stride; MapVectorType& v_xmax_; MapVectorType& v_ymax_; -}; // end of class RemapS16 +}; // end of class RemapS16 + +template <> +void RemapS16::transform_pixels(svuint32_t offsets_b, svbool_t pg_b, + svuint32_t offsets_t, svbool_t pg_t, + Columns dst, + svbool_t pg_dst) { + // Copy pixels from source + svuint32_t result_b = + svld1ub_gather_u32offset_u32(pg_b, &src_rows_[0], offsets_b); + svuint32_t result_t = + svld1ub_gather_u32offset_u32(pg_t, &src_rows_[0], offsets_t); + svuint16_t result = svtrn1_u16(svreinterpret_u16_u32(result_b), + svreinterpret_u16_u32(result_t)); + svst1b_u16(pg_dst, &dst[0], result); +} + +template <> +void RemapS16::transform_pixels(svuint32_t offsets_b, svbool_t pg_b, + svuint32_t offsets_t, svbool_t pg_t, + Columns dst, + svbool_t pg_dst) { + // Copy pixels from source + svuint32_t result_b = + svld1uh_gather_u32offset_u32(pg_b, &src_rows_[0], offsets_b); + svuint32_t result_t = + svld1uh_gather_u32offset_u32(pg_t, &src_rows_[0], offsets_t); + svuint16_t result = svtrn1_u16(svreinterpret_u16_u32(result_b), + svreinterpret_u16_u32(result_t)); + svst1_u16(pg_dst, &dst[0], result); +} template kleidicv_error_t remap_s16_sc(const T* src, size_t src_stride, size_t src_width, diff --git a/kleidicv/src/transform/remap_sve2.cpp b/kleidicv/src/transform/remap_sve2.cpp index f71f2fb93..ff5b80583 100644 --- a/kleidicv/src/transform/remap_sve2.cpp +++ b/kleidicv/src/transform/remap_sve2.cpp @@ -13,9 +13,9 @@ kleidicv_error_t remap_s16(const T *src, size_t src_stride, size_t src_width, const int16_t *mapxy, size_t mapxy_stride, kleidicv_border_type_t border_type, const T *border_value) { - return remap_s16_sc(src, src_stride, src_width, src_height, dst, - dst_stride, dst_width, dst_height, channels, - mapxy, mapxy_stride, border_type, border_value); + return remap_s16_sc(src, src_stride, src_width, src_height, dst, + dst_stride, dst_width, dst_height, channels, mapxy, + mapxy_stride, border_type, border_value); } template @@ -41,6 +41,7 @@ kleidicv_error_t remap_s16point5(const T *src, size_t src_stride, kleidicv_border_type_t border_type, const type *border_value) KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16(uint8_t); +KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16(uint16_t); #define KLEIDICV_INSTANTIATE_TEMPLATE_REMAP_S16Point5(type) \ template KLEIDICV_TARGET_FN_ATTRS kleidicv_error_t remap_s16point5( \ diff --git a/kleidicv_thread/include/kleidicv_thread/kleidicv_thread.h b/kleidicv_thread/include/kleidicv_thread/kleidicv_thread.h index 0bd45c7b1..7ae5628f4 100644 --- a/kleidicv_thread/include/kleidicv_thread/kleidicv_thread.h +++ b/kleidicv_thread/include/kleidicv_thread/kleidicv_thread.h @@ -393,6 +393,17 @@ kleidicv_error_t kleidicv_thread_remap_s16_u8( kleidicv_border_type_t border_type, const uint8_t *border_value, kleidicv_thread_multithreading); +/// Internal - not part of the public API and its direct use is not supported. +/// +/// Multithreaded implementation of kleidicv_remap_s16_u16 - see the +/// documentation of that function for more details. +kleidicv_error_t kleidicv_thread_remap_s16_u16( + const uint16_t *src, size_t src_stride, size_t src_width, size_t src_height, + uint16_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height, + size_t channels, const int16_t *mapxy, size_t mapxy_stride, + kleidicv_border_type_t border_type, const uint16_t *border_value, + kleidicv_thread_multithreading); + /// Internal - not part of the public API and its direct use is not supported. /// /// Multithreaded implementation of kleidicv_remap_s16point5_u8 - see the diff --git a/kleidicv_thread/src/kleidicv_thread.cpp b/kleidicv_thread/src/kleidicv_thread.cpp index d4ce0b8c6..b2f37c7d2 100644 --- a/kleidicv_thread/src/kleidicv_thread.cpp +++ b/kleidicv_thread/src/kleidicv_thread.cpp @@ -677,6 +677,27 @@ kleidicv_error_t kleidicv_thread_remap_s16_u8( return parallel_batches(callback, mt, dst_height); } +kleidicv_error_t kleidicv_thread_remap_s16_u16( + const uint16_t *src, size_t src_stride, size_t src_width, size_t src_height, + uint16_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height, + size_t channels, const int16_t *mapxy, size_t mapxy_stride, + kleidicv_border_type_t border_type, const uint16_t *border_value, + kleidicv_thread_multithreading mt) { + if (!kleidicv::remap_s16_is_implemented(src_stride, src_width, + src_height, dst_width, + border_type, channels)) { + return KLEIDICV_ERROR_NOT_IMPLEMENTED; + } + auto callback = [=](unsigned begin, unsigned end) { + return kleidicv_remap_s16_u16( + src, src_stride, src_width, src_height, + dst + begin * dst_stride / sizeof(uint16_t), dst_stride, dst_width, + end - begin, channels, mapxy + begin * mapxy_stride / sizeof(int16_t), + mapxy_stride, border_type, border_value); + }; + return parallel_batches(callback, mt, dst_height); +} + kleidicv_error_t kleidicv_thread_remap_s16point5_u8( const uint8_t *src, size_t src_stride, size_t src_width, size_t src_height, uint8_t *dst, size_t dst_stride, size_t dst_width, size_t dst_height, diff --git a/scripts/benchmark/benchmarks.txt b/scripts/benchmark/benchmarks.txt index c3bde40f5..601720b43 100755 --- a/scripts/benchmark/benchmarks.txt +++ b/scripts/benchmark/benchmarks.txt @@ -79,6 +79,7 @@ InRange_U8: opencv_perf_core '*inRangeScalar/*' '($PIXEL_FORMAT, 8UC1, 1, 2)' InRange_F32: opencv_perf_core '*inRangeScalar/*' '($PIXEL_FORMAT, 32FC1, 1, 2)' Remap_S16_U8: opencv_perf_imgproc '*Remap/*' '($PIXEL_FORMAT, 8UC1, 16SC2, INTER_NEAREST, BORDER_REPLICATE)' +Remap_S16_U16: opencv_perf_imgproc '*Remap/*' '($PIXEL_FORMAT, 16UC1, 16SC2, INTER_NEAREST, BORDER_REPLICATE)' Remap_S16Point5_U8: opencv_perf_imgproc '*Remap/*' '($PIXEL_FORMAT, 8UC1, 16SC2, INTER_LINEAR, BORDER_REPLICATE)' WarpPerspective_Nearest: opencv_perf_imgproc '*WarpPerspective/*' '($PIXEL_FORMAT, INTER_NEAREST, BORDER_REPLICATE, 8UC1)' WarpPerspectiveNear_Nearest: opencv_perf_imgproc '*WarpPerspectiveNear/*' '($PIXEL_FORMAT, INTER_NEAREST, BORDER_REPLICATE, 8UC1)' diff --git a/test/api/test_remap.cpp b/test/api/test_remap.cpp index af585df00..c6ffdbf33 100644 --- a/test/api/test_remap.cpp +++ b/test/api/test_remap.cpp @@ -10,6 +10,12 @@ #include "kleidicv/ctypes.h" #include "kleidicv/kleidicv.h" +#define KLEIDICV_REMAP_S16(type, type_suffix) \ + KLEIDICV_API(remap_s16, kleidicv_remap_s16_##type_suffix, type) + +KLEIDICV_REMAP_S16(uint8_t, u8); +KLEIDICV_REMAP_S16(uint16_t, u16); + template class RemapS16 : public testing::Test { public: @@ -96,7 +102,7 @@ class RemapS16 : public testing::Test { calculate_expected(source, mapxy, expected); ASSERT_EQ(KLEIDICV_OK, - kleidicv_remap_s16_u8( + remap_s16()( source.data(), source.stride(), source.width(), source.height(), actual.data(), actual.stride(), actual.width(), actual.height(), channels, mapxy.data(), @@ -124,7 +130,7 @@ class RemapS16 : public testing::Test { calculate_expected(source, mapxy, expected); ASSERT_EQ(KLEIDICV_OK, - kleidicv_remap_s16_u8( + remap_s16()( source.data(), source.stride(), source.width(), source.height(), actual.data(), actual.stride(), actual.width(), actual.height(), channels, mapxy.data(), @@ -153,7 +159,7 @@ class RemapS16 : public testing::Test { } }; -using RemapElementTypes = ::testing::Types; +using RemapElementTypes = ::testing::Types; TYPED_TEST_SUITE(RemapS16, RemapElementTypes); TYPED_TEST(RemapS16, RandomNoPadding) { @@ -161,7 +167,9 @@ TYPED_TEST(RemapS16, RandomNoPadding) { size_t src_h = 4; size_t dst_w = src_w; size_t dst_h = src_h; - TestFixture::test_random(src_w, src_h, dst_w, dst_h, 1, 0); + size_t channels = 1; + size_t padding = 0; + TestFixture::test_random(src_w, src_h, dst_w, dst_h, channels, padding); } TYPED_TEST(RemapS16, OutsideRandomPadding) { @@ -169,7 +177,10 @@ TYPED_TEST(RemapS16, OutsideRandomPadding) { size_t src_h = 4; size_t dst_w = src_w; size_t dst_h = src_h; - TestFixture::test_outside_random(src_w, src_h, dst_w, dst_h, 1, 13); + size_t channels = 1; + size_t padding = 13; + TestFixture::test_outside_random(src_w, src_h, dst_w, dst_h, channels, + padding); } TYPED_TEST(RemapS16, BlendPadding) { @@ -177,7 +188,9 @@ TYPED_TEST(RemapS16, BlendPadding) { size_t src_h = 4; size_t dst_w = src_w; size_t dst_h = src_h; - TestFixture::test_blend(src_w, src_h, dst_w, dst_h, 1, 13); + size_t channels = 1; + size_t padding = 13; + TestFixture::test_blend(src_w, src_h, dst_w, dst_h, channels, padding); } TYPED_TEST(RemapS16, BlendBigStride) { @@ -185,23 +198,28 @@ TYPED_TEST(RemapS16, BlendBigStride) { size_t src_h = 16; size_t dst_w = src_w; size_t dst_h = src_h; - TestFixture::test_blend(src_w, src_h, dst_w, dst_h, 1, (1 << 16) - src_w - 1); + size_t channels = 1; + size_t padding = std::numeric_limits::max() - src_w; + TestFixture::test_blend(src_w, src_h, dst_w, dst_h, channels, padding); } TYPED_TEST(RemapS16, CornerCases) { - size_t src_w = std::numeric_limits::max() + 1; - size_t src_h = std::numeric_limits::max() + 1; - size_t dst_w = 3 * test::Options::vector_lanes() - 1; - size_t dst_h = 4; - TestFixture::test_corner_cases(src_w, src_h, dst_w, dst_h, 1, 17); + size_t src_w = 3 * test::Options::vector_lanes() - 1; + size_t src_h = 4; + size_t dst_w = src_w; + size_t dst_h = src_h; + size_t channels = 1; + size_t padding = 17; + TestFixture::test_corner_cases(src_w, src_h, dst_w, dst_h, channels, padding); } TYPED_TEST(RemapS16, NullPointer) { const TypeParam src[4] = {}; TypeParam dst[1]; int16_t mapxy[2] = {}; - test::test_null_args(kleidicv_remap_s16_u8, src, 2, 2, 2, dst, 1, 1, 1, 1, - mapxy, 4, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr); + test::test_null_args(remap_s16(), src, 2 * sizeof(TypeParam), 2, 2, + dst, 1 * sizeof(TypeParam), 1, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr); } TYPED_TEST(RemapS16, ZeroImageSize) { @@ -210,11 +228,12 @@ TYPED_TEST(RemapS16, ZeroImageSize) { int16_t mapxy[2] = {}; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 1, 0, 1, dst, 1, 0, 1, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()(src, 0, 0, 1, dst, 0, 0, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 1, 1, 0, dst, 1, 1, 0, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()(src, 1 * sizeof(TypeParam), 1, 0, dst, + 1 * sizeof(TypeParam), 1, 0, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); } TYPED_TEST(RemapS16, InvalidImageSize) { @@ -223,35 +242,43 @@ TYPED_TEST(RemapS16, InvalidImageSize) { int16_t mapxy[16] = {}; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8( - src, 1, std::numeric_limits::max() + 2, 1, dst, 8, 8, - 1, 1, mapxy, 4, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()(src, 1 * sizeof(TypeParam), + std::numeric_limits::max() + 2, 1, + dst, 8, 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8( - src, 1, 1, std::numeric_limits::max() + 2, dst, 8, 8, + remap_s16()(src, 1 * sizeof(TypeParam), 1, + std::numeric_limits::max() + 2, dst, + 8, 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + + EXPECT_EQ(KLEIDICV_ERROR_RANGE, + remap_s16()( + src, (KLEIDICV_MAX_IMAGE_PIXELS + 1) * sizeof(TypeParam), + KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, dst, 8 * sizeof(TypeParam), 8, 1, 1, mapxy, 4, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, - kleidicv_remap_s16_u8(src, 1, KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, dst, - 8, 8, 1, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); - EXPECT_EQ( - KLEIDICV_ERROR_RANGE, - kleidicv_remap_s16_u8(src, 1, KLEIDICV_MAX_IMAGE_PIXELS, - KLEIDICV_MAX_IMAGE_PIXELS, dst, 8, 8, 1, 1, mapxy, - 4, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()( + src, KLEIDICV_MAX_IMAGE_PIXELS * sizeof(TypeParam), + KLEIDICV_MAX_IMAGE_PIXELS, KLEIDICV_MAX_IMAGE_PIXELS, dst, + 8 * sizeof(TypeParam), 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); EXPECT_EQ(KLEIDICV_ERROR_RANGE, - kleidicv_remap_s16_u8(src, 1, 1, 1, dst, 1, - KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()( + src, 1 * sizeof(TypeParam), 1, 1, dst, + (KLEIDICV_MAX_IMAGE_PIXELS + 1) * sizeof(TypeParam), + KLEIDICV_MAX_IMAGE_PIXELS + 1, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); - EXPECT_EQ( - KLEIDICV_ERROR_RANGE, - kleidicv_remap_s16_u8(src, 1, 1, 1, dst, 1, KLEIDICV_MAX_IMAGE_PIXELS, - KLEIDICV_MAX_IMAGE_PIXELS, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + EXPECT_EQ(KLEIDICV_ERROR_RANGE, + remap_s16()( + src, 1 * sizeof(TypeParam), 1, 1, dst, + KLEIDICV_MAX_IMAGE_PIXELS * sizeof(TypeParam), + KLEIDICV_MAX_IMAGE_PIXELS, KLEIDICV_MAX_IMAGE_PIXELS, 1, mapxy, + 4, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); } TYPED_TEST(RemapS16, UnsupportedBigStride) { @@ -261,8 +288,16 @@ TYPED_TEST(RemapS16, UnsupportedBigStride) { EXPECT_EQ( KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 2 << 16, 1, 1, dst, 2 << 16, 8, 1, 2, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()( + src, (std::numeric_limits::max() + 1) * sizeof(TypeParam), + 1, 1, dst, 8 * sizeof(TypeParam), 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + + EXPECT_EQ(KLEIDICV_OK, + remap_s16()( + src, std::numeric_limits::max() * sizeof(TypeParam), + 1, 1, dst, 8 * sizeof(TypeParam), 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); } TYPED_TEST(RemapS16, UnsupportedTwoChannels) { @@ -271,8 +306,9 @@ TYPED_TEST(RemapS16, UnsupportedTwoChannels) { int16_t mapxy[16] = {}; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 1, 1, 1, dst, 8, 8, 1, 2, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()(src, 1 * sizeof(TypeParam), 1, 1, dst, + 8 * sizeof(TypeParam), 8, 1, 2, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); } TYPED_TEST(RemapS16, UnsupportedBorderTypeConst) { @@ -281,8 +317,9 @@ TYPED_TEST(RemapS16, UnsupportedBorderTypeConst) { int16_t mapxy[16] = {}; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 1, 1, 1, dst, 8, 8, 1, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_CONSTANT, src)); + remap_s16()(src, 1 * sizeof(TypeParam), 1, 1, dst, + 8 * sizeof(TypeParam), 8, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_CONSTANT, nullptr)); } TYPED_TEST(RemapS16, UnsupportedTooSmallImage) { @@ -291,8 +328,9 @@ TYPED_TEST(RemapS16, UnsupportedTooSmallImage) { int16_t mapxy[16] = {}; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_remap_s16_u8(src, 1, 1, 1, dst, 8, 7, 1, 1, mapxy, 4, - KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); + remap_s16()(src, 1 * sizeof(TypeParam), 1, 1, dst, + 7 * sizeof(TypeParam), 7, 1, 1, mapxy, 4, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr)); } template @@ -525,7 +563,9 @@ TYPED_TEST(RemapS16Point5, BlendBigStride) { size_t src_h = 16; size_t dst_w = src_w; size_t dst_h = src_h; - TestFixture::test_blend(src_w, src_h, dst_w, dst_h, 1, (1 << 16) - src_w - 1); + size_t channels = 1; + size_t padding = std::numeric_limits::max() - src_w; + TestFixture::test_blend(src_w, src_h, dst_w, dst_h, channels, padding); } TYPED_TEST(RemapS16Point5, CornerCases) { diff --git a/test/api/test_thread.cpp b/test/api/test_thread.cpp index 6f09b8855..862f0229d 100644 --- a/test/api/test_thread.cpp +++ b/test/api/test_thread.cpp @@ -603,6 +603,12 @@ TEST_P(Thread, remap_s16_u8_border_replicate) { 1, KLEIDICV_BORDER_TYPE_REPLICATE, nullptr); } +TEST_P(Thread, remap_s16_u16_border_replicate) { + check_remap_s16(kleidicv_remap_s16_u16, + kleidicv_thread_remap_s16_u16, 1, + KLEIDICV_BORDER_TYPE_REPLICATE, nullptr); +} + TEST_P(Thread, remap_s16_u8_not_implemented) { const uint8_t border_value[4] = {}; check_remap_s16_not_implemented(kleidicv_thread_remap_s16_u8, 2, @@ -613,6 +619,14 @@ TEST_P(Thread, remap_s16_u8_not_implemented) { border_value); } +TEST_P(Thread, remap_s16_u16_not_implemented) { + check_remap_s16_not_implemented(kleidicv_thread_remap_s16_u16, 2, + KLEIDICV_BORDER_TYPE_REPLICATE, + nullptr); + check_remap_s16_not_implemented( + kleidicv_thread_remap_s16_u16, 1, KLEIDICV_BORDER_TYPE_CONSTANT, nullptr); +} + TEST_P(Thread, remap_s16point5_u8_border_replicate) { check_remap_s16point5(kleidicv_remap_s16point5_u8, kleidicv_thread_remap_s16point5_u8, 1, diff --git a/test/api/test_warp_perspective.cpp b/test/api/test_warp_perspective.cpp index b7b81ba38..49cd9a674 100644 --- a/test/api/test_warp_perspective.cpp +++ b/test/api/test_warp_perspective.cpp @@ -470,10 +470,10 @@ TYPED_TEST(WarpPerspectiveNearest, UnsupportedBorderTypeConst) { TypeParam dst[8]; EXPECT_EQ(KLEIDICV_ERROR_NOT_IMPLEMENTED, - kleidicv_warp_perspective_u8(src, 1, 1, 1, dst, 8, 8, 1, - transform_identity, 1, - KLEIDICV_INTERPOLATION_NEAREST, - KLEIDICV_BORDER_TYPE_CONSTANT, src)); + kleidicv_warp_perspective_u8( + src, 1, 1, 1, dst, 8, 8, 1, transform_identity, 1, + KLEIDICV_INTERPOLATION_NEAREST, KLEIDICV_BORDER_TYPE_CONSTANT, + nullptr)); } TYPED_TEST(WarpPerspectiveNearest, UnsupportedTooSmallImage) { -- GitLab