From 2e909c38dcd0ff4d13499114101cde619c6cca56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A9=E9=9F=B3=E3=81=82=E3=82=81?= Date: Fri, 7 Feb 2025 00:34:54 +0800 Subject: [PATCH] Merge pull request #26804 from amane-ame:norm_hal_rvv Add RISC-V HAL implementation for cv::norm and cv::normalize #26804 This patch implements `cv::norm` with norm types `NORM_INF/NORM_L1/NORM_L2/NORM_L2SQR` and `Mat::convertTo` function in RVV_HAL using native intrinsic, optimizing the performance for `cv::norm(src)`, `cv::norm(src1, src2)`, and `cv::normalize(src)` with data types `8UC1/8UC4/32FC1`. `cv::normalize` also calls `minMaxIdx`, #26789 implements RVV_HAL for this. Tested on MUSE-PI for both gcc 14.2 and clang 20.0. ``` $ opencv_test_core --gtest_filter="*Norm*" $ opencv_perf_core --gtest_filter="*norm*" --perf_min_samples=300 --perf_force_samples=300 ``` The head of the perf table is shown below since the table is too long. View the full perf table here: [hal_rvv_norm.pdf](https://github.com/user-attachments/files/18468255/hal_rvv_norm.pdf) Untitled ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [ ] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [ ] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [ ] The feature is well documented and sample code can be built with the project CMake --- 3rdparty/hal_rvv/hal_rvv.hpp | 3 + .../hal_rvv/hal_rvv_1p0/convert_scale.hpp | 120 ++++ 3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp | 517 +++++++++++++++ 3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp | 605 ++++++++++++++++++ modules/core/src/convert.dispatch.cpp | 9 + modules/core/src/hal_replacement.hpp | 60 ++ modules/core/src/norm.cpp | 29 +- 7 files changed, 1339 insertions(+), 4 deletions(-) create mode 100644 3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp create mode 100644 3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp create mode 100644 3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp diff --git a/3rdparty/hal_rvv/hal_rvv.hpp b/3rdparty/hal_rvv/hal_rvv.hpp index 8278ca946e..0ff9c3530e 100644 --- a/3rdparty/hal_rvv/hal_rvv.hpp +++ b/3rdparty/hal_rvv/hal_rvv.hpp @@ -22,6 +22,9 @@ #if defined(__riscv_v) && __riscv_v == 1000000 #include "hal_rvv_1p0/merge.hpp" // core #include "hal_rvv_1p0/mean.hpp" // core +#include "hal_rvv_1p0/norm.hpp" // core +#include "hal_rvv_1p0/norm_diff.hpp" // core +#include "hal_rvv_1p0/convert_scale.hpp" // core #include "hal_rvv_1p0/minmax.hpp" // core #include "hal_rvv_1p0/atan.hpp" // core #endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp new file mode 100644 index 0000000000..3a779f5cb3 --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/convert_scale.hpp @@ -0,0 +1,120 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_CONVERT_SCALE_HPP_INCLUDED +#define OPENCV_HAL_RVV_CONVERT_SCALE_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_convertScale +#define cv_hal_convertScale cv::cv_hal_rvv::convertScale + +inline int convertScale_8U8U(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + uchar* dst_row = dst + i * dst_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl); + auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl); + auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl); + auto vec_dst_u16 = __riscv_vfncvt_xu(vec_fma, vl); + auto vec_dst = __riscv_vnclipu(vec_dst_u16, 0, __RISCV_VXRM_RNU, vl); + __riscv_vse8_v_u8m2(dst_row + j, vec_dst, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale_8U32F(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + float* dst_row = reinterpret_cast(dst + i * dst_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_src_u16 = __riscv_vzext_vf2(vec_src, vl); + auto vec_src_f32 = __riscv_vfwcvt_f(vec_src_u16, vl); + auto vec_fma = __riscv_vfmadd(vec_src_f32, a, vec_b, vl); + __riscv_vse32_v_f32m8(dst_row + j, vec_fma, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale_32F32F(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, double alpha, double beta) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_b = __riscv_vfmv_v_f_f32m8(beta, vlmax); + float a = alpha; + + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + float* dst_row = reinterpret_cast(dst + i * dst_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_fma = __riscv_vfmadd(vec_src, a, vec_b, vl); + __riscv_vse32_v_f32m8(dst_row + j, vec_fma, vl); + } + } + + return CV_HAL_ERROR_OK; +} + +inline int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, + int sdepth, int ddepth, double alpha, double beta) +{ + if (!dst) + return CV_HAL_ERROR_OK; + + switch (sdepth) + { + case CV_8U: + switch (ddepth) + { + case CV_8U: + return convertScale_8U8U(src, src_step, dst, dst_step, width, height, alpha, beta); + case CV_32F: + return convertScale_8U32F(src, src_step, dst, dst_step, width, height, alpha, beta); + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_32F: + switch (ddepth) + { + case CV_32F: + return convertScale_32F32F(src, src_step, dst, dst_step, width, height, alpha, beta); + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp new file mode 100644 index 0000000000..e53b9d4391 --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/norm.hpp @@ -0,0 +1,517 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_NORM_HPP_INCLUDED +#define OPENCV_HAL_RVV_NORM_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_norm +#define cv_hal_norm cv::cv_hal_rvv::norm + +inline int normInf_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m8(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + vec_max = __riscv_vmaxu_tumu(bool_mask, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_8UC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normInf_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + vlm = __riscv_vsetvl_e8m2(width - jm); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m8(vec_mask_ext), 0, vl); + vec_max = __riscv_vmaxu_tumu(bool_mask_ext, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + auto vec_src = __riscv_vle8_v_u8m8(src_row + j, vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask_ext, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_8UC4(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask_ext, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask_ext, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src_row = src + i * src_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + reduce(vl); + + auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normInf_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_max = __riscv_vfmv_v_f_f32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_abs = __riscv_vfabs_v_f32m8_m(bool_mask, vec_src, vl); + vec_max = __riscv_vfmax_tumu(bool_mask, vec_max, vec_max, vec_abs, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src = __riscv_vle32_v_f32m8(src_row + j, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + vec_max = __riscv_vfmax_tu(vec_max, vec_max, vec_abs, vl); + } + } + } + auto sc_max = __riscv_vfmv_s_f_f32m1(0, vlmax); + sc_max = __riscv_vfredmax(vec_max, sc_max, vlmax); + *result = __riscv_vfmv_f(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normL1_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_abs = __riscv_vfabs_v_f32m4_m(bool_mask, vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8_m(bool_mask, vec_abs, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_fext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8(vec_abs, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_fext, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normL2Sqr_32FC1(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_mul = __riscv_vfwmul_vv_f64m8_m(bool_mask, vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_mul, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src_row = reinterpret_cast(src + i * src_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src = __riscv_vle32_v_f32m4(src_row + j, vl); + auto vec_mul = __riscv_vfwmul(vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_mul, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int norm(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, + int height, int type, int norm_type, double* result) +{ + if (!result) + return CV_HAL_ERROR_OK; + + switch (type) + { + case CV_8UC1: + switch (norm_type) + { + case NORM_INF: + return normInf_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_8UC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_8UC1(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_8UC4: + switch (norm_type) + { + case NORM_INF: + return normInf_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_8UC4(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_8UC4(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + case CV_32FC1: + switch (norm_type) + { + case NORM_INF: + return normInf_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L1: + return normL1_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2SQR: + return normL2Sqr_32FC1(src, src_step, mask, mask_step, width, height, result); + case NORM_L2: + int ret = normL2Sqr_32FC1(src, src_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + return ret; + } + return CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + return CV_HAL_ERROR_NOT_IMPLEMENTED; +} + +}} + +#endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp new file mode 100644 index 0000000000..6e4a9be65d --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/norm_diff.hpp @@ -0,0 +1,605 @@ +// This file is part of OpenCV project. +// It is subject to the license terms in the LICENSE file found in the top-level directory +// of this distribution and at http://opencv.org/license.html. +#ifndef OPENCV_HAL_RVV_NORM_DIFF_HPP_INCLUDED +#define OPENCV_HAL_RVV_NORM_DIFF_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +#undef cv_hal_normDiff +#define cv_hal_normDiff cv::cv_hal_rvv::normDiff + +inline int normDiffInf_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m8(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m8_m(bool_mask, __riscv_vmaxu_vv_u8m8_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m8_m(bool_mask, vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tumu(bool_mask, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m8(width - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask, __riscv_vmaxu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_8UC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask, __riscv_vmaxu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask, vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e8m2(width - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffInf_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m8(); + auto vec_max = __riscv_vmv_v_x_u8m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + vlm = __riscv_vsetvl_e8m2(width - jm); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m8(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m8_m(bool_mask_ext, __riscv_vmaxu_vv_u8m8_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m8_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tumu(bool_mask_ext, vec_max, vec_max, vec_src, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m8(width * 4 - j); + auto vec_src1 = __riscv_vle8_v_u8m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m8(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + vec_max = __riscv_vmaxu_tu(vec_max, vec_max, vec_src, vl); + } + } + } + auto sc_max = __riscv_vmv_s_x_u8m1(0, vlmax); + sc_max = __riscv_vredmaxu(vec_max, sc_max, vlmax); + *result = __riscv_vmv_x(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask_ext, __riscv_vmaxu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4_u32m8_m(bool_mask_ext, vec_src, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_zext = __riscv_vzext_vf4(vec_src, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + auto sc_sum = __riscv_vmv_s_x_u32m1(0, vlmax); + sc_sum = __riscv_vredsum(vec_sum, sc_sum, vlmax); + *result = __riscv_vmv_x(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_8UC4(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e8m2(); + auto vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + int cnt = 0; + auto reduce = [&](int vl) { + if ((cnt += vl) < (1 << 16)) + return; + cnt = vl; + for (int i = 0; i < vlmax; i++) + { + *result += __riscv_vmv_x(vec_sum); + vec_sum = __riscv_vslidedown(vec_sum, 1, vlmax); + } + vec_sum = __riscv_vmv_v_x_u32m8(0, vlmax); + }; + + *result = 0; + if (mask) + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + const uchar* mask_row = mask + i * mask_step; + int vl, vlm; + for (int j = 0, jm = 0; j < width * 4; j += vl, jm += vlm) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + vlm = __riscv_vsetvl_e8mf2(width - jm); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8mf2(mask_row + jm, vlm); + auto vec_mask_ext = __riscv_vmul(__riscv_vzext_vf4(__riscv_vminu(vec_mask, 1, vlm), vlm), 0x01010101, vlm); + auto bool_mask_ext = __riscv_vmsne(__riscv_vreinterpret_u8m2(vec_mask_ext), 0, vl); + auto vec_src = __riscv_vsub_vv_u8m2_m(bool_mask_ext, __riscv_vmaxu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), + __riscv_vminu_vv_u8m2_m(bool_mask_ext, vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu_vv_u16m4_m(bool_mask_ext, vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2_u32m8_m(bool_mask_ext, vec_mul, vl); + vec_sum = __riscv_vadd_tumu(bool_mask_ext, vec_sum, vec_sum, vec_zext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const uchar* src1_row = src1 + i * src1_step; + const uchar* src2_row = src2 + i * src2_step; + int vl; + for (int j = 0; j < width * 4; j += vl) + { + vl = __riscv_vsetvl_e8m2(width * 4 - j); + reduce(vl); + + auto vec_src1 = __riscv_vle8_v_u8m2(src1_row + j, vl); + auto vec_src2 = __riscv_vle8_v_u8m2(src2_row + j, vl); + auto vec_src = __riscv_vsub(__riscv_vmaxu(vec_src1, vec_src2, vl), __riscv_vminu(vec_src1, vec_src2, vl), vl); + auto vec_mul = __riscv_vwmulu(vec_src, vec_src, vl); + auto vec_zext = __riscv_vzext_vf2(vec_mul, vl); + vec_sum = __riscv_vadd_tu(vec_sum, vec_sum, vec_zext, vl); + } + } + } + reduce(1 << 16); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffInf_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m8(); + auto vec_max = __riscv_vfmv_v_f_f32m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src1 = __riscv_vle32_v_f32m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m8(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m2(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m8_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs_v_f32m8_m(bool_mask, vec_src, vl); + vec_max = __riscv_vfmax_tumu(bool_mask, vec_max, vec_max, vec_abs, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m8(width - j); + auto vec_src1 = __riscv_vle32_v_f32m8(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m8(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + vec_max = __riscv_vfmax_tu(vec_max, vec_max, vec_abs, vl); + } + } + } + auto sc_max = __riscv_vfmv_s_f_f32m1(0, vlmax); + sc_max = __riscv_vfredmax(vec_max, sc_max, vlmax); + *result = __riscv_vfmv_f(sc_max); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL1_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m4_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs_v_f32m4_m(bool_mask, vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8_m(bool_mask, vec_abs, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_fext, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_abs = __riscv_vfabs(vec_src, vl); + auto vec_fext = __riscv_vfwcvt_f_f_v_f64m8(vec_abs, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_fext, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiffL2Sqr_32FC1(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, size_t mask_step, int width, int height, double* result) +{ + int vlmax = __riscv_vsetvlmax_e32m4(); + auto vec_sum = __riscv_vfmv_v_f_f64m8(0, vlmax); + + if (mask) + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + const uchar* mask_row = mask + i * mask_step; + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_mask = __riscv_vle8_v_u8m1(mask_row + j, vl); + auto bool_mask = __riscv_vmsne(vec_mask, 0, vl); + auto vec_src = __riscv_vfsub_vv_f32m4_m(bool_mask, vec_src1, vec_src2, vl); + auto vec_mul = __riscv_vfwmul_vv_f64m8_m(bool_mask, vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tumu(bool_mask, vec_sum, vec_sum, vec_mul, vl); + } + } + } + else + { + for (int i = 0; i < height; i++) + { + const float* src1_row = reinterpret_cast(src1 + i * src1_step); + const float* src2_row = reinterpret_cast(src2 + i * src2_step); + int vl; + for (int j = 0; j < width; j += vl) + { + vl = __riscv_vsetvl_e32m4(width - j); + auto vec_src1 = __riscv_vle32_v_f32m4(src1_row + j, vl); + auto vec_src2 = __riscv_vle32_v_f32m4(src2_row + j, vl); + auto vec_src = __riscv_vfsub(vec_src1, vec_src2, vl); + auto vec_mul = __riscv_vfwmul(vec_src, vec_src, vl); + vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, vec_mul, vl); + } + } + } + auto sc_sum = __riscv_vfmv_s_f_f64m1(0, vlmax); + sc_sum = __riscv_vfredosum(vec_sum, sc_sum, vlmax); + *result = __riscv_vfmv_f(sc_sum); + + return CV_HAL_ERROR_OK; +} + +inline int normDiff(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, + size_t mask_step, int width, int height, int type, int norm_type, double* result) +{ + if (!result) + return CV_HAL_ERROR_OK; + + int ret; + switch (type) + { + case CV_8UC1: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_8UC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + case CV_8UC4: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_8UC4(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + case CV_32FC1: + switch (norm_type & ~NORM_RELATIVE) + { + case NORM_INF: + ret = normDiffInf_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L1: + ret = normDiffL1_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2SQR: + ret = normDiffL2Sqr_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + break; + case NORM_L2: + ret = normDiffL2Sqr_32FC1(src1, src1_step, src2, src2_step, mask, mask_step, width, height, result); + *result = std::sqrt(*result); + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + break; + default: + ret = CV_HAL_ERROR_NOT_IMPLEMENTED; + } + + if(ret == CV_HAL_ERROR_OK && (norm_type & NORM_RELATIVE)) + { + double result_; + ret = cv::cv_hal_rvv::norm(src2, src2_step, mask, mask_step, width, height, type, norm_type & ~NORM_RELATIVE, &result_); + if(ret == CV_HAL_ERROR_OK) + { + *result /= result_ + DBL_EPSILON; + } + } + + return ret; +} + +}} + +#endif diff --git a/modules/core/src/convert.dispatch.cpp b/modules/core/src/convert.dispatch.cpp index 2b4035285f..a33708a557 100644 --- a/modules/core/src/convert.dispatch.cpp +++ b/modules/core/src/convert.dispatch.cpp @@ -281,6 +281,15 @@ void Mat::convertTo(OutputArray dst, int type_, double alpha, double beta) const dst.create(dims, size, dtype); Mat dstMat = dst.getMat(); + if( dims <= 2 ) + { + CALL_HAL(convertScale, cv_hal_convertScale, src.data, src.step, dstMat.data, dstMat.step, src.cols * cn, src.rows, sdepth, ddepth, alpha, beta); + } + else if( src.isContinuous() && dstMat.isContinuous() ) + { + CALL_HAL(convertScale, cv_hal_convertScale, src.data, 0, dstMat.data, 0, (int)src.total() * cn, 1, sdepth, ddepth, alpha, beta); + } + BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth); double scale[] = {alpha, beta}; CV_Assert( func != 0 ); diff --git a/modules/core/src/hal_replacement.hpp b/modules/core/src/hal_replacement.hpp index d435db52f6..a0efad43ca 100644 --- a/modules/core/src/hal_replacement.hpp +++ b/modules/core/src/hal_replacement.hpp @@ -307,9 +307,69 @@ Hamming distance between two vectors inline int hal_ni_normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } //! @} +/** +@brief Generic norm of an array. +@param src Source image +@param src_step Source image +@param mask Specified array region. +@param mask_step Mask array step. +@param width Source image dimensions +@param height Source image dimensions +@param type Element type of source image +@param norm_type Type of the norm +@param result Pointer to result output +*/ +//! @addtogroup core_hal_interface_norm Absolute norm +//! @{ +inline int hal_ni_norm(const uchar* src, size_t src_step, const uchar* mask, size_t mask_step, int width, + int height, int type, int norm_type, double* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +/** +@brief Generic norm between two arrays. +@param src1 First source image +@param src1_step First source image +@param src2 Second source image +@param src2_step Second source image +@param mask Specified array region. +@param mask_step Mask array step. +@param width Source image dimensions +@param height Source image dimensions +@param type Element type of source image +@param norm_type Type of the norm +@param result Pointer to result output +*/ +//! @addtogroup core_hal_interface_norm Absolute norm +//! @{ +inline int hal_ni_normDiff(const uchar* src1, size_t src1_step, const uchar* src2, size_t src2_step, const uchar* mask, + size_t mask_step, int width, int height, int type, int norm_type, double* result) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + +/** +@brief Convert array to another with specified type. +@param src Source image +@param src_step Source image +@param dst Destination image +@param dst_step Destination image +@param width Source image dimensions +@param height Source image dimensions +@param sdepth Depth of source image +@param ddepth Depth of destination image +@param alpha Scale value +@param beta Shift value +*/ +//! @addtogroup core_hal_interface_convert Array convert +//! @{ +inline int hal_ni_convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step, int width, int height, + int sdepth, int ddepth, double alpha, double beta) { return CV_HAL_ERROR_NOT_IMPLEMENTED; } +//! @} + //! @cond IGNORED #define cv_hal_normHamming8u hal_ni_normHamming8u #define cv_hal_normHammingDiff8u hal_ni_normHammingDiff8u +#define cv_hal_norm hal_ni_norm +#define cv_hal_normDiff hal_ni_normDiff +#define cv_hal_convertScale hal_ni_convertScale //! @endcond /** diff --git a/modules/core/src/norm.cpp b/modules/core/src/norm.cpp index d6875be833..0452e40a55 100644 --- a/modules/core/src/norm.cpp +++ b/modules/core/src/norm.cpp @@ -623,9 +623,20 @@ double norm( InputArray _src, int normType, InputArray _mask ) #endif Mat src = _src.getMat(), mask = _mask.getMat(); + int depth = src.depth(), cn = src.channels(); + if( src.dims <= 2 ) + { + double result; + CALL_HAL_RET(norm, cv_hal_norm, result, src.data, src.step, mask.data, mask.step, src.cols, src.rows, src.type(), normType); + } + else if( src.isContinuous() && mask.isContinuous() ) + { + double result; + CALL_HAL_RET(norm, cv_hal_norm, result, src.data, 0, mask.data, 0, (int)src.total(), 1, src.type(), normType); + } + CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_norm(src, normType, mask, _result), _result); - int depth = src.depth(), cn = src.channels(); if( src.isContinuous() && mask.empty() ) { size_t len = src.total()*cn; @@ -1108,6 +1119,19 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask _result) #endif + Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); + int depth = src1.depth(), cn = src1.channels(); + if( src1.dims <= 2 ) + { + double result; + CALL_HAL_RET(normDiff, cv_hal_normDiff, result, src1.data, src1.step, src2.data, src2.step, mask.data, mask.step, src1.cols, src1.rows, src1.type(), normType); + } + else if( src1.isContinuous() && src2.isContinuous() && mask.isContinuous() ) + { + double result; + CALL_HAL_RET(normDiff, cv_hal_normDiff, result, src1.data, 0, src2.data, 0, mask.data, 0, (int)src1.total(), 1, src1.type(), normType); + } + CV_IPP_RUN(IPP_VERSION_X100 >= 700, ipp_norm(_src1, _src2, normType, _mask, _result), _result); if( normType & CV_RELATIVE ) @@ -1115,9 +1139,6 @@ double norm( InputArray _src1, InputArray _src2, int normType, InputArray _mask return norm(_src1, _src2, normType & ~CV_RELATIVE, _mask)/(norm(_src2, normType, _mask) + DBL_EPSILON); } - Mat src1 = _src1.getMat(), src2 = _src2.getMat(), mask = _mask.getMat(); - int depth = src1.depth(), cn = src1.channels(); - normType &= 7; CV_Assert( normType == NORM_INF || normType == NORM_L1 || normType == NORM_L2 || normType == NORM_L2SQR ||