mirror of
https://github.com/opencv/opencv.git
synced 2026-09-12 05:11:04 -05:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user