1
0
mirror of https://github.com/opencv/opencv.git synced 2026-07-31 00:03:03 +04:00

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)

<img width="1304" alt="Untitled" src="https://github.com/user-attachments/assets/3550b671-6d96-4db3-8b5b-d4cb241da650" />

### 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
This commit is contained in:
天音あめ
2025-02-07 00:34:54 +08:00
committed by GitHub
parent 01e3fe8791
commit 2e909c38dc
7 changed files with 1339 additions and 4 deletions
+3
View File
@@ -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
+120
View File
@@ -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 <riscv_vector.h>
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<float*>(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<const float*>(src + i * src_step);
float* dst_row = reinterpret_cast<float*>(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
+517
View File
@@ -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 <riscv_vector.h>
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<const float*>(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<const float*>(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<const float*>(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<const float*>(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<const float*>(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<const float*>(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
+605
View File
@@ -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 <riscv_vector.h>
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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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<const float*>(src1 + i * src1_step);
const float* src2_row = reinterpret_cast<const float*>(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
+9
View File
@@ -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 );
+60
View File
@@ -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
/**
+25 -4
View File
@@ -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 ||