core:rvv: add 32F to 16S convertScale HAL

Add an RVV HAL implementation for CV_32F to CV_16S conversion.

The RISC-V convertScale HAL already handles several source/destination
depth combinations, but CV_32F to CV_16S currently returns
CV_HAL_ERROR_NOT_IMPLEMENTED and falls back to the generic core path.

Implement the missing conversion using native RVV intrinsics. The
identity-scale case skips the multiply-add, while scaled conversions
apply alpha and beta before narrowing to signed 16-bit output.

The implementation is VLEN-agnostic and uses vsetvl for tail handling.

Functional test:

```text
./build-rvv/bin/opencv_test_core \
    --gtest_filter='*ConvertScale*'
```

Performance was measured with opencv_perf_core on SpacemiT K3
(RVV 1.0, VLEN=256), comparing against an unmodified 5.x baseline.

CV_32F -> CV_16S median time:

```text
1920x1080 C1, alpha=1:
    26.16 ms -> 1.46 ms  (17.92x)

1920x1080 C1, alpha=1/255:
    24.10 ms -> 1.45 ms  (16.62x)

1920x1080 C4, alpha=1:
    103.76 ms -> 6.06 ms  (17.12x)

1920x1080 C4, alpha=1/255:
    96.03 ms -> 5.68 ms  (16.91x)
```

All four corresponding opencv_perf_core cases pass.

Co-authored-by: Yang Wang [yangwang@iscas.ac.cn](mailto:yangwang@iscas.ac.cn)
Co-authored-by: Yuansheng [yuansheng@iscas.ac.cn](mailto:yuansheng@iscas.ac.cn)
This commit is contained in:
Zhang Jinhan
2026-09-10 13:38:10 +08:00
parent c803222407
commit 39fbe07189

View File

@@ -293,6 +293,76 @@ inline int convertScale_32F32F(const uchar* src, size_t src_step, uchar* dst, si
return CV_HAL_ERROR_OK;
}
inline int convertScale_32F16S(const uchar* src, size_t src_step,
uchar* dst, size_t dst_step,
int width, int height,
double alpha, double beta)
{
if (alpha == 1.0 && beta == 0.0)
{
for (int i = 0; i < height; i++)
{
const float* src_row =
reinterpret_cast<const float*>(src + i * src_step);
short* dst_row =
reinterpret_cast<short*>(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_dst =
__riscv_vfncvt_x(vec_src, vl);
__riscv_vse16_v_i16m4(
dst_row + j, vec_dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
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);
short* dst_row =
reinterpret_cast<short*>(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);
auto vec_dst =
__riscv_vfncvt_x(vec_fma, vl);
__riscv_vse16_v_i16m4(
dst_row + j, vec_dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
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)
{
@@ -342,6 +412,8 @@ int convertScale(const uchar* src, size_t src_step, uchar* dst, size_t dst_step,
{
case CV_8U:
return convertScale_32F8U(src, src_step, dst, dst_step, width, height, alpha, beta);
case CV_16S:
return convertScale_32F16S(src, src_step, dst, dst_step, width, height, alpha, beta);
case CV_32F:
return convertScale_32F32F(src, src_step, dst, dst_step, width, height, alpha, beta);
}