vendor: OpenCV 5.0.0 snapshot at 40738fb16ceddb5fb3fea747585f7ce6abb0605b

This commit is contained in:
Gitea Mirror Bot
2026-08-22 00:10:33 +08:00
commit f7f077da11
6933 changed files with 2335208 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION ${MIN_VER_CMAKE} FATAL_ERROR)
set(RVV_HAL_INCLUDE_DIR include)
set(RVV_HAL_SOURCE_DIR src)
file(GLOB rvv_hal_headers RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "${RVV_HAL_INCLUDE_DIR}/*.hpp")
file(GLOB rvv_hal_sources RELATIVE "${CMAKE_CURRENT_LIST_DIR}" "${RVV_HAL_SOURCE_DIR}/**/*.cpp")
set(HAL_LIB_NAME "rvv_hal")
add_library(${HAL_LIB_NAME} STATIC)
target_sources(${HAL_LIB_NAME} PRIVATE ${rvv_hal_headers} ${rvv_hal_sources})
set_target_properties(${HAL_LIB_NAME} PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${3P_LIBRARY_OUTPUT_PATH})
if(NOT BUILD_SHARED_LIBS)
ocv_install_target(${HAL_LIB_NAME} EXPORT OpenCVModules ARCHIVE DESTINATION ${OPENCV_3P_LIB_INSTALL_PATH} COMPONENT dev)
endif()
target_include_directories(${HAL_LIB_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_SOURCE_DIR}/modules/core/include
${CMAKE_SOURCE_DIR}/modules/imgproc/include
${CMAKE_SOURCE_DIR}/modules/features/include)
set(RVV_HAL_FOUND TRUE CACHE INTERNAL "")
set(RVV_HAL_VERSION "0.0.1" CACHE INTERNAL "")
set(RVV_HAL_LIBRARIES ${HAL_LIB_NAME} CACHE INTERNAL "")
set(RVV_HAL_HEADERS "rvv_hal.hpp" CACHE INTERNAL "")
set(RVV_HAL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "")
+332
View File
@@ -0,0 +1,332 @@
// 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_RVV_HAL_CORE_HPP
#define OPENCV_RVV_HAL_CORE_HPP
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
/* ############ merge ############ */
int merge8u(const uchar** src, uchar* dst, int len, int cn);
int merge16u(const ushort** src, ushort* dst, int len, int cn);
int merge32s(const int** src, int* dst, int len, int cn);
int merge64s(const int64** src, int64* dst, int len, int cn);
#undef cv_hal_merge8u
#define cv_hal_merge8u cv::rvv_hal::core::merge8u
#undef cv_hal_merge16u
#define cv_hal_merge16u cv::rvv_hal::core::merge16u
#undef cv_hal_merge32s
#define cv_hal_merge32s cv::rvv_hal::core::merge32s
#undef cv_hal_merge64s
#define cv_hal_merge64s cv::rvv_hal::core::merge64s
/* ############ meanStdDev ############ */
int meanStdDev(const uchar* src_data, size_t src_step, int width, int height, int src_type,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
#undef cv_hal_meanStdDev
#define cv_hal_meanStdDev cv::rvv_hal::core::meanStdDev
/* ############ dft ############ */
int dft(const uchar* src, uchar* dst, int depth, int nf, int *factors, double scale,
int* itab, void* wave, int tab_size, int n, bool isInverse, bool noPermute);
#undef cv_hal_dft
#define cv_hal_dft cv::rvv_hal::core::dft
/* ############ norm ############ */
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);
#undef cv_hal_norm
#define cv_hal_norm cv::rvv_hal::core::norm
/* ############ normDiff ############ */
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);
#undef cv_hal_normDiff
#define cv_hal_normDiff cv::rvv_hal::core::normDiff
/* ############ normHamming ############ */
int normHamming8u(const uchar* a, int n, int cellSize, int* result);
int normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result);
#undef cv_hal_normHamming8u
#define cv_hal_normHamming8u cv::rvv_hal::core::normHamming8u
#undef cv_hal_normHammingDiff8u
#define cv_hal_normHammingDiff8u cv::rvv_hal::core::normHammingDiff8u
/* ############ convertScale ############ */
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);
#undef cv_hal_convertScale
#define cv_hal_convertScale cv::rvv_hal::core::convertScale
/* ############ minMaxIdx ############ */
int minMaxIdx(const uchar* src_data, size_t src_step, int width, int height, int depth,
double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask, size_t mask_step = 0);
#undef cv_hal_minMaxIdx
#define cv_hal_minMaxIdx cv::rvv_hal::core::minMaxIdx
#undef cv_hal_minMaxIdxMaskStep
#define cv_hal_minMaxIdxMaskStep cv::rvv_hal::core::minMaxIdx
/* ############ fastAtan ############ */
int fast_atan_32(const float* y, const float* x, float* dst, size_t n, bool angle_in_deg);
int fast_atan_64(const double* y, const double* x, double* dst, size_t n, bool angle_in_deg);
#undef cv_hal_fastAtan32f
#define cv_hal_fastAtan32f cv::rvv_hal::core::fast_atan_32
#undef cv_hal_fastAtan64f
#define cv_hal_fastAtan64f cv::rvv_hal::core::fast_atan_64
/* ############ split ############ */
int split8u(const uchar* src, uchar** dst, int len, int cn);
#undef cv_hal_split8u
#define cv_hal_split8u cv::rvv_hal::core::split8u
/* ############ sqrt ############ */
int sqrt32f(const float* src, float* dst, int _len);
int sqrt64f(const double* src, double* dst, int _len);
#undef cv_hal_sqrt32f
#define cv_hal_sqrt32f cv::rvv_hal::core::sqrt32f
#undef cv_hal_sqrt64f
#define cv_hal_sqrt64f cv::rvv_hal::core::sqrt64f
int invSqrt32f(const float* src, float* dst, int _len);
int invSqrt64f(const double* src, double* dst, int _len);
#undef cv_hal_invSqrt32f
#define cv_hal_invSqrt32f cv::rvv_hal::core::invSqrt32f
#undef cv_hal_invSqrt64f
#define cv_hal_invSqrt64f cv::rvv_hal::core::invSqrt64f
/* ############ magnitude ############ */
int magnitude32f(const float *x, const float *y, float *dst, int len);
int magnitude64f(const double *x, const double *y, double *dst, int len);
#undef cv_hal_magnitude32f
#define cv_hal_magnitude32f cv::rvv_hal::core::magnitude32f
#undef cv_hal_magnitude64f
#define cv_hal_magnitude64f cv::rvv_hal::core::magnitude64f
/* ############ cartToPolar ############ */
int cartToPolar32f(const float* x, const float* y, float* mag, float* angle, int len, bool angleInDegrees);
int cartToPolar64f(const double* x, const double* y, double* mag, double* angle, int len, bool angleInDegrees);
#undef cv_hal_cartToPolar32f
#define cv_hal_cartToPolar32f cv::rvv_hal::core::cartToPolar32f
#undef cv_hal_cartToPolar64f
#define cv_hal_cartToPolar64f cv::rvv_hal::core::cartToPolar64f
/* ############ polarToCart ############ */
int polarToCart32f(const float* mag, const float* angle, float* x, float* y, int len, bool angleInDegrees);
int polarToCart64f(const double* mag, const double* angle, double* x, double* y, int len, bool angleInDegrees);
#undef cv_hal_polarToCart32f
#define cv_hal_polarToCart32f cv::rvv_hal::core::polarToCart32f
#undef cv_hal_polarToCart64f
#define cv_hal_polarToCart64f cv::rvv_hal::core::polarToCart64f
/* ############ polarToCart ############ */
int flip(int src_type, const uchar* src_data, size_t src_step, int src_width, int src_height,
uchar* dst_data, size_t dst_step, int flip_mode);
#undef cv_hal_flip
#define cv_hal_flip cv::rvv_hal::core::flip
/* ############ lut ############ */
int lut(const uchar* src_data, size_t src_step, size_t src_type,
const uchar* lut_data, size_t lut_channel_size, size_t lut_channels,
uchar* dst_data, size_t dst_step, int width, int height);
#undef cv_hal_lut
#define cv_hal_lut cv::rvv_hal::core::lut
/* ############ exp ############ */
int exp32f(const float* src, float* dst, int _len);
int exp64f(const double* src, double* dst, int _len);
#undef cv_hal_exp32f
#define cv_hal_exp32f cv::rvv_hal::core::exp32f
#undef cv_hal_exp64f
#define cv_hal_exp64f cv::rvv_hal::core::exp64f
/* ############ log ############ */
int log32f(const float* src, float* dst, int _len);
int log64f(const double* src, double* dst, int _len);
#undef cv_hal_log32f
#define cv_hal_log32f cv::rvv_hal::core::log32f
#undef cv_hal_log64f
#define cv_hal_log64f cv::rvv_hal::core::log64f
/* ############ lu ############ */
int LU32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, int* info);
int LU64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, int* info);
#undef cv_hal_LU32f
#define cv_hal_LU32f cv::rvv_hal::core::LU32f
#undef cv_hal_LU64f
#define cv_hal_LU64f cv::rvv_hal::core::LU64f
/* ############ cholesky ############ */
int Cholesky32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, bool* info);
int Cholesky64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, bool* info);
#undef cv_hal_Cholesky32f
#define cv_hal_Cholesky32f cv::rvv_hal::core::Cholesky32f
#undef cv_hal_Cholesky64f
#define cv_hal_Cholesky64f cv::rvv_hal::core::Cholesky64f
/* ############ qr ############ */
int QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info);
int QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info);
#undef cv_hal_QR32f
#define cv_hal_QR32f cv::rvv_hal::core::QR32f
#undef cv_hal_QR64f
#define cv_hal_QR64f cv::rvv_hal::core::QR64f
/* ############ SVD ############ */
int SVD32f(float* src, size_t src_step, float* w, float* u, size_t u_step, float* vt, size_t vt_step, int m, int n, int flags);
int SVD64f(double* src, size_t src_step, double* w, double* u, size_t u_step, double* vt, size_t vt_step, int m, int n, int flags);
#undef cv_hal_SVD32f
#define cv_hal_SVD32f cv::rvv_hal::core::SVD32f
#undef cv_hal_SVD64f
#define cv_hal_SVD64f cv::rvv_hal::core::SVD64f
/* ############ copyToMasked ############ */
int copyToMasked(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height,
int type, const uchar *mask_data, size_t mask_step, int mask_type);
#undef cv_hal_copyToMasked
#define cv_hal_copyToMasked cv::rvv_hal::core::copyToMasked
/* ############ div, recip ############ */
int div8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, double scale);
int div8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height, double scale);
int div16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height, double scale);
int div16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height, double scale);
int div32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height, double scale);
int div32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height, double scale);
// int div64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, double *dst_data, size_t dst_step, int width, int height, double scale);
#undef cv_hal_div8u
#define cv_hal_div8u cv::rvv_hal::core::div8u
#undef cv_hal_div8s
#define cv_hal_div8s cv::rvv_hal::core::div8s
#undef cv_hal_div16u
#define cv_hal_div16u cv::rvv_hal::core::div16u
#undef cv_hal_div16s
#define cv_hal_div16s cv::rvv_hal::core::div16s
#undef cv_hal_div32s
#define cv_hal_div32s cv::rvv_hal::core::div32s
#undef cv_hal_div32f
#define cv_hal_div32f cv::rvv_hal::core::div32f
// #undef cv_hal_div64f
// #define cv_hal_div64f cv::rvv_hal::core::div64f
int recip8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, double scale);
int recip8s(const schar *src_data, size_t src_step, schar *dst_data, size_t dst_step, int width, int height, double scale);
int recip16u(const ushort *src_data, size_t src_step, ushort *dst_data, size_t dst_step, int width, int height, double scale);
int recip16s(const short *src_data, size_t src_step, short *dst_data, size_t dst_step, int width, int height, double scale);
int recip32s(const int *src_data, size_t src_step, int *dst_data, size_t dst_step, int width, int height, double scale);
int recip32f(const float *src_data, size_t src_step, float *dst_data, size_t dst_step, int width, int height, double scale);
// int recip64f(const double *src_data, size_t src_step, double *dst_data, size_t dst_step, int width, int height, double scale);
#undef cv_hal_recip8u
#define cv_hal_recip8u cv::rvv_hal::core::recip8u
#undef cv_hal_recip8s
#define cv_hal_recip8s cv::rvv_hal::core::recip8s
#undef cv_hal_recip16u
#define cv_hal_recip16u cv::rvv_hal::core::recip16u
#undef cv_hal_recip16s
#define cv_hal_recip16s cv::rvv_hal::core::recip16s
#undef cv_hal_recip32s
#define cv_hal_recip32s cv::rvv_hal::core::recip32s
#undef cv_hal_recip32f
#define cv_hal_recip32f cv::rvv_hal::core::recip32f
// #undef cv_hal_recip64f
// #define cv_hal_recip64f cv::rvv_hal::core::recip64f
/* ############ dotProduct ############ */
int dotprod(const uchar *a_data, size_t a_step, const uchar *b_data, size_t b_step,
int width, int height, int type, double *dot_val);
#undef cv_hal_dotProduct
#define cv_hal_dotProduct cv::rvv_hal::core::dotprod
/* ############ compare ############ */
int cmp8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
int cmp8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
int cmp16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
int cmp16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
int cmp32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
int cmp32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
// int cmp64f(const double *src1_data, size_t src1_step, const double *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation);
#undef cv_hal_cmp8u
#define cv_hal_cmp8u cv::rvv_hal::core::cmp8u
#undef cv_hal_cmp8s
#define cv_hal_cmp8s cv::rvv_hal::core::cmp8s
#undef cv_hal_cmp16u
#define cv_hal_cmp16u cv::rvv_hal::core::cmp16u
#undef cv_hal_cmp16s
#define cv_hal_cmp16s cv::rvv_hal::core::cmp16s
#undef cv_hal_cmp32s
#define cv_hal_cmp32s cv::rvv_hal::core::cmp32s
#undef cv_hal_cmp32f
#define cv_hal_cmp32f cv::rvv_hal::core::cmp32f
// #undef cv_hal_cmp64f
// #define cv_hal_cmp64f cv::rvv_hal::core::cmp64f
/* ############ transpose2d ############ */
int transpose2d(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int src_width, int src_height, int element_size);
#undef cv_hal_transpose2d
#define cv_hal_transpose2d cv::rvv_hal::core::transpose2d
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
#endif // OPENCV_RVV_HAL_CORE_HPP
+26
View File
@@ -0,0 +1,26 @@
// 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_RVV_HAL_FEATURES2D_HPP
#define OPENCV_RVV_HAL_FEATURES2D_HPP
struct cvhalFilter2D;
namespace cv { namespace rvv_hal { namespace features2d {
#if CV_HAL_RVV_1P0_ENABLED
int FAST(const uchar* src_data, size_t src_step, int width, int height,
void** keypoints_data, size_t* keypoints_count,
int threshold, bool nonmax_suppression, int detector_type, void* (*realloc_func)(void*, size_t));
#undef cv_hal_FASTv2
#define cv_hal_FASTv2 cv::rvv_hal::features2d::FAST
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::features2d
#endif // OPENCV_RVV_HAL_IMGPROC_HPP
+299
View File
@@ -0,0 +1,299 @@
// 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_RVV_HAL_IMGPROC_HPP
#define OPENCV_RVV_HAL_IMGPROC_HPP
struct cvhalFilter2D;
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
/* ############ imageMoments ############ */
int imageMoments(const uchar* src_data, size_t src_step, int src_type,
int width, int height, bool binary, double m[10]);
#undef cv_hal_imageMoments
#define cv_hal_imageMoments cv::rvv_hal::imgproc::imageMoments
/* ############ filter ############ */
int filterInit(cvhalFilter2D** context, uchar* kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height, int /*max_width*/, int /*max_height*/, int src_type, int dst_type, int borderType, double delta, int anchor_x, int anchor_y, bool /*allowSubmatrix*/, bool /*allowInplace*/);
int filter(cvhalFilter2D* context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y);
int filterFree(cvhalFilter2D* context);
#undef cv_hal_filterInit
#define cv_hal_filterInit cv::rvv_hal::imgproc::filterInit
#undef cv_hal_filter
#define cv_hal_filter cv::rvv_hal::imgproc::filter
#undef cv_hal_filterFree
#define cv_hal_filterFree cv::rvv_hal::imgproc::filterFree
/* ############ sepFilter ############ */
int sepFilterInit(cvhalFilter2D **context, int src_type, int dst_type, int kernel_type, uchar* kernelx_data, int kernelx_length, uchar* kernely_data, int kernely_length, int anchor_x, int anchor_y, double delta, int borderType);
int sepFilter(cvhalFilter2D *context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y);
int sepFilterFree(cvhalFilter2D* context);
#undef cv_hal_sepFilterInit
#define cv_hal_sepFilterInit cv::rvv_hal::imgproc::sepFilterInit
#undef cv_hal_sepFilter
#define cv_hal_sepFilter cv::rvv_hal::imgproc::sepFilter
#undef cv_hal_sepFilterFree
#define cv_hal_sepFilterFree cv::rvv_hal::imgproc::sepFilterFree
/* ############ morph ############ */
int morphInit(cvhalFilter2D** context, int operation, int src_type, int dst_type, int /*max_width*/, int /*max_height*/, int kernel_type, uchar* kernel_data, size_t kernel_step, int kernel_width, int kernel_height, int anchor_x, int anchor_y, int borderType, const double borderValue[4], int iterations, bool /*allowSubmatrix*/, bool /*allowInplace*/);
int morph(cvhalFilter2D* context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int src_full_width, int src_full_height, int src_roi_x, int src_roi_y, int /*dst_full_width*/, int /*dst_full_height*/, int /*dst_roi_x*/, int /*dst_roi_y*/);
int morphFree(cvhalFilter2D* context);
#undef cv_hal_morphInit
#undef cv_hal_morph
#undef cv_hal_morphFree
#define cv_hal_morphInit cv::rvv_hal::imgproc::morphInit
#define cv_hal_morph cv::rvv_hal::imgproc::morph
#define cv_hal_morphFree cv::rvv_hal::imgproc::morphFree
/* ############ gaussianBlur ############ */
int gaussianBlurBinomial(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, size_t margin_left, size_t margin_top, size_t margin_right, size_t margin_bottom, size_t ksize, int border_type);
#undef cv_hal_gaussianBlurBinomial
#define cv_hal_gaussianBlurBinomial cv::rvv_hal::imgproc::gaussianBlurBinomial
/* ############ medianBlur ############ */
int medianBlur(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, int ksize);
#undef cv_hal_medianBlur
#define cv_hal_medianBlur cv::rvv_hal::imgproc::medianBlur
/* ############ boxFilter ############ */
int boxFilter(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int src_depth, int dst_depth, int cn, int margin_left, int margin_top, int margin_right, int margin_bottom, size_t ksize_width, size_t ksize_height, int anchor_x, int anchor_y, bool normalize, int border_type);
#undef cv_hal_boxFilter
#define cv_hal_boxFilter cv::rvv_hal::imgproc::boxFilter
/* ############ bilateralFilter ############ */
int bilateralFilter(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int depth, int cn, int d, double sigma_color,
double sigma_space, int border_type);
#undef cv_hal_bilateralFilter
#define cv_hal_bilateralFilter cv::rvv_hal::imgproc::bilateralFilter
/* ############ pyramid ############ */
int pyrDown(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int depth, int cn, int border_type);
int pyrUp(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int depth, int cn, int border_type);
#undef cv_hal_pyrdown
#define cv_hal_pyrdown cv::rvv_hal::imgproc::pyrDown
#undef cv_hal_pyrup
#define cv_hal_pyrup cv::rvv_hal::imgproc::pyrUp
/* ############ cvtColor ############ */
int cvtBGRtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, int dcn, bool swapBlue);
int cvtGraytoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn);
int cvtBGRtoGray(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue);
int cvtBGR5x5toBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int dcn, bool swapBlue, int greenBits);
int cvtBGRtoBGR5x5(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int greenBits);
int cvtBGR5x5toGray(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int greenBits);
int cvtGraytoBGR5x5(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int greenBits);
int cvtYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isCbCr);
int cvtBGRtoYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isCbCr);
int cvtOnePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx, int yIdx);
int cvtTwoPlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx);
int cvtThreePlaneYUVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int dst_width, int dst_height, int dcn, bool swapBlue, int uIdx);
int cvtOnePlaneBGRtoYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int uIdx, int yIdx);
int cvtBGRtoTwoPlaneYUV(const uchar * src_data, size_t src_step, uchar * y_data, size_t y_step, uchar * uv_data, size_t uv_step, int width, int height, int scn, bool swapBlue, int uIdx);
int cvtBGRtoThreePlaneYUV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int scn, bool swapBlue, int uIdx);
int cvtHSVtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isFullRange, bool isHSV);
int cvtBGRtoHSV(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isFullRange, bool isHSV);
int cvtXYZtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue);
int cvtBGRtoXYZ(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue);
int cvtLabtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int dcn, bool swapBlue, bool isLab, bool srgb);
int cvtBGRtoLab(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, bool swapBlue, bool isLab, bool srgb);
#undef cv_hal_cvtBGRtoBGR
#define cv_hal_cvtBGRtoBGR cv::rvv_hal::imgproc::cvtBGRtoBGR
#undef cv_hal_cvtGraytoBGR
#define cv_hal_cvtGraytoBGR cv::rvv_hal::imgproc::cvtGraytoBGR
#undef cv_hal_cvtBGRtoGray
#define cv_hal_cvtBGRtoGray cv::rvv_hal::imgproc::cvtBGRtoGray
#undef cv_hal_cvtBGR5x5toBGR
#define cv_hal_cvtBGR5x5toBGR cv::rvv_hal::imgproc::cvtBGR5x5toBGR
#undef cv_hal_cvtBGRtoBGR5x5
#define cv_hal_cvtBGRtoBGR5x5 cv::rvv_hal::imgproc::cvtBGRtoBGR5x5
#undef cv_hal_cvtBGR5x5toGray
#define cv_hal_cvtBGR5x5toGray cv::rvv_hal::imgproc::cvtBGR5x5toGray
#undef cv_hal_cvtGraytoBGR5x5
#define cv_hal_cvtGraytoBGR5x5 cv::rvv_hal::imgproc::cvtGraytoBGR5x5
#undef cv_hal_cvtYUVtoBGR
#define cv_hal_cvtYUVtoBGR cv::rvv_hal::imgproc::cvtYUVtoBGR
#undef cv_hal_cvtBGRtoYUV
#define cv_hal_cvtBGRtoYUV cv::rvv_hal::imgproc::cvtBGRtoYUV
#undef cv_hal_cvtOnePlaneYUVtoBGR
#define cv_hal_cvtOnePlaneYUVtoBGR cv::rvv_hal::imgproc::cvtOnePlaneYUVtoBGR
#undef cv_hal_cvtTwoPlaneYUVtoBGR
#define cv_hal_cvtTwoPlaneYUVtoBGR cv::rvv_hal::imgproc::cvtTwoPlaneYUVtoBGR
#undef cv_hal_cvtThreePlaneYUVtoBGR
#define cv_hal_cvtThreePlaneYUVtoBGR cv::rvv_hal::imgproc::cvtThreePlaneYUVtoBGR
#undef cv_hal_cvtOnePlaneBGRtoYUV
#define cv_hal_cvtOnePlaneBGRtoYUV cv::rvv_hal::imgproc::cvtOnePlaneBGRtoYUV
#undef cv_hal_cvtBGRtoTwoPlaneYUV
#define cv_hal_cvtBGRtoTwoPlaneYUV cv::rvv_hal::imgproc::cvtBGRtoTwoPlaneYUV
#undef cv_hal_cvtBGRtoThreePlaneYUV
#define cv_hal_cvtBGRtoThreePlaneYUV cv::rvv_hal::imgproc::cvtBGRtoThreePlaneYUV
#undef cv_hal_cvtHSVtoBGR
#define cv_hal_cvtHSVtoBGR cv::rvv_hal::imgproc::cvtHSVtoBGR
#undef cv_hal_cvtBGRtoHSV
#define cv_hal_cvtBGRtoHSV cv::rvv_hal::imgproc::cvtBGRtoHSV
#undef cv_hal_cvtXYZtoBGR
#define cv_hal_cvtXYZtoBGR cv::rvv_hal::imgproc::cvtXYZtoBGR
#undef cv_hal_cvtBGRtoXYZ
#define cv_hal_cvtBGRtoXYZ cv::rvv_hal::imgproc::cvtBGRtoXYZ
#undef cv_hal_cvtLabtoBGR
#define cv_hal_cvtLabtoBGR cv::rvv_hal::imgproc::cvtLabtoBGR
#undef cv_hal_cvtBGRtoLab
#define cv_hal_cvtBGRtoLab cv::rvv_hal::imgproc::cvtBGRtoLab
/* ############ warp ############ */
int remap32f(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
float* mapx, size_t mapx_step, float* mapy, size_t mapy_step,
int interpolation, int border_type, const double border_value[4]);
int remap32fc2(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
float* map, size_t map_step, int interpolation, int border_type, const double border_value[4]);
int remap16s(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height,
uchar *dst_data, size_t dst_step, int dst_width, int dst_height,
short* mapx, size_t mapx_step, ushort* mapy, size_t mapy_step,
int interpolation, int border_type, const double border_value[4]);
// BUG: https://github.com/opencv/opencv/issues/27279
// #undef cv_hal_remap32f
// #define cv_hal_remap32f cv::cv_hal_rvv::imgproc::remap32f
// #undef cv_hal_remap32fc2
// #define cv_hal_remap32fc2 cv::cv_hal_rvv::imgproc::remap32fc2
// #undef cv_hal_remap16s
// #define cv_hal_remap16s cv::cv_hal_rvv::imgproc::remap16s
int warpAffine(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, const double M[6], int interpolation, int borderType, const double borderValue[4]);
int warpPerspective(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, const double M[9], int interpolation, int borderType, const double borderValue[4]);
// BUG: https://github.com/opencv/opencv/issues/27280
//#undef cv_hal_warpAffine
//#define cv_hal_warpAffine cv::cv_hal_rvv::imgproc::warpAffine
//#undef cv_hal_warpPerspective
//#define cv_hal_warpPerspective cv::cv_hal_rvv::imgproc::warpPerspective
/* ############ threshold ############ */
int threshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, double thresh, double maxValue, int thresholdType);
int threshold_otsu(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, double maxValue, int thresholdType, double* thresh);
int adaptiveThreshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C);
// disabled since UI is fast enough, only called in threshold_otsu
// #undef cv_hal_threshold
// #define cv_hal_threshold cv::rvv_hal::imgproc::threshold
#undef cv_hal_threshold_otsu
#define cv_hal_threshold_otsu cv::rvv_hal::imgproc::threshold_otsu
#undef cv_hal_adaptiveThreshold
#define cv_hal_adaptiveThreshold cv::rvv_hal::imgproc::adaptiveThreshold
/* ############ histogram ############ */
int equalize_hist(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height);
#undef cv_hal_equalize_hist
#define cv_hal_equalize_hist cv::rvv_hal::imgproc::equalize_hist
int calc_hist(const uchar* src_data, size_t src_step, int src_type, int src_width, int src_height, float* hist_data, int hist_size, const float** ranges, bool uniform, bool accumulate);
#undef cv_hal_calcHist
#define cv_hal_calcHist cv::rvv_hal::imgproc::calc_hist
/* ############ resize ############ */
int resize(int src_type, const uchar *src_data, size_t src_step, int src_width, int src_height, uchar *dst_data, size_t dst_step, int dst_width, int dst_height, double inv_scale_x, double inv_scale_y, int interpolation);
#undef cv_hal_resize
#define cv_hal_resize cv::rvv_hal::imgproc::resize
/* ############ resize ############ */
int integral(int depth, int sdepth, int sqdepth,
const uchar* src_data, size_t src_step,
uchar* sum_data, size_t sum_step,
uchar* sqsum_data, size_t sqsum_step,
uchar* tilted_data, [[maybe_unused]] size_t tilted_step,
int width, int height, int cn);
#undef cv_hal_integral
#define cv_hal_integral cv::rvv_hal::imgproc::integral
/* ############ laplacian ############ */
int laplacian(const uint8_t* src_data, size_t src_step,
uint8_t* dst_data, size_t dst_step,
int width, int height,
int src_depth, int dst_depth, int cn,
int ksize, int border_type, uint8_t border_value);
#undef cv_hal_laplacian
#define cv_hal_laplacian cv::rvv_hal::imgproc::laplacian
/* ############ scharr ############ */
int scharr(const uint8_t *src_data, size_t src_step, uint8_t *dst_data, size_t dst_step, int width, int height, int src_depth, int dst_depth, int cn, int margin_left, int margin_top, int margin_right, int margin_bottom, int dx, int dy, double scale, double delta, int border_type);
#undef cv_hal_scharr
#define cv_hal_scharr cv::rvv_hal::imgproc::scharr
/* ############ sobel ############ */
int sobel(const uint8_t *src_data, size_t src_step, uint8_t *dst_data, size_t dst_step, int width, int height, int src_depth, int dst_depth, int cn, int margin_left, int margin_top, int margin_right, int margin_bottom, int dx, int dy, int ksize, double scale, double delta, int border_type);
#undef cv_hal_sobel
#define cv_hal_sobel cv::rvv_hal::imgproc::sobel
/* ############ canny ############ */
int canny(const uint8_t *src_data, size_t src_step,
uint8_t *dst_data, size_t dst_step,
int width, int height, int cn,
double low_thresh, double high_thresh,
int ksize, bool L2gradient);
#undef cv_hal_canny
#define cv_hal_canny cv::rvv_hal::imgproc::canny
/* ############ spatialGradient ############ */
int spatialGradient(const uint8_t* src_data, size_t src_step,
int16_t* dx_data, size_t dx_step,
int16_t* dy_data, size_t dy_step,
int width, int height,
int ksize, int border_type);
#undef cv_hal_spatialGradient
#define cv_hal_spatialGradient cv::rvv_hal::imgproc::spatialGradient
#endif // CV_HAL_RVV_1P0_ENABLED
#if CV_HAL_RVV_071_ENABLED
int cvtBGRtoBGR(const uchar * src_data, size_t src_step, uchar * dst_data, size_t dst_step, int width, int height, int depth, int scn, int dcn, bool swapBlue);
#undef cv_hal_cvtBGRtoBGR
#define cv_hal_cvtBGRtoBGR cv::rvv_hal::imgproc::cvtBGRtoBGR
#endif // CV_HAL_RVV_071_ENABLED
}}} // cv::rvv_hal::imgproc
#endif // OPENCV_RVV_HAL_IMGPROC_HPP
+878
View File
@@ -0,0 +1,878 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#ifndef OPENCV_RVV_HAL_TYPES_HPP
#define OPENCV_RVV_HAL_TYPES_HPP
#include <riscv_vector.h>
#include <type_traits>
namespace cv { namespace rvv_hal {
#if CV_HAL_RVV_1P0_ENABLED
enum RVV_LMUL
{
LMUL_1 = 1,
LMUL_2 = 2,
LMUL_4 = 4,
LMUL_8 = 8,
LMUL_f2,
LMUL_f4,
LMUL_f8,
};
template <typename T, RVV_LMUL LMUL>
struct RVV;
// -------------------------------Supported types--------------------------------
using RVV_U8M1 = struct RVV<uint8_t, LMUL_1>;
using RVV_U8M2 = struct RVV<uint8_t, LMUL_2>;
using RVV_U8M4 = struct RVV<uint8_t, LMUL_4>;
using RVV_U8M8 = struct RVV<uint8_t, LMUL_8>;
using RVV_U8MF2 = struct RVV<uint8_t, LMUL_f2>;
using RVV_U8MF4 = struct RVV<uint8_t, LMUL_f4>;
using RVV_U8MF8 = struct RVV<uint8_t, LMUL_f8>;
using RVV_I8M1 = struct RVV<int8_t, LMUL_1>;
using RVV_I8M2 = struct RVV<int8_t, LMUL_2>;
using RVV_I8M4 = struct RVV<int8_t, LMUL_4>;
using RVV_I8M8 = struct RVV<int8_t, LMUL_8>;
using RVV_I8MF2 = struct RVV<int8_t, LMUL_f2>;
using RVV_I8MF4 = struct RVV<int8_t, LMUL_f4>;
using RVV_I8MF8 = struct RVV<int8_t, LMUL_f8>;
using RVV_U16M1 = struct RVV<uint16_t, LMUL_1>;
using RVV_U16M2 = struct RVV<uint16_t, LMUL_2>;
using RVV_U16M4 = struct RVV<uint16_t, LMUL_4>;
using RVV_U16M8 = struct RVV<uint16_t, LMUL_8>;
using RVV_U16MF2 = struct RVV<uint16_t, LMUL_f2>;
using RVV_U16MF4 = struct RVV<uint16_t, LMUL_f4>;
using RVV_I16M1 = struct RVV<int16_t, LMUL_1>;
using RVV_I16M2 = struct RVV<int16_t, LMUL_2>;
using RVV_I16M4 = struct RVV<int16_t, LMUL_4>;
using RVV_I16M8 = struct RVV<int16_t, LMUL_8>;
using RVV_I16MF2 = struct RVV<int16_t, LMUL_f2>;
using RVV_I16MF4 = struct RVV<int16_t, LMUL_f4>;
using RVV_U32M1 = struct RVV<uint32_t, LMUL_1>;
using RVV_U32M2 = struct RVV<uint32_t, LMUL_2>;
using RVV_U32M4 = struct RVV<uint32_t, LMUL_4>;
using RVV_U32M8 = struct RVV<uint32_t, LMUL_8>;
using RVV_U32MF2 = struct RVV<uint32_t, LMUL_f2>;
using RVV_I32M1 = struct RVV<int32_t, LMUL_1>;
using RVV_I32M2 = struct RVV<int32_t, LMUL_2>;
using RVV_I32M4 = struct RVV<int32_t, LMUL_4>;
using RVV_I32M8 = struct RVV<int32_t, LMUL_8>;
using RVV_I32MF2 = struct RVV<int32_t, LMUL_f2>;
using RVV_U64M1 = struct RVV<uint64_t, LMUL_1>;
using RVV_U64M2 = struct RVV<uint64_t, LMUL_2>;
using RVV_U64M4 = struct RVV<uint64_t, LMUL_4>;
using RVV_U64M8 = struct RVV<uint64_t, LMUL_8>;
using RVV_I64M1 = struct RVV<int64_t, LMUL_1>;
using RVV_I64M2 = struct RVV<int64_t, LMUL_2>;
using RVV_I64M4 = struct RVV<int64_t, LMUL_4>;
using RVV_I64M8 = struct RVV<int64_t, LMUL_8>;
using RVV_F32M1 = struct RVV<float, LMUL_1>;
using RVV_F32M2 = struct RVV<float, LMUL_2>;
using RVV_F32M4 = struct RVV<float, LMUL_4>;
using RVV_F32M8 = struct RVV<float, LMUL_8>;
using RVV_F32MF2 = struct RVV<float, LMUL_f2>;
using RVV_F64M1 = struct RVV<double, LMUL_1>;
using RVV_F64M2 = struct RVV<double, LMUL_2>;
using RVV_F64M4 = struct RVV<double, LMUL_4>;
using RVV_F64M8 = struct RVV<double, LMUL_8>;
template <typename Dst_T, typename RVV_T>
using RVV_SameLen =
RVV<Dst_T, RVV_LMUL(static_cast<int>((RVV_T::lmul <= 8 ? RVV_T::lmul * static_cast<float>(sizeof(Dst_T)) : RVV_T::lmul == 9 ? static_cast<float>(sizeof(Dst_T)) / 2 : RVV_T::lmul == 10 ? static_cast<float>(sizeof(Dst_T)) / 4 : static_cast<float>(sizeof(Dst_T)) / 8) / sizeof(typename RVV_T::ElemType) == 0.5 ? 9 : \
(RVV_T::lmul <= 8 ? RVV_T::lmul * static_cast<float>(sizeof(Dst_T)) : RVV_T::lmul == 9 ? static_cast<float>(sizeof(Dst_T)) / 2 : RVV_T::lmul == 10 ? static_cast<float>(sizeof(Dst_T)) / 4 : static_cast<float>(sizeof(Dst_T)) / 8) / sizeof(typename RVV_T::ElemType) == 0.25 ? 10 : \
(RVV_T::lmul <= 8 ? RVV_T::lmul * static_cast<float>(sizeof(Dst_T)) : RVV_T::lmul == 9 ? static_cast<float>(sizeof(Dst_T)) / 2 : RVV_T::lmul == 10 ? static_cast<float>(sizeof(Dst_T)) / 4 : static_cast<float>(sizeof(Dst_T)) / 8) / sizeof(typename RVV_T::ElemType) == 0.125 ? 11 : \
(RVV_T::lmul <= 8 ? RVV_T::lmul * static_cast<float>(sizeof(Dst_T)) : RVV_T::lmul == 9 ? static_cast<float>(sizeof(Dst_T)) / 2 : RVV_T::lmul == 10 ? static_cast<float>(sizeof(Dst_T)) / 4 : static_cast<float>(sizeof(Dst_T)) / 8) / sizeof(typename RVV_T::ElemType)))>;
template <size_t DstSize> struct RVV_ToIntHelper;
template <size_t DstSize> struct RVV_ToUintHelper;
template <size_t DstSize> struct RVV_ToFloatHelper;
template <typename RVV_T>
using RVV_ToInt =
RVV<typename RVV_ToIntHelper<sizeof(typename RVV_T::ElemType)>::type, RVV_T::lmul>;
template <typename RVV_T>
using RVV_ToUint =
RVV<typename RVV_ToUintHelper<sizeof(typename RVV_T::ElemType)>::type, RVV_T::lmul>;
template <typename RVV_T>
using RVV_ToFloat =
RVV<typename RVV_ToFloatHelper<sizeof(typename RVV_T::ElemType)>::type, RVV_T::lmul>;
template <typename RVV_T>
using RVV_BaseType = RVV<typename RVV_T::ElemType, LMUL_1>;
// -------------------------------Supported operations--------------------------------
#define HAL_RVV_SIZE_RELATED(EEW, TYPE, LMUL, S_OR_F, X_OR_F, IS_U, IS_F, IS_O) \
static inline size_t setvlmax() { return __riscv_vsetvlmax_e##EEW##LMUL(); } \
static inline size_t setvl(size_t vl) { return __riscv_vsetvl_e##EEW##LMUL(vl); } \
static inline VecType vload(const ElemType* ptr, size_t vl) { \
return __riscv_vle##EEW##_v_##TYPE##LMUL(ptr, vl); \
} \
static inline VecType vload(BoolType vm, const ElemType* ptr, size_t vl) { \
return __riscv_vle##EEW(vm, ptr, vl); \
} \
static inline VecType vload_stride(const ElemType* ptr, ptrdiff_t unit, size_t vl) { \
return __riscv_vlse##EEW##_v_##TYPE##LMUL(ptr, unit, vl); \
} \
static inline VecType vload_stride(BoolType vm, const ElemType* ptr, ptrdiff_t unit, size_t vl) { \
return __riscv_vlse##EEW(vm, ptr, unit, vl); \
} \
static inline void vstore(ElemType* ptr, VecType v, size_t vl) { \
__riscv_vse##EEW(ptr, v, vl); \
} \
static inline void vstore(BoolType vm, ElemType* ptr, VecType v, size_t vl) { \
__riscv_vse##EEW(vm, ptr, v, vl); \
} \
static inline void vstore_stride(ElemType* ptr, ptrdiff_t unit, VecType v, size_t vl) { \
__riscv_vsse##EEW(ptr, unit, v, vl); \
} \
static inline void vstore_stride(BoolType vm, ElemType* ptr, ptrdiff_t unit, VecType v, size_t vl) { \
__riscv_vsse##EEW(vm, ptr, unit, v, vl); \
} \
static inline VecType vundefined() { return __riscv_vundefined_##TYPE##LMUL(); } \
static inline VecType vmv(ElemType a, size_t vl) { \
return __riscv_v##IS_F##mv_v_##X_OR_F##_##TYPE##LMUL(a, vl); \
} \
static inline VecType vmv_s(ElemType a, size_t vl) { \
return __riscv_v##IS_F##mv_s_##X_OR_F##_##TYPE##LMUL(a, vl); \
} \
static inline VecType vslideup(VecType vs2, VecType vs1, size_t n, size_t vl) { \
return __riscv_vslideup_vx_##TYPE##LMUL(vs2, vs1, n, vl); \
} \
static inline VecType vslidedown(VecType vs, size_t n, size_t vl) { \
return __riscv_vslidedown_vx_##TYPE##LMUL(vs, n, vl); \
} \
HAL_RVV_SIZE_RELATED_CUSTOM(EEW, TYPE, LMUL)
#define HAL_RVV_SIZE_UNRELATED(S_OR_F, X_OR_F, IS_U, IS_F, IS_O) \
static inline ElemType vmv_x(VecType vs2) { return __riscv_v##IS_F##mv_##X_OR_F(vs2); } \
\
static inline BoolType vmlt(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##lt##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmle(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##le##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmgt(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##gt##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmle(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##le##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmgt(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##gt##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmge(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##ge##IS_U(vs2, vs1, vl); \
} \
static inline BoolType vmeq(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##eq(vs2, vs1, vl); \
} \
static inline BoolType vmne(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##ne(vs2, vs1, vl); \
} \
static inline BoolType vmlt_mu(BoolType vm, BoolType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##lt##IS_U##_mu(vm, vd, vs2, vs1, vl); \
} \
static inline BoolType vmle_mu(BoolType vm, BoolType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##le##IS_U##_mu(vm, vd, vs2, vs1, vl); \
} \
static inline BoolType vmgt_mu(BoolType vm, BoolType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##gt##IS_U##_mu(vm, vd, vs2, vs1, vl); \
} \
static inline BoolType vmge_mu(BoolType vm, BoolType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_vm##S_OR_F##ge##IS_U##_mu(vm, vd, vs2, vs1, vl); \
} \
\
static inline VecType vadd(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##add(vs2, vs1, vl); \
} \
static inline VecType vsub(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##sub(vs2, vs1, vl); \
} \
static inline VecType vadd_tu(VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##add_tu(vd, vs2, vs1, vl); \
} \
static inline VecType vsub_tu(VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##sub_tu(vd, vs2, vs1, vl); \
} \
static inline VecType vmul(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##mul(vs2, vs1, vl); \
} \
\
static inline VecType vslide1down(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_v##IS_F##slide1down(vs2, vs1, vl); \
} \
static inline VecType vslide1up(VecType vs2, ElemType vs1, size_t vl) { \
return __riscv_v##IS_F##slide1up(vs2, vs1, vl); \
} \
\
static inline VecType vmin(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##min##IS_U(vs2, vs1, vl); \
} \
static inline VecType vmax(VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##max##IS_U(vs2, vs1, vl); \
} \
static inline VecType vmin_tu(VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##min##IS_U##_tu(vd, vs2, vs1, vl); \
} \
static inline VecType vmax_tu(VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##max##IS_U##_tu(vd, vs2, vs1, vl); \
} \
static inline VecType vmin_tumu(BoolType vm, VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##min##IS_U##_tumu(vm, vd, vs2, vs1, vl); \
} \
static inline VecType vmax_tumu(BoolType vm, VecType vd, VecType vs2, VecType vs1, size_t vl) { \
return __riscv_v##IS_F##max##IS_U##_tumu(vm, vd, vs2, vs1, vl); \
} \
\
static inline BaseType vredmin(VecType vs2, BaseType vs1, size_t vl) { \
return __riscv_v##IS_F##redmin##IS_U(vs2, vs1, vl); \
} \
static inline BaseType vredmax(VecType vs2, BaseType vs1, size_t vl) { \
return __riscv_v##IS_F##redmax##IS_U(vs2, vs1, vl); \
} \
static inline BaseType vredsum(VecType vs2, BaseType vs1, size_t vl) { \
return __riscv_v##IS_F##red##IS_O##sum(vs2, vs1, vl); \
}
#define HAL_RVV_BOOL_TYPE(S_OR_F, X_OR_F, IS_U, IS_F, IS_O) \
decltype(__riscv_vm##S_OR_F##eq(std::declval<VecType>(), std::declval<VecType>(), 0))
#define HAL_RVV_DEFINE_ONE(ELEM_TYPE, VEC_TYPE, LMUL_TYPE, \
EEW, TYPE, LMUL, ...) \
template <> struct RVV<ELEM_TYPE, LMUL_TYPE> \
{ \
using ElemType = ELEM_TYPE; \
using VecType = v##VEC_TYPE##LMUL##_t; \
using BoolType = HAL_RVV_BOOL_TYPE(__VA_ARGS__); \
using BaseType = v##VEC_TYPE##m1_t; \
\
static constexpr RVV_LMUL lmul = LMUL_TYPE; \
\
HAL_RVV_SIZE_RELATED(EEW, TYPE, LMUL, __VA_ARGS__) \
HAL_RVV_SIZE_UNRELATED(__VA_ARGS__) \
\
template <typename FROM> \
inline static VecType cast(FROM v, size_t vl); \
template <typename FROM> \
inline static VecType reinterpret(FROM v); \
}; \
\
template <> \
inline RVV<ELEM_TYPE, LMUL_TYPE>::VecType \
RVV<ELEM_TYPE, LMUL_TYPE>::cast( \
RVV<ELEM_TYPE, LMUL_TYPE>::VecType v, \
[[maybe_unused]] size_t vl \
) \
{ \
return v; \
}
// -------------------------------Define all types--------------------------------
#define HAL_RVV_DEFINE_ALL(ELEM_TYPE, VEC_TYPE, \
EEW, TYPE, ...) \
HAL_RVV_DEFINE_ONE(ELEM_TYPE, VEC_TYPE, LMUL_1, \
EEW, TYPE, m1, __VA_ARGS__) \
HAL_RVV_DEFINE_ONE(ELEM_TYPE, VEC_TYPE, LMUL_2, \
EEW, TYPE, m2, __VA_ARGS__) \
HAL_RVV_DEFINE_ONE(ELEM_TYPE, VEC_TYPE, LMUL_4, \
EEW, TYPE, m4, __VA_ARGS__) \
HAL_RVV_DEFINE_ONE(ELEM_TYPE, VEC_TYPE, LMUL_8, \
EEW, TYPE, m8, __VA_ARGS__)
#define HAL_RVV_SIGNED_PARAM s,x, , ,
#define HAL_RVV_UNSIGNED_PARAM s,x,u, ,
#define HAL_RVV_FLOAT_PARAM f,f, ,f,o
// -------------------------------Define Unsigned Integer--------------------------------
#define HAL_RVV_SIZE_RELATED_CUSTOM(EEW, TYPE, LMUL) \
static inline VecType vid(size_t vl) { return __riscv_vid_v_##TYPE##LMUL(vl); }
// LMUL = 1, 2, 4, 8
HAL_RVV_DEFINE_ALL( uint8_t, uint8, 8, u8, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ALL(uint16_t, uint16, 16, u16, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ALL(uint32_t, uint32, 32, u32, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ALL(uint64_t, uint64, 64, u64, HAL_RVV_UNSIGNED_PARAM)
// LMUL = f2
HAL_RVV_DEFINE_ONE( uint8_t, uint8, LMUL_f2, 8, u8, mf2, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ONE(uint16_t, uint16, LMUL_f2, 16, u16, mf2, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ONE(uint32_t, uint32, LMUL_f2, 32, u32, mf2, HAL_RVV_UNSIGNED_PARAM)
// LMUL = f4
HAL_RVV_DEFINE_ONE( uint8_t, uint8, LMUL_f4, 8, u8, mf4, HAL_RVV_UNSIGNED_PARAM)
HAL_RVV_DEFINE_ONE(uint16_t, uint16, LMUL_f4, 16, u16, mf4, HAL_RVV_UNSIGNED_PARAM)
// LMUL = f8
HAL_RVV_DEFINE_ONE( uint8_t, uint8, LMUL_f8, 8, u8, mf8, HAL_RVV_UNSIGNED_PARAM)
#undef HAL_RVV_SIZE_RELATED_CUSTOM
// -------------------------------Define Signed Integer--------------------------------
#define HAL_RVV_SIZE_RELATED_CUSTOM(EEW, TYPE, LMUL)
// LMUL = 1, 2, 4, 8
HAL_RVV_DEFINE_ALL( int8_t, int8, 8, i8, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ALL(int16_t, int16, 16, i16, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ALL(int32_t, int32, 32, i32, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ALL(int64_t, int64, 64, i64, HAL_RVV_SIGNED_PARAM)
// LMUL = f2
HAL_RVV_DEFINE_ONE( int8_t, int8, LMUL_f2, 8, i8, mf2, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ONE(int16_t, int16, LMUL_f2, 16, i16, mf2, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ONE(int32_t, int32, LMUL_f2, 32, i32, mf2, HAL_RVV_SIGNED_PARAM)
// LMUL = f4
HAL_RVV_DEFINE_ONE( int8_t, int8, LMUL_f4, 8, i8, mf4, HAL_RVV_SIGNED_PARAM)
HAL_RVV_DEFINE_ONE(int16_t, int16, LMUL_f4, 16, i16, mf4, HAL_RVV_SIGNED_PARAM)
// LMUL = f8
HAL_RVV_DEFINE_ONE( int8_t, int8, LMUL_f8, 8, i8, mf8, HAL_RVV_SIGNED_PARAM)
// -------------------------------Define Floating Point--------------------------------
// LMUL = 1, 2, 4, 8
HAL_RVV_DEFINE_ALL( float, float32, 32, f32, HAL_RVV_FLOAT_PARAM)
HAL_RVV_DEFINE_ALL(double, float64, 64, f64, HAL_RVV_FLOAT_PARAM)
// LMUL = f2
HAL_RVV_DEFINE_ONE( float, float32, LMUL_f2, 32, f32, mf2, HAL_RVV_FLOAT_PARAM)
#undef HAL_RVV_SIZE_RELATED_CUSTOM
#undef HAL_RVV_DEFINE_ALL
#undef HAL_RVV_DEFINE_ONE
#undef HAL_RVV_BOOL_TYPE
#undef HAL_RVV_SIZE_UNRELATED
#undef HAL_RVV_SIZE_RELATED
// -------------------------------Define cast--------------------------------
template <> struct RVV_ToIntHelper<1> {using type = int8_t;};
template <> struct RVV_ToIntHelper<2> {using type = int16_t;};
template <> struct RVV_ToIntHelper<4> {using type = int32_t;};
template <> struct RVV_ToIntHelper<8> {using type = int64_t;};
template <> struct RVV_ToUintHelper<1> {using type = uint8_t;};
template <> struct RVV_ToUintHelper<2> {using type = uint16_t;};
template <> struct RVV_ToUintHelper<4> {using type = uint32_t;};
template <> struct RVV_ToUintHelper<8> {using type = uint64_t;};
template <> struct RVV_ToFloatHelper<2> {using type = _Float16;};
template <> struct RVV_ToFloatHelper<4> {using type = float;};
template <> struct RVV_ToFloatHelper<8> {using type = double;};
#define HAL_RVV_CVT(ONE, TWO) \
template <> \
inline ONE::VecType ONE::cast(TWO::VecType v, size_t vl) { return __riscv_vncvt_x(v, vl); } \
template <> \
inline TWO::VecType TWO::cast(ONE::VecType v, size_t vl) { return __riscv_vsext_vf2(v, vl); }
HAL_RVV_CVT(RVV_I8M4, RVV_I16M8)
HAL_RVV_CVT(RVV_I8M2, RVV_I16M4)
HAL_RVV_CVT(RVV_I8M1, RVV_I16M2)
HAL_RVV_CVT(RVV_I8MF2, RVV_I16M1)
HAL_RVV_CVT(RVV_I8MF4, RVV_I16MF2)
HAL_RVV_CVT(RVV_I8MF8, RVV_I16MF4)
HAL_RVV_CVT(RVV_I16M4, RVV_I32M8)
HAL_RVV_CVT(RVV_I16M2, RVV_I32M4)
HAL_RVV_CVT(RVV_I16M1, RVV_I32M2)
HAL_RVV_CVT(RVV_I16MF2, RVV_I32M1)
HAL_RVV_CVT(RVV_I16MF4, RVV_I32MF2)
HAL_RVV_CVT(RVV_I32M4, RVV_I64M8)
HAL_RVV_CVT(RVV_I32M2, RVV_I64M4)
HAL_RVV_CVT(RVV_I32M1, RVV_I64M2)
HAL_RVV_CVT(RVV_I32MF2, RVV_I64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(ONE, TWO) \
template <> \
inline ONE::VecType ONE::cast(TWO::VecType v, size_t vl) { return __riscv_vncvt_x(v, vl); } \
template <> \
inline TWO::VecType TWO::cast(ONE::VecType v, size_t vl) { return __riscv_vzext_vf2(v, vl); }
HAL_RVV_CVT(RVV_U8M4, RVV_U16M8)
HAL_RVV_CVT(RVV_U8M2, RVV_U16M4)
HAL_RVV_CVT(RVV_U8M1, RVV_U16M2)
HAL_RVV_CVT(RVV_U8MF2, RVV_U16M1)
HAL_RVV_CVT(RVV_U8MF4, RVV_U16MF2)
HAL_RVV_CVT(RVV_U8MF8, RVV_U16MF4)
HAL_RVV_CVT(RVV_U16M4, RVV_U32M8)
HAL_RVV_CVT(RVV_U16M2, RVV_U32M4)
HAL_RVV_CVT(RVV_U16M1, RVV_U32M2)
HAL_RVV_CVT(RVV_U16MF2, RVV_U32M1)
HAL_RVV_CVT(RVV_U16MF4, RVV_U32MF2)
HAL_RVV_CVT(RVV_U32M4, RVV_U64M8)
HAL_RVV_CVT(RVV_U32M2, RVV_U64M4)
HAL_RVV_CVT(RVV_U32M1, RVV_U64M2)
HAL_RVV_CVT(RVV_U32MF2, RVV_U64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(ONE, FOUR) \
template <> \
inline FOUR::VecType FOUR::cast(ONE::VecType v, size_t vl) { return __riscv_vsext_vf4(v, vl); } \
template <> \
inline ONE::VecType ONE::cast(FOUR::VecType v, size_t vl) { \
return __riscv_vncvt_x(__riscv_vncvt_x(v, vl), vl); \
}
HAL_RVV_CVT(RVV_I8M2, RVV_I32M8)
HAL_RVV_CVT(RVV_I8M1, RVV_I32M4)
HAL_RVV_CVT(RVV_I8MF2, RVV_I32M2)
HAL_RVV_CVT(RVV_I8MF4, RVV_I32M1)
HAL_RVV_CVT(RVV_I8MF8, RVV_I32MF2)
HAL_RVV_CVT(RVV_I16M2, RVV_I64M8)
HAL_RVV_CVT(RVV_I16M1, RVV_I64M4)
HAL_RVV_CVT(RVV_I16MF2, RVV_I64M2)
HAL_RVV_CVT(RVV_I16MF4, RVV_I64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(ONE, FOUR) \
template <> \
inline FOUR::VecType FOUR::cast(ONE::VecType v, size_t vl) { return __riscv_vzext_vf4(v, vl); } \
template <> \
inline ONE::VecType ONE::cast(FOUR::VecType v, size_t vl) { \
return __riscv_vncvt_x(__riscv_vncvt_x(v, vl), vl); \
}
HAL_RVV_CVT(RVV_U8M2, RVV_U32M8)
HAL_RVV_CVT(RVV_U8M1, RVV_U32M4)
HAL_RVV_CVT(RVV_U8MF2, RVV_U32M2)
HAL_RVV_CVT(RVV_U8MF4, RVV_U32M1)
HAL_RVV_CVT(RVV_U8MF8, RVV_U32MF2)
HAL_RVV_CVT(RVV_U16M2, RVV_U64M8)
HAL_RVV_CVT(RVV_U16M1, RVV_U64M4)
HAL_RVV_CVT(RVV_U16MF2, RVV_U64M2)
HAL_RVV_CVT(RVV_U16MF4, RVV_U64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(ONE, EIGHT) \
template <> \
inline EIGHT::VecType EIGHT::cast(ONE::VecType v, size_t vl) { return __riscv_vsext_vf8(v, vl); } \
template <> \
inline ONE::VecType ONE::cast(EIGHT::VecType v, size_t vl) { \
return __riscv_vncvt_x(__riscv_vncvt_x(__riscv_vncvt_x(v ,vl), vl), vl); \
}
HAL_RVV_CVT(RVV_I8M1, RVV_I64M8)
HAL_RVV_CVT(RVV_I8MF2, RVV_I64M4)
HAL_RVV_CVT(RVV_I8MF4, RVV_I64M2)
HAL_RVV_CVT(RVV_I8MF8, RVV_I64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(ONE, EIGHT) \
template <> \
inline EIGHT::VecType EIGHT::cast(ONE::VecType v, size_t vl) { return __riscv_vzext_vf8(v, vl); } \
template <> \
inline ONE::VecType ONE::cast(EIGHT::VecType v, size_t vl) { \
return __riscv_vncvt_x(__riscv_vncvt_x(__riscv_vncvt_x(v ,vl), vl), vl); \
}
HAL_RVV_CVT(RVV_U8M1, RVV_U64M8)
HAL_RVV_CVT(RVV_U8MF2, RVV_U64M4)
HAL_RVV_CVT(RVV_U8MF4, RVV_U64M2)
HAL_RVV_CVT(RVV_U8MF8, RVV_U64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(F32, F64) \
template <> \
inline F32::VecType F32::cast(F64::VecType v, size_t vl) { return __riscv_vfncvt_f(v, vl); } \
template <> \
inline F64::VecType F64::cast(F32::VecType v, size_t vl) { return __riscv_vfwcvt_f(v, vl); }
HAL_RVV_CVT(RVV_F32M4, RVV_F64M8)
HAL_RVV_CVT(RVV_F32M2, RVV_F64M4)
HAL_RVV_CVT(RVV_F32M1, RVV_F64M2)
HAL_RVV_CVT(RVV_F32MF2, RVV_F64M1)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_TYPE, LMUL, IS_U) \
template <> \
inline RVV<A, LMUL_TYPE>::VecType RVV<A, LMUL_TYPE>::cast( \
RVV<B, LMUL_TYPE>::VecType v, size_t vl \
) { \
return __riscv_vfcvt_f_x##IS_U##_v_##A_TYPE##LMUL(v, vl); \
} \
template <> \
inline RVV<B, LMUL_TYPE>::VecType RVV<B, LMUL_TYPE>::cast( \
RVV<A, LMUL_TYPE>::VecType v, size_t vl \
) { \
return __riscv_vfcvt_x##IS_U##_f_v_##B_TYPE##LMUL(v, vl); \
}
HAL_RVV_CVT( float, int32_t, f32, i32, LMUL_1, m1, )
HAL_RVV_CVT( float, int32_t, f32, i32, LMUL_2, m2, )
HAL_RVV_CVT( float, int32_t, f32, i32, LMUL_4, m4, )
HAL_RVV_CVT( float, int32_t, f32, i32, LMUL_8, m8, )
HAL_RVV_CVT( float, int32_t, f32, i32, LMUL_f2, mf2, )
HAL_RVV_CVT( float, uint32_t, f32, u32, LMUL_1, m1, u)
HAL_RVV_CVT( float, uint32_t, f32, u32, LMUL_2, m2, u)
HAL_RVV_CVT( float, uint32_t, f32, u32, LMUL_4, m4, u)
HAL_RVV_CVT( float, uint32_t, f32, u32, LMUL_8, m8, u)
HAL_RVV_CVT( float, uint32_t, f32, u32, LMUL_f2, mf2, u)
HAL_RVV_CVT(double, int64_t, f64, i64, LMUL_1, m1, )
HAL_RVV_CVT(double, int64_t, f64, i64, LMUL_2, m2, )
HAL_RVV_CVT(double, int64_t, f64, i64, LMUL_4, m4, )
HAL_RVV_CVT(double, int64_t, f64, i64, LMUL_8, m8, )
HAL_RVV_CVT(double, uint64_t, f64, u64, LMUL_1, m1, u)
HAL_RVV_CVT(double, uint64_t, f64, u64, LMUL_2, m2, u)
HAL_RVV_CVT(double, uint64_t, f64, u64, LMUL_4, m4, u)
HAL_RVV_CVT(double, uint64_t, f64, u64, LMUL_8, m8, u)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_TYPE, LMUL) \
template <> \
inline RVV<A, LMUL_TYPE>::VecType RVV<A, LMUL_TYPE>::reinterpret(RVV<B, LMUL_TYPE>::VecType v) { \
return __riscv_vreinterpret_##A_TYPE##LMUL(v); \
} \
template <> \
inline RVV<B, LMUL_TYPE>::VecType RVV<B, LMUL_TYPE>::reinterpret(RVV<A, LMUL_TYPE>::VecType v) { \
return __riscv_vreinterpret_##B_TYPE##LMUL(v); \
}
#define HAL_RVV_CVT2(A, B, A_TYPE, B_TYPE) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_1, m1) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_2, m2) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_4, m4) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_8, m8)
HAL_RVV_CVT2( uint8_t, int8_t, u8, i8)
HAL_RVV_CVT2(uint16_t, int16_t, u16, i16)
HAL_RVV_CVT2(uint32_t, int32_t, u32, i32)
HAL_RVV_CVT2(uint64_t, int64_t, u64, i64)
HAL_RVV_CVT2( int32_t, float, i32, f32)
HAL_RVV_CVT2(uint32_t, float, u32, f32)
HAL_RVV_CVT2( int64_t, double, i64, f64)
HAL_RVV_CVT2(uint64_t, double, u64, f64)
#undef HAL_RVV_CVT2
HAL_RVV_CVT( uint8_t, int8_t, u8, i8, LMUL_f2, mf2)
HAL_RVV_CVT(uint16_t, int16_t, u16, i16, LMUL_f2, mf2)
HAL_RVV_CVT(uint32_t, int32_t, u32, i32, LMUL_f2, mf2)
HAL_RVV_CVT( int32_t, float, i32, f32, LMUL_f2, mf2)
HAL_RVV_CVT(uint32_t, float, u32, f32, LMUL_f2, mf2)
HAL_RVV_CVT( uint8_t, int8_t, u8, i8, LMUL_f4, mf4)
HAL_RVV_CVT(uint16_t, int16_t, u16, i16, LMUL_f4, mf4)
HAL_RVV_CVT( uint8_t, int8_t, u8, i8, LMUL_f8, mf8)
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_TYPE, LMUL) \
template <> \
inline RVV<A, LMUL_TYPE>::VecType RVV<A, LMUL_TYPE>::cast(RVV<B, LMUL_TYPE>::VecType v, [[maybe_unused]] size_t vl) { \
return __riscv_vreinterpret_##A_TYPE##LMUL(v); \
} \
template <> \
inline RVV<B, LMUL_TYPE>::VecType RVV<B, LMUL_TYPE>::cast(RVV<A, LMUL_TYPE>::VecType v, [[maybe_unused]] size_t vl) { \
return __riscv_vreinterpret_##B_TYPE##LMUL(v); \
}
#define HAL_RVV_CVT2(A, B, A_TYPE, B_TYPE) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_1, m1) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_2, m2) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_4, m4) \
HAL_RVV_CVT(A, B, A_TYPE, B_TYPE, LMUL_8, m8)
HAL_RVV_CVT2( uint8_t, int8_t, u8, i8)
HAL_RVV_CVT2(uint16_t, int16_t, u16, i16)
HAL_RVV_CVT2(uint32_t, int32_t, u32, i32)
HAL_RVV_CVT2(uint64_t, int64_t, u64, i64)
#undef HAL_RVV_CVT2
#undef HAL_RVV_CVT
#define HAL_RVV_CVT(FROM, INTERMEDIATE, TO) \
template <> \
inline TO::VecType TO::cast(FROM::VecType v, size_t vl) { \
return TO::cast(INTERMEDIATE::cast(v, vl), vl); \
} \
template <> \
inline FROM::VecType FROM::cast(TO::VecType v, size_t vl) { \
return FROM::cast(INTERMEDIATE::cast(v, vl), vl); \
}
// Integer and Float conversions
HAL_RVV_CVT(RVV_I8M1, RVV_I32M4, RVV_F32M4)
HAL_RVV_CVT(RVV_I8M2, RVV_I32M8, RVV_F32M8)
HAL_RVV_CVT(RVV_I8M1, RVV_I64M8, RVV_F64M8)
HAL_RVV_CVT(RVV_I16M1, RVV_I32M2, RVV_F32M2)
HAL_RVV_CVT(RVV_I16M2, RVV_I32M4, RVV_F32M4)
HAL_RVV_CVT(RVV_I16M4, RVV_I32M8, RVV_F32M8)
HAL_RVV_CVT(RVV_I16M1, RVV_I64M4, RVV_F64M4)
HAL_RVV_CVT(RVV_I16M2, RVV_I64M8, RVV_F64M8)
HAL_RVV_CVT(RVV_I32M1, RVV_I64M2, RVV_F64M2)
HAL_RVV_CVT(RVV_I32M2, RVV_I64M4, RVV_F64M4)
HAL_RVV_CVT(RVV_I32M4, RVV_I64M8, RVV_F64M8)
HAL_RVV_CVT(RVV_U8M1, RVV_U32M4, RVV_F32M4)
HAL_RVV_CVT(RVV_U8M2, RVV_U32M8, RVV_F32M8)
HAL_RVV_CVT(RVV_U8M1, RVV_U64M8, RVV_F64M8)
HAL_RVV_CVT(RVV_U16M1, RVV_U32M2, RVV_F32M2)
HAL_RVV_CVT(RVV_U16M2, RVV_U32M4, RVV_F32M4)
HAL_RVV_CVT(RVV_U16M4, RVV_U32M8, RVV_F32M8)
HAL_RVV_CVT(RVV_U16M1, RVV_U64M4, RVV_F64M4)
HAL_RVV_CVT(RVV_U16M2, RVV_U64M8, RVV_F64M8)
HAL_RVV_CVT(RVV_U32M1, RVV_U64M2, RVV_F64M2)
HAL_RVV_CVT(RVV_U32M2, RVV_U64M4, RVV_F64M4)
HAL_RVV_CVT(RVV_U32M4, RVV_U64M8, RVV_F64M8)
// Signed and Unsigned conversions
HAL_RVV_CVT(RVV_U8M1, RVV_U16M2, RVV_I16M2)
HAL_RVV_CVT(RVV_U8M2, RVV_U16M4, RVV_I16M4)
HAL_RVV_CVT(RVV_U8M4, RVV_U16M8, RVV_I16M8)
HAL_RVV_CVT(RVV_U8M1, RVV_U32M4, RVV_I32M4)
HAL_RVV_CVT(RVV_U8M2, RVV_U32M8, RVV_I32M8)
HAL_RVV_CVT(RVV_U8M1, RVV_U64M8, RVV_I64M8)
#undef HAL_RVV_CVT
// ---------------------------- Define Register Group Operations -------------------------------
#if defined(__clang__) && __clang_major__ <= 17
#define HAL_RVV_GROUP(ONE, TWO, TYPE, ONE_LMUL, TWO_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(TWO::VecType v) { \
return __riscv_vget_v_##TYPE##TWO_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(TWO::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##TWO_LMUL(v, idx, val); \
} \
inline TWO::VecType vcreate(ONE::VecType v0, ONE::VecType v1) { \
TWO::VecType v{}; \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##TWO_LMUL(v, 0, v0); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##TWO_LMUL(v, 1, v1); \
return v; \
}
#else
#define HAL_RVV_GROUP(ONE, TWO, TYPE, ONE_LMUL, TWO_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(TWO::VecType v) { \
return __riscv_vget_v_##TYPE##TWO_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(TWO::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##TWO_LMUL(v, idx, val); \
} \
inline TWO::VecType vcreate(ONE::VecType v0, ONE::VecType v1) { \
return __riscv_vcreate_v_##TYPE##ONE_LMUL##_##TYPE##TWO_LMUL(v0, v1); \
}
#endif
HAL_RVV_GROUP(RVV_I8M1, RVV_I8M2, i8, m1, m2)
HAL_RVV_GROUP(RVV_I8M2, RVV_I8M4, i8, m2, m4)
HAL_RVV_GROUP(RVV_I8M4, RVV_I8M8, i8, m4, m8)
HAL_RVV_GROUP(RVV_I16M1, RVV_I16M2, i16, m1, m2)
HAL_RVV_GROUP(RVV_I16M2, RVV_I16M4, i16, m2, m4)
HAL_RVV_GROUP(RVV_I16M4, RVV_I16M8, i16, m4, m8)
HAL_RVV_GROUP(RVV_I32M1, RVV_I32M2, i32, m1, m2)
HAL_RVV_GROUP(RVV_I32M2, RVV_I32M4, i32, m2, m4)
HAL_RVV_GROUP(RVV_I32M4, RVV_I32M8, i32, m4, m8)
HAL_RVV_GROUP(RVV_I64M1, RVV_I64M2, i64, m1, m2)
HAL_RVV_GROUP(RVV_I64M2, RVV_I64M4, i64, m2, m4)
HAL_RVV_GROUP(RVV_I64M4, RVV_I64M8, i64, m4, m8)
HAL_RVV_GROUP(RVV_U8M1, RVV_U8M2, u8, m1, m2)
HAL_RVV_GROUP(RVV_U8M2, RVV_U8M4, u8, m2, m4)
HAL_RVV_GROUP(RVV_U8M4, RVV_U8M8, u8, m4, m8)
HAL_RVV_GROUP(RVV_U16M1, RVV_U16M2, u16, m1, m2)
HAL_RVV_GROUP(RVV_U16M2, RVV_U16M4, u16, m2, m4)
HAL_RVV_GROUP(RVV_U16M4, RVV_U16M8, u16, m4, m8)
HAL_RVV_GROUP(RVV_U32M1, RVV_U32M2, u32, m1, m2)
HAL_RVV_GROUP(RVV_U32M2, RVV_U32M4, u32, m2, m4)
HAL_RVV_GROUP(RVV_U32M4, RVV_U32M8, u32, m4, m8)
HAL_RVV_GROUP(RVV_U64M1, RVV_U64M2, u64, m1, m2)
HAL_RVV_GROUP(RVV_U64M2, RVV_U64M4, u64, m2, m4)
HAL_RVV_GROUP(RVV_U64M4, RVV_U64M8, u64, m4, m8)
HAL_RVV_GROUP(RVV_F32M1, RVV_F32M2, f32, m1, m2)
HAL_RVV_GROUP(RVV_F32M2, RVV_F32M4, f32, m2, m4)
HAL_RVV_GROUP(RVV_F32M4, RVV_F32M8, f32, m4, m8)
HAL_RVV_GROUP(RVV_F64M1, RVV_F64M2, f64, m1, m2)
HAL_RVV_GROUP(RVV_F64M2, RVV_F64M4, f64, m2, m4)
HAL_RVV_GROUP(RVV_F64M4, RVV_F64M8, f64, m4, m8)
#undef HAL_RVV_GROUP
#if defined(__clang__) && __clang_major__ <= 17
#define HAL_RVV_GROUP(ONE, FOUR, TYPE, ONE_LMUL, FOUR_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(FOUR::VecType v) { \
return __riscv_vget_v_##TYPE##FOUR_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(FOUR::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, idx, val); \
} \
inline FOUR::VecType vcreate(ONE::VecType v0, ONE::VecType v1, ONE::VecType v2, ONE::VecType v3) { \
FOUR::VecType v{}; \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, 0, v0); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, 1, v1); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, 2, v2); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, 3, v3); \
return v; \
}
#else
#define HAL_RVV_GROUP(ONE, FOUR, TYPE, ONE_LMUL, FOUR_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(FOUR::VecType v) { \
return __riscv_vget_v_##TYPE##FOUR_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(FOUR::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v, idx, val); \
} \
inline FOUR::VecType vcreate(ONE::VecType v0, ONE::VecType v1, ONE::VecType v2, ONE::VecType v3) { \
return __riscv_vcreate_v_##TYPE##ONE_LMUL##_##TYPE##FOUR_LMUL(v0, v1, v2, v3); \
}
#endif
HAL_RVV_GROUP(RVV_I8M1, RVV_I8M4, i8, m1, m4)
HAL_RVV_GROUP(RVV_I8M2, RVV_I8M8, i8, m2, m8)
HAL_RVV_GROUP(RVV_U8M1, RVV_U8M4, u8, m1, m4)
HAL_RVV_GROUP(RVV_U8M2, RVV_U8M8, u8, m2, m8)
HAL_RVV_GROUP(RVV_I16M1, RVV_I16M4, i16, m1, m4)
HAL_RVV_GROUP(RVV_I16M2, RVV_I16M8, i16, m2, m8)
HAL_RVV_GROUP(RVV_U16M1, RVV_U16M4, u16, m1, m4)
HAL_RVV_GROUP(RVV_U16M2, RVV_U16M8, u16, m2, m8)
HAL_RVV_GROUP(RVV_I32M1, RVV_I32M4, i32, m1, m4)
HAL_RVV_GROUP(RVV_I32M2, RVV_I32M8, i32, m2, m8)
HAL_RVV_GROUP(RVV_U32M1, RVV_U32M4, u32, m1, m4)
HAL_RVV_GROUP(RVV_U32M2, RVV_U32M8, u32, m2, m8)
HAL_RVV_GROUP(RVV_I64M1, RVV_I64M4, i64, m1, m4)
HAL_RVV_GROUP(RVV_I64M2, RVV_I64M8, i64, m2, m8)
HAL_RVV_GROUP(RVV_U64M1, RVV_U64M4, u64, m1, m4)
HAL_RVV_GROUP(RVV_U64M2, RVV_U64M8, u64, m2, m8)
HAL_RVV_GROUP(RVV_F32M1, RVV_F32M4, f32, m1, m4)
HAL_RVV_GROUP(RVV_F32M2, RVV_F32M8, f32, m2, m8)
HAL_RVV_GROUP(RVV_F64M1, RVV_F64M4, f64, m1, m4)
HAL_RVV_GROUP(RVV_F64M2, RVV_F64M8, f64, m2, m8)
#undef HAL_RVV_GROUP
#if defined(__clang__) && __clang_major__ <= 17
#define HAL_RVV_GROUP(ONE, EIGHT, TYPE, ONE_LMUL, EIGHT_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(EIGHT::VecType v) { \
return __riscv_vget_v_##TYPE##EIGHT_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(EIGHT::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, idx, val); \
} \
inline EIGHT::VecType vcreate(ONE::VecType v0, ONE::VecType v1, ONE::VecType v2, ONE::VecType v3, \
ONE::VecType v4, ONE::VecType v5, ONE::VecType v6, ONE::VecType v7) { \
EIGHT::VecType v{}; \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 0, v0); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 1, v1); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 2, v2); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 3, v3); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 4, v4); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 5, v5); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 6, v6); \
v = __riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, 7, v7); \
return v; \
}
#else
#define HAL_RVV_GROUP(ONE, EIGHT, TYPE, ONE_LMUL, EIGHT_LMUL) \
template <size_t idx> \
inline ONE::VecType vget(EIGHT::VecType v) { \
return __riscv_vget_v_##TYPE##EIGHT_LMUL##_##TYPE##ONE_LMUL(v, idx); \
} \
template <size_t idx> \
inline void vset(EIGHT::VecType v, ONE::VecType val) { \
__riscv_vset_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v, idx, val); \
} \
inline EIGHT::VecType vcreate(ONE::VecType v0, ONE::VecType v1, ONE::VecType v2, ONE::VecType v3, \
ONE::VecType v4, ONE::VecType v5, ONE::VecType v6, ONE::VecType v7) { \
return __riscv_vcreate_v_##TYPE##ONE_LMUL##_##TYPE##EIGHT_LMUL(v0, v1, v2, v3, v4, v5, v6, v7); \
}
#endif
HAL_RVV_GROUP(RVV_I8M1, RVV_I8M8, i8, m1, m8)
HAL_RVV_GROUP(RVV_U8M1, RVV_U8M8, u8, m1, m8)
HAL_RVV_GROUP(RVV_I16M1, RVV_I16M8, i16, m1, m8)
HAL_RVV_GROUP(RVV_U16M1, RVV_U16M8, u16, m1, m8)
HAL_RVV_GROUP(RVV_I32M1, RVV_I32M8, i32, m1, m8)
HAL_RVV_GROUP(RVV_U32M1, RVV_U32M8, u32, m1, m8)
HAL_RVV_GROUP(RVV_I64M1, RVV_I64M8, i64, m1, m8)
HAL_RVV_GROUP(RVV_U64M1, RVV_U64M8, u64, m1, m8)
HAL_RVV_GROUP(RVV_F32M1, RVV_F32M8, f32, m1, m8)
HAL_RVV_GROUP(RVV_F64M1, RVV_F64M8, f64, m1, m8)
#undef HAL_RVV_GROUP
#endif // CV_HAL_RVV_1P0_ENABLED
}} // namespace cv::rvv_hal
#endif //OPENCV_RVV_HAL_TYPES_HPP
+32
View File
@@ -0,0 +1,32 @@
// 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_HPP_INCLUDED
#define OPENCV_HAL_RVV_HPP_INCLUDED
#include "opencv2/core/base.hpp"
#include "opencv2/core/utility.hpp"
#include "opencv2/core/hal/interface.h"
#if defined(__riscv_v) && __riscv_v == 1000000
#define CV_HAL_RVV_1P0_ENABLED 1
#else
#define CV_HAL_RVV_1P0_ENABLED 0
#endif
#if defined(__riscv_v) && __riscv_v == 7000 && defined(__GNUC__) && __GNUC__ == 10 && __GNUC_MINOR__ == 4 && defined(__THEAD_VERSION__)
#define CV_HAL_RVV_071_ENABLED 1
#else
#define CV_HAL_RVV_071_ENABLED 0
#endif
#if CV_HAL_RVV_1P0_ENABLED || CV_HAL_RVV_071_ENABLED
#include <riscv_vector.h>
#endif
#include "include/types.hpp"
#include "include/core.hpp"
#include "include/imgproc.hpp"
#include "include/features2d.hpp"
#endif // OPENCV_HAL_RVV_HPP_INCLUDED
+64
View File
@@ -0,0 +1,64 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
int fast_atan_32(const float* y, const float* x, float* dst, size_t n, bool angle_in_deg)
{
auto atan_params = angle_in_deg ? common::atan_params_deg : common::atan_params_rad;
for (size_t vl = 0; n > 0; n -= vl)
{
vl = __riscv_vsetvl_e32m4(n);
auto vy = __riscv_vle32_v_f32m4(y, vl);
auto vx = __riscv_vle32_v_f32m4(x, vl);
auto a = common::rvv_atan(vy, vx, vl, atan_params);
__riscv_vse32(dst, a, vl);
x += vl;
y += vl;
dst += vl;
}
return CV_HAL_ERROR_OK;
}
int fast_atan_64(const double* y, const double* x, double* dst, size_t n, bool angle_in_deg)
{
// this also uses float32 version, ref: mathfuncs_core.simd.hpp
auto atan_params = angle_in_deg ? common::atan_params_deg : common::atan_params_rad;
for (size_t vl = 0; n > 0; n -= vl)
{
vl = __riscv_vsetvl_e64m8(n);
auto vy = __riscv_vfncvt_f(__riscv_vle64_v_f64m8(y, vl), vl);
auto vx = __riscv_vfncvt_f(__riscv_vle64_v_f64m8(x, vl), vl);
auto a = common::rvv_atan(vy, vx, vl, atan_params);
__riscv_vse64(dst, __riscv_vfwcvt_f(a, vl), vl);
x += vl;
y += vl;
dst += vl;
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+50
View File
@@ -0,0 +1,50 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template <typename RVV_T, typename T = typename RVV_T::ElemType>
inline int cartToPolar(const T* x, const T* y, T* mag, T* angle, int len, bool angleInDegrees)
{
using CalType = RVV_SameLen<float, RVV_T>;
auto atan_params = angleInDegrees ? common::atan_params_deg : common::atan_params_rad;
size_t vl;
for (; len > 0; len -= (int)vl, x += vl, y += vl, mag += vl, angle += vl)
{
vl = RVV_T::setvl(len);
auto vx = CalType::cast(RVV_T::vload(x, vl), vl);
auto vy = CalType::cast(RVV_T::vload(y, vl), vl);
auto vmag = common::sqrt<2>(__riscv_vfmadd(vx, vx, __riscv_vfmul(vy, vy, vl), vl), vl);
RVV_T::vstore(mag, RVV_T::cast(vmag, vl), vl);
auto vangle = common::rvv_atan(vy, vx, vl, atan_params);
RVV_T::vstore(angle, RVV_T::cast(vangle, vl), vl);
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int cartToPolar32f(const float* x, const float* y, float* mag, float* angle, int len, bool angleInDegrees) {
return cartToPolar<RVV_F32M4>(x, y, mag, angle, len, angleInDegrees);
}
int cartToPolar64f(const double* x, const double* y, double* mag, double* angle, int len, bool angleInDegrees) {
return cartToPolar<RVV_F64M8>(x, y, mag, angle, len, angleInDegrees);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+128
View File
@@ -0,0 +1,128 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include <cmath>
#include <limits>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from core/src/matrix_decomp.cpp,
// in the function template static int cv::CholImpl
template <typename RVV_T, typename T = typename RVV_T::ElemType>
inline int Cholesky(T* src1, size_t src1_step, int m, T* src2, size_t src2_step, int n, bool* info)
{
int i, j, k;
double s;
src1_step /= sizeof(src1[0]);
src2_step /= sizeof(src2[0]);
int vlmax = RVV_T::setvlmax(), vl;
for( i = 0; i < m; i++ )
{
for( j = 0; j < i; j++ )
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < j; k += vl )
{
vl = RVV_T::setvl(j - k);
auto vec_src1 = RVV_T::vload(src1 + i * src1_step + k, vl);
auto vec_src2 = RVV_T::vload(src1 + j * src1_step + k, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
s = src1[i*src1_step + j] - __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV<T, LMUL_1>::vmv_s(0, vlmax), vlmax));
src1[i*src1_step + j] = (T)(s*src1[j*src1_step + j]);
}
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < j; k += vl )
{
vl = RVV_T::setvl(j - k);
auto vec_src = RVV_T::vload(src1 + i * src1_step + k, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src, vec_src, vl);
}
s = src1[i*src1_step + i] - __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV<T, LMUL_1>::vmv_s(0, vlmax), vlmax));
if( s < std::numeric_limits<T>::epsilon() )
{
*info = false;
return CV_HAL_ERROR_OK;
}
src1[i*src1_step + i] = (T)(1./std::sqrt(s));
}
if (!src2)
{
for( i = 0; i < m; i += vl )
{
vl = RVV_T::setvl(m - i);
auto vec_src = RVV_T::vload_stride(src1 + i * src1_step + i, sizeof(T) * (src1_step + 1), vl);
vec_src = __riscv_vfrdiv(vec_src, 1, vl);
RVV_T::vstore_stride(src1 + i * src1_step + i, sizeof(T) * (src1_step + 1), vec_src, vl);
}
*info = true;
return CV_HAL_ERROR_OK;
}
for( i = 0; i < m; i++ )
{
for( j = 0; j < n; j++ )
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < i; k += vl )
{
vl = RVV_T::setvl(i - k);
auto vec_src1 = RVV_T::vload(src1 + i * src1_step + k, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + k * src2_step + j, sizeof(T) * src2_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
s = src2[i*src2_step + j] - __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV<T, LMUL_1>::vmv_s(0, vlmax), vlmax));
src2[i*src2_step + j] = (T)(s*src1[i*src1_step + i]);
}
}
for( i = m-1; i >= 0; i-- )
{
for( j = 0; j < n; j++ )
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = i + 1; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload_stride(src1 + k * src1_step + i, sizeof(T) * src1_step, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + k * src2_step + j, sizeof(T) * src2_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
s = src2[i*src2_step + j] - __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV<T, LMUL_1>::vmv_s(0, vlmax), vlmax));
src2[i*src2_step + j] = (T)(s*src1[i*src1_step + i]);
}
}
for( i = 0; i < m; i += vl )
{
vl = RVV_T::setvl(m - i);
auto vec_src = RVV_T::vload_stride(src1 + i * src1_step + i, sizeof(T) * (src1_step + 1), vl);
vec_src = __riscv_vfrdiv(vec_src, 1, vl);
RVV_T::vstore_stride(src1 + i * src1_step + i, sizeof(T) * (src1_step + 1), vec_src, vl);
}
*info = true;
return CV_HAL_ERROR_OK;
}
} // anonymous
int Cholesky32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, bool* info) {
return Cholesky<RVV_F32M4>(src1, src1_step, m, src2, src2_step, n, info);
}
int Cholesky64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, bool* info) {
return Cholesky<RVV_F64M4>(src1, src1_step, m, src2, src2_step, n, info);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+195
View File
@@ -0,0 +1,195 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Third party copyrights are property of their respective owners.
#ifndef OPENCV_HAL_RVV_CORE_COMMON_HPP_INCLUDED
#define OPENCV_HAL_RVV_CORE_COMMON_HPP_INCLUDED
#include <riscv_vector.h>
#include <cmath>
#include <cfloat>
namespace cv { namespace rvv_hal { namespace core { namespace common {
#if CV_HAL_RVV_1P0_ENABLED
#define CV_HAL_RVV_NOOP(a) (a)
// ############ abs ############
#define CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(_Tpvs, _Tpvd, shift, suffix) \
inline _Tpvd __riscv_vabs(const _Tpvs& v, const int vl) { \
_Tpvs mask = __riscv_vsra(v, shift, vl); \
_Tpvs v_xor = __riscv_vxor(v, mask, vl); \
return __riscv_vreinterpret_##suffix( \
__riscv_vsub(v_xor, mask, vl) \
); \
}
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint8m2_t, vuint8m2_t, 7, u8m2)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint8m8_t, vuint8m8_t, 7, u8m8)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint16m4_t, vuint16m4_t, 15, u16m4)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint16m8_t, vuint16m8_t, 15, u16m8)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint32m4_t, vuint32m4_t, 31, u32m4)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABS(vint32m8_t, vuint32m8_t, 31, u32m8)
// ############ absdiff ############
#define CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(_Tpvs, _Tpvd, cast, sub, max, min) \
inline _Tpvd __riscv_vabd(const _Tpvs& v1, const _Tpvs& v2, const int vl) { \
return cast(__riscv_##sub(__riscv_##max(v1, v2, vl), __riscv_##min(v1, v2, vl), vl)); \
}
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vuint8m4_t, vuint8m4_t, CV_HAL_RVV_NOOP, vsub, vmaxu, vminu)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vuint8m8_t, vuint8m8_t, CV_HAL_RVV_NOOP, vsub, vmaxu, vminu)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vuint16m2_t, vuint16m2_t, CV_HAL_RVV_NOOP, vsub, vmaxu, vminu)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vuint16m8_t, vuint16m8_t, CV_HAL_RVV_NOOP, vsub, vmaxu, vminu)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint8m4_t, vuint8m4_t, __riscv_vreinterpret_u8m4, vsub, vmax, vmin)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint8m8_t, vuint8m8_t, __riscv_vreinterpret_u8m8, vsub, vmax, vmin)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint16m2_t, vuint16m2_t, __riscv_vreinterpret_u16m2, vsub, vmax, vmin)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint16m8_t, vuint16m8_t, __riscv_vreinterpret_u16m8, vsub, vmax, vmin)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint32m4_t, vuint32m4_t, __riscv_vreinterpret_u32m4, vsub, vmax, vmin)
CV_HAL_RVV_COMMON_CUSTOM_INTRIN_ABSDIFF(vint32m8_t, vuint32m8_t, __riscv_vreinterpret_u32m8, vsub, vmax, vmin)
// ############ reciprocal ############
inline vfloat32m4_t __riscv_vfrec(const vfloat32m4_t &x, const int vl) {
auto rec = __riscv_vfrec7(x, vl);
auto cls = __riscv_vfclass(rec, vl);
auto m = __riscv_vmseq(__riscv_vand(cls, 0b10111000, vl), 0, vl);
auto two = __riscv_vfmv_v_f_f32m4(2.f, vl);
rec = __riscv_vfmul_mu(m, rec, __riscv_vfnmsac(two, x, rec, vl), rec, vl);
rec = __riscv_vfmul_mu(m, rec, __riscv_vfnmsac(two, x, rec, vl), rec, vl);
return rec;
}
// ############ atan ############
// ref: mathfuncs_core.simd.hpp
static constexpr float pi = CV_PI;
struct AtanParams
{
float p1, p3, p5, p7, angle_90;
};
static constexpr AtanParams atan_params_rad {
0.9997878412794807F,
-0.3258083974640975F,
0.1555786518463281F,
-0.04432655554792128F,
90.F * (pi / 180.F)};
static constexpr AtanParams atan_params_deg {
atan_params_rad.p1 * (180 / pi),
atan_params_rad.p3 * (180 / pi),
atan_params_rad.p5 * (180 / pi),
atan_params_rad.p7 * (180 / pi),
90.F};
template <typename VEC_T>
__attribute__((always_inline)) inline VEC_T
rvv_atan(VEC_T vy, VEC_T vx, size_t vl, const AtanParams& params)
{
const auto ax = __riscv_vfabs(vx, vl);
const auto ay = __riscv_vfabs(vy, vl);
// Reciprocal Estimate (vfrec7) is not accurate enough to pass the test of cartToPolar.
const auto c = __riscv_vfdiv(__riscv_vfmin(ax, ay, vl),
__riscv_vfadd(__riscv_vfmax(ax, ay, vl), FLT_EPSILON, vl),
vl);
const auto c2 = __riscv_vfmul(c, c, vl);
// Using vfmadd only results in about a 2% performance improvement, but it occupies 3 additional
// M4 registers. (Performance test on phase32f::VectorLength::1048576: time decreased
// from 5.952ms to 5.805ms on Muse Pi)
// Additionally, when registers are nearly fully utilized (though not yet exhausted), the
// compiler is likely to fail to optimize and may introduce slower memory access (e.g., in
// cv::rvv_hal::fast_atan_64).
// Saving registers can also make this function more reusable in other contexts.
// Therefore, vfmadd is not used here.
auto a = __riscv_vfadd(__riscv_vfmul(c2, params.p7, vl), params.p5, vl);
a = __riscv_vfadd(__riscv_vfmul(c2, a, vl), params.p3, vl);
a = __riscv_vfadd(__riscv_vfmul(c2, a, vl), params.p1, vl);
a = __riscv_vfmul(a, c, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(ax, ay, vl), a, a, params.angle_90, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(vx, 0.F, vl), a, a, params.angle_90 * 2, vl);
a = __riscv_vfrsub_mu(__riscv_vmflt(vy, 0.F, vl), a, a, params.angle_90 * 4, vl);
return a;
}
// ############ sqrt ############
template <typename RVV_T>
struct Sqrt32f
{
using T = RVV_T;
static constexpr size_t iter_times = 2;
};
template <typename RVV_T>
struct Sqrt64f
{
using T = RVV_T;
static constexpr size_t iter_times = 3;
};
// Newton-Raphson method
// Use 4 LMUL registers
template <size_t iter_times, typename VEC_T>
inline VEC_T sqrt(VEC_T x, size_t vl)
{
auto x2 = __riscv_vfmul(x, 0.5, vl);
auto y = __riscv_vfrsqrt7(x, vl);
#ifdef __clang__
#pragma unroll
#endif
for (size_t i = 0; i < iter_times; i++)
{
auto t = __riscv_vfmul(y, y, vl);
t = __riscv_vfmul(t, x2, vl);
t = __riscv_vfrsub(t, 1.5, vl);
y = __riscv_vfmul(t, y, vl);
}
// just to prevent the compiler from calculating mask before the iteration, which will run out
// of registers and cause memory access.
asm volatile("" ::: "memory");
auto classified = __riscv_vfclass(x, vl);
// block -0, +0, positive subnormal number, +inf
auto mask = __riscv_vmseq(__riscv_vand(classified, 0b10111000, vl), 0, vl);
return __riscv_vfmul_mu(mask, x, x, y, vl);
}
// Newton-Raphson method
// Use 3 LMUL registers and 1 mask register
template <size_t iter_times, typename VEC_T>
inline VEC_T invSqrt(VEC_T x, size_t vl)
{
auto classified = __riscv_vfclass(x, vl);
// block -0, +0, positive subnormal number, +inf
auto mask = __riscv_vmseq(__riscv_vand(classified, 0b10111000, vl), 0, vl);
auto x2 = __riscv_vfmul(x, 0.5, vl);
auto y = __riscv_vfrsqrt7(x, vl);
#ifdef __clang__
#pragma unroll
#endif
for (size_t i = 0; i < iter_times; i++)
{
auto t = __riscv_vfmul(y, y, vl);
t = __riscv_vfmul(t, x2, vl);
t = __riscv_vfrsub(t, 1.5, vl);
y = __riscv_vfmul_mu(mask, y, t, y, vl);
}
return y;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}}} // cv::rvv_hal::core::common
#endif // OPENCV_HAL_RVV_CORE_COMMON_HPP_INCLUDED
+129
View File
@@ -0,0 +1,129 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
constexpr RVV_LMUL getLMUL(size_t sz) {
// c++11 only allows exactly one return statement inside the function body modified by constexpr
return sz == 1 ? LMUL_8 : (sz == 2 ? LMUL_4 : (sz == 4 ? LMUL_2 : LMUL_1));
}
static inline vbool1_t vlt(const vuint8m8_t &a, const vuint8m8_t &b, const int vl) { return __riscv_vmsltu(a, b, vl); }
static inline vbool1_t vlt(const vint8m8_t &a, const vint8m8_t &b, const int vl) { return __riscv_vmslt(a, b, vl); }
static inline vbool2_t vlt(const vuint16m8_t &a, const vuint16m8_t &b, const int vl) { return __riscv_vmsltu(a, b, vl); }
static inline vbool2_t vlt(const vint16m8_t &a, const vint16m8_t &b, const int vl) { return __riscv_vmslt(a, b, vl); }
static inline vbool4_t vlt(const vint32m8_t &a, const vint32m8_t &b, const int vl) { return __riscv_vmslt(a, b, vl); }
static inline vbool4_t vlt(const vfloat32m8_t &a, const vfloat32m8_t &b, const int vl) { return __riscv_vmflt(a, b, vl); }
static inline vbool1_t vle(const vuint8m8_t &a, const vuint8m8_t &b, const int vl) { return __riscv_vmsleu(a, b, vl); }
static inline vbool1_t vle(const vint8m8_t &a, const vint8m8_t &b, const int vl) { return __riscv_vmsle(a, b, vl); }
static inline vbool2_t vle(const vuint16m8_t &a, const vuint16m8_t &b, const int vl) { return __riscv_vmsleu(a, b, vl); }
static inline vbool2_t vle(const vint16m8_t &a, const vint16m8_t &b, const int vl) { return __riscv_vmsle(a, b, vl); }
static inline vbool4_t vle(const vint32m8_t &a, const vint32m8_t &b, const int vl) { return __riscv_vmsle(a, b, vl); }
static inline vbool4_t vle(const vfloat32m8_t &a, const vfloat32m8_t &b, const int vl) { return __riscv_vmfle(a, b, vl); }
static inline vbool1_t veq(const vuint8m8_t &a, const vuint8m8_t &b, const int vl) { return __riscv_vmseq(a, b, vl); }
static inline vbool1_t veq(const vint8m8_t &a, const vint8m8_t &b, const int vl) { return __riscv_vmseq(a, b, vl); }
static inline vbool2_t veq(const vuint16m8_t &a, const vuint16m8_t &b, const int vl) { return __riscv_vmseq(a, b, vl); }
static inline vbool2_t veq(const vint16m8_t &a, const vint16m8_t &b, const int vl) { return __riscv_vmseq(a, b, vl); }
static inline vbool4_t veq(const vint32m8_t &a, const vint32m8_t &b, const int vl) { return __riscv_vmseq(a, b, vl); }
static inline vbool4_t veq(const vfloat32m8_t &a, const vfloat32m8_t &b, const int vl) { return __riscv_vmfeq(a, b, vl); }
static inline vbool1_t vne(const vuint8m8_t &a, const vuint8m8_t &b, const int vl) { return __riscv_vmsne(a, b, vl); }
static inline vbool1_t vne(const vint8m8_t &a, const vint8m8_t &b, const int vl) { return __riscv_vmsne(a, b, vl); }
static inline vbool2_t vne(const vuint16m8_t &a, const vuint16m8_t &b, const int vl) { return __riscv_vmsne(a, b, vl); }
static inline vbool2_t vne(const vint16m8_t &a, const vint16m8_t &b, const int vl) { return __riscv_vmsne(a, b, vl); }
static inline vbool4_t vne(const vint32m8_t &a, const vint32m8_t &b, const int vl) { return __riscv_vmsne(a, b, vl); }
static inline vbool4_t vne(const vfloat32m8_t &a, const vfloat32m8_t &b, const int vl) { return __riscv_vmfne(a, b, vl); }
#define CV_HAL_RVV_COMPARE_OP(op_name) \
template <typename _Tps> \
struct op_name { \
using in = RVV<_Tps, LMUL_8>; \
using out = RVV<uint8_t, getLMUL(sizeof(_Tps))>; \
constexpr static uint8_t one = 255; \
static inline void run(const _Tps *src1, const _Tps *src2, uchar *dst, const int len) { \
auto zero = out::vmv(0, out::setvlmax()); \
int vl; \
for (int i = 0; i < len; i += vl) { \
vl = in::setvl(len - i); \
auto v1 = in::vload(src1 + i, vl); \
auto v2 = in::vload(src2 + i, vl); \
auto m = v##op_name(v1, v2, vl); \
out::vstore(dst + i, __riscv_vmerge(zero, one, m, vl), vl); \
} \
} \
};
CV_HAL_RVV_COMPARE_OP(lt)
CV_HAL_RVV_COMPARE_OP(le)
CV_HAL_RVV_COMPARE_OP(eq)
CV_HAL_RVV_COMPARE_OP(ne)
template <template<typename _Tps> class op, typename _Tps> static inline
int compare_impl(const _Tps *src1_data, size_t src1_step, const _Tps *src2_data, size_t src2_step,
uchar *dst_data, size_t dst_step, int width, int height) {
if (src1_step == src2_step && src1_step == dst_step && src1_step == width * sizeof(_Tps)) {
width *= height;
height = 1;
}
for (int h = 0; h < height; h++) {
const _Tps *src1 = reinterpret_cast<const _Tps*>((const uchar*)src1_data + h * src1_step);
const _Tps *src2 = reinterpret_cast<const _Tps*>((const uchar*)src2_data + h * src2_step);
uchar *dst = dst_data + h * dst_step;
op<_Tps>::run(src1, src2, dst, width);
}
return CV_HAL_ERROR_OK;
}
template <typename _Tps> inline
int compare(const _Tps *src1_data, size_t src1_step, const _Tps *src2_data, size_t src2_step,
uchar *dst_data, size_t dst_step, int width, int height, int operation) {
switch (operation) {
case CMP_LT: return compare_impl<lt, _Tps>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height);
case CMP_GT: return compare_impl<lt, _Tps>(src2_data, src2_step, src1_data, src1_step, dst_data, dst_step, width, height);
case CMP_LE: return compare_impl<le, _Tps>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height);
case CMP_GE: return compare_impl<le, _Tps>(src2_data, src2_step, src1_data, src1_step, dst_data, dst_step, width, height);
case CMP_EQ: return compare_impl<eq, _Tps>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height);
case CMP_NE: return compare_impl<ne, _Tps>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height);
default: return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
}
} // namespace anonymous
int cmp8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<uchar>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
int cmp8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<schar>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
int cmp16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<ushort>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
int cmp16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<short>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
int cmp32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<int>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
int cmp32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, int operation) {
return compare<float>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, operation);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+356
View File
@@ -0,0 +1,356 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
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_8U16U(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 uchar* src_row = src + i * src_step;
ushort* dst_row = reinterpret_cast<ushort*>(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_dst = __riscv_vzext_vf2(vec_src, vl);
__riscv_vse16_v_u16m4(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 uchar* src_row = src + i * src_step;
ushort* dst_row = reinterpret_cast<ushort*>(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 = __riscv_vfncvt_xu(vec_fma, vl);
__riscv_vse16_v_u16m4(dst_row + j, vec_dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
inline int convertScale_8U16S(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 uchar* src_row = 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_e8m2(width - j);
auto vec_src = __riscv_vle8_v_u8m2(src_row + j, vl);
auto vec_dst = __riscv_vreinterpret_v_u16m4_i16m4(__riscv_vzext_vf2(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 uchar* src_row = 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_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 = __riscv_vfncvt_x(vec_fma, vl);
__riscv_vse16_v_i16m4(dst_row + j, vec_dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
inline int convertScale_16U8U(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 ushort* src_row = reinterpret_cast<const ushort*>(src + i * src_step);
uchar* dst_row = dst + i * dst_step;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e16m4(width - j);
auto vec_src = __riscv_vle16_v_u16m4(src_row + j, vl);
auto vec_dst = __riscv_vnclipu(vec_src, 0, __RISCV_VXRM_RNU, vl);
__riscv_vse8_v_u8m2(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 ushort* src_row = reinterpret_cast<const ushort*>(src + i * src_step);
uchar* dst_row = dst + i * dst_step;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e16m4(width - j);
auto vec_src = __riscv_vle16_v_u16m4(src_row + j, vl);
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src, 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_16U32F(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 ushort* src_row = reinterpret_cast<const ushort*>(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_e16m4(width - j);
auto vec_src = __riscv_vle16_v_u16m4(src_row + j, vl);
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src, 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_16S32F(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 short* src_row = reinterpret_cast<const short*>(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_e16m4(width - j);
auto vec_src = __riscv_vle16_v_i16m4(src_row + j, vl);
auto vec_src_f32 = __riscv_vfwcvt_f(vec_src, 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_32F8U(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);
uchar* dst_row = 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_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_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;
}
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;
if ((unsigned)ddepth >= CV_DEPTH_MAX)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// Column-shaped sources can target row-shaped continuous vectors.
if (width == 1 && height > 1 && dst_step != CV_ELEM_SIZE1(ddepth))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
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_16U:
return convertScale_8U16U(src, src_step, dst, dst_step, width, height, alpha, beta);
case CV_16S:
return convertScale_8U16S(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_16U:
switch (ddepth)
{
case CV_8U:
return convertScale_16U8U(src, src_step, dst, dst_step, width, height, alpha, beta);
case CV_32F:
return convertScale_16U32F(src, src_step, dst, dst_step, width, height, alpha, beta);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_16S:
switch (ddepth)
{
case CV_32F:
return convertScale_16S32F(src, src_step, dst, dst_step, width, height, alpha, beta);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_32F:
switch (ddepth)
{
case CV_8U:
return convertScale_32F8U(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);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+154
View File
@@ -0,0 +1,154 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
#define CV_HAL_RVV_COPY_MASK_eXc1(X, mask_lmul) \
static int copyToMasked_e##X##c1(const uchar *src_data, size_t src_step, const uchar *mask_data, size_t mask_step, \
uchar *dst_data, size_t dst_step, int width, int height) { \
for (; height--; mask_data += mask_step, src_data += src_step, dst_data += dst_step) { \
const uint##X##_t *src = (const uint##X##_t*)src_data; \
uint##X##_t *dst = (uint##X##_t*)dst_data; \
int vl; \
for (int i = 0; i < width; i += vl) { \
vl = __riscv_vsetvl_e8m##mask_lmul(width - i); \
auto m = __riscv_vmsne(__riscv_vle8_v_u8m##mask_lmul(mask_data + i, vl), 0, vl); \
auto v = __riscv_vle##X##_v_u##X##m8_m(m, src + i, vl); \
__riscv_vse##X##_v_u##X##m8_m(m, dst + i, v, vl); \
} \
} \
return CV_HAL_ERROR_OK; \
}
CV_HAL_RVV_COPY_MASK_eXc1(8, 8)
CV_HAL_RVV_COPY_MASK_eXc1(16, 4)
CV_HAL_RVV_COPY_MASK_eXc1(32, 2)
CV_HAL_RVV_COPY_MASK_eXc1(64, 1)
#define CV_HAL_RVV_COPY_MASK_eXc3(X, mask_lmul) \
static int copyToMasked_e##X##c3(const uchar *src_data, size_t src_step, const uchar *mask_data, size_t mask_step, \
uchar *dst_data, size_t dst_step, int width, int height) { \
for (; height--; mask_data += mask_step, src_data += src_step, dst_data += dst_step) { \
const uint##X##_t *src = (const uint##X##_t*)src_data; \
uint##X##_t *dst = (uint##X##_t*)dst_data; \
int vl; \
for (int i = 0; i < width; i += vl) { \
vl = __riscv_vsetvl_e8m##mask_lmul(width - i); \
auto m = __riscv_vmsne(__riscv_vle8_v_u8m##mask_lmul(mask_data + i, vl), 0, vl); \
auto v = __riscv_vlseg3e##X##_v_u##X##m2x3_m(m, src + 3 * i, vl); \
__riscv_vsseg3e##X##_v_u##X##m2x3_m(m, dst + 3 * i, v, vl); \
} \
} \
return CV_HAL_ERROR_OK; \
}
CV_HAL_RVV_COPY_MASK_eXc3(8, 2)
CV_HAL_RVV_COPY_MASK_eXc3(16, 1)
CV_HAL_RVV_COPY_MASK_eXc3(32, f2)
CV_HAL_RVV_COPY_MASK_eXc3(64, f4)
static int copyToMasked_e64c2(const uchar *src_data, size_t src_step,
const uchar *mask_data, size_t mask_step,
uchar *dst_data, size_t dst_step, int width,
int height) {
for (; height--; mask_data += mask_step, src_data += src_step, dst_data += dst_step) {
const uint64_t *src = (const uint64_t *)src_data;
uint64_t *dst = (uint64_t *)dst_data;
int vl;
for (int i = 0; i < width; i += vl) {
vl = __riscv_vsetvl_e8mf2(width - i);
auto m = __riscv_vmsne(__riscv_vle8_v_u8mf2(mask_data + i, vl), 0, vl);
auto v = __riscv_vlseg2e64_v_u64m4x2_m(m, src + 2 * i, vl);
__riscv_vsseg2e64_v_u64m4x2_m(m, dst + 2 * i, v, vl);
}
}
return CV_HAL_ERROR_OK;
}
static int copyToMasked_e64c4(const uchar *src_data, size_t src_step,
const uchar *mask_data, size_t mask_step,
uchar *dst_data, size_t dst_step, int width,
int height) {
for (; height--; mask_data += mask_step, src_data += src_step, dst_data += dst_step) {
const uint64_t *src = (const uint64_t *)src_data;
uint64_t *dst = (uint64_t *)dst_data;
int vl;
for (int i = 0; i < width; i += vl) {
vl = __riscv_vsetvl_e8mf4(width - i);
auto m = __riscv_vmsne(__riscv_vle8_v_u8mf4(mask_data + i, vl), 0, vl);
auto v = __riscv_vlseg4e64_v_u64m2x4_m(m, src + 4 * i, vl);
__riscv_vsseg4e64_v_u64m2x4_m(m, dst + 4 * i, v, vl);
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
using CopyToMaskedFunc = int (*)(const uchar*, size_t, const uchar*, size_t, uchar*, size_t, int, int);
int copyToMasked(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height,
int type, const uchar *mask_data, size_t mask_step, int mask_type) {
int cn = CV_MAT_CN(type);
int mdepth = CV_MAT_DEPTH(mask_type), mcn = CV_MAT_CN(mask_type);
if (mcn > 1 || mdepth != CV_8U) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
static CopyToMaskedFunc tab[] = {
0, copyToMasked_e8c1, copyToMasked_e16c1, copyToMasked_e8c3,
copyToMasked_e32c1, 0, copyToMasked_e16c3, 0,
copyToMasked_e64c1, 0, 0, 0,
copyToMasked_e32c3, 0, 0, 0,
copyToMasked_e64c2, 0, 0, 0,
0, 0, 0, 0,
copyToMasked_e64c3, 0, 0, 0,
0, 0, 0, 0,
copyToMasked_e64c4
};
size_t elem_size = CV_ELEM_SIZE(type);
CopyToMaskedFunc func = elem_size <= 32 ? tab[elem_size] : nullptr;
if (func == nullptr) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
size_t elem_size1 = static_cast<size_t>(CV_ELEM_SIZE1(type));
bool src_continuous = (src_step == width * elem_size1 * cn || (src_step != width * elem_size1 * cn && height == 1));
bool dst_continuous = (dst_step == width * elem_size1 * cn || (dst_step != width * elem_size1 * cn && height == 1));
bool mask_continuous = (mask_step == static_cast<size_t>(width));
size_t nplanes = 1;
int _width = width, _height = height;
if (!src_continuous || !dst_continuous || !mask_continuous) {
nplanes = height;
_width = width * mcn;
_height = 1;
}
auto _src = src_data;
auto _mask = mask_data;
auto _dst = dst_data;
for (size_t i = 0; i < nplanes; i++) {
if (!src_continuous || !dst_continuous || !mask_continuous) {
_src = src_data + src_step * i;
_mask = mask_data + mask_step * i;
_dst = dst_data + dst_step * i;
}
func(_src, src_step, _mask, mask_step, _dst, dst_step, _width, _height);
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+299
View File
@@ -0,0 +1,299 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
#include "common.hpp"
#include <limits>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
inline size_t setvl(int l) { return __riscv_vsetvl_e8m1(l); }
inline vuint8m1_t vle(const uint8_t *p, int vl) { return __riscv_vle8_v_u8m1(p, vl); }
inline vint8m1_t vle(const int8_t *p, int vl) { return __riscv_vle8_v_i8m1(p, vl); }
inline vuint16m2_t vle(const uint16_t *p, int vl) { return __riscv_vle16_v_u16m2(p, vl); }
inline vint16m2_t vle(const int16_t *p, int vl) { return __riscv_vle16_v_i16m2(p, vl); }
inline vint32m4_t vle(const int *p, int vl) { return __riscv_vle32_v_i32m4(p, vl); }
inline vfloat32m4_t vle(const float *p, int vl) { return __riscv_vle32_v_f32m4(p, vl); }
inline void vse(uint8_t *p, const vuint8m1_t &v, int vl) { __riscv_vse8(p, v, vl); }
inline void vse(int8_t *p, const vint8m1_t &v, int vl) { __riscv_vse8(p, v, vl); }
inline void vse(uint16_t *p, const vuint16m2_t &v, int vl) { __riscv_vse16(p, v, vl); }
inline void vse(int16_t *p, const vint16m2_t &v, int vl) { __riscv_vse16(p, v, vl); }
inline void vse(int *p, const vint32m4_t &v, int vl) { __riscv_vse32(p, v, vl); }
inline void vse(float *p, const vfloat32m4_t &v, int vl) { __riscv_vse32(p, v, vl); }
inline vuint16m2_t ext(const vuint8m1_t &v, const int vl) { return __riscv_vzext_vf2(v, vl); }
inline vint16m2_t ext(const vint8m1_t &v, const int vl) { return __riscv_vsext_vf2(v, vl); }
inline vuint8m1_t nclip(const vuint16m2_t &v, const int vl) { return __riscv_vnclipu(v, 0, __RISCV_VXRM_RNU, vl); }
inline vint8m1_t nclip(const vint16m2_t &v, const int vl) { return __riscv_vnclip(v, 0, __RISCV_VXRM_RNU, vl); }
template <typename VT> inline
VT div_sat(const VT &v1, const VT &v2, const float scale, const int vl) {
return nclip(div_sat(ext(v1, vl), ext(v2, vl), scale, vl), vl);
}
template <> inline
vint16m2_t div_sat(const vint16m2_t &v1, const vint16m2_t &v2, const float scale, const int vl) {
auto f1 = __riscv_vfwcvt_f(v1, vl);
auto f2 = __riscv_vfwcvt_f(v2, vl);
auto res = __riscv_vfmul(f1, __riscv_vfmul(common::__riscv_vfrec(f2, vl), scale, vl), vl);
return __riscv_vfncvt_x(res, vl);
}
template <> inline
vuint16m2_t div_sat(const vuint16m2_t &v1, const vuint16m2_t &v2, const float scale, const int vl) {
auto f1 = __riscv_vfwcvt_f(v1, vl);
auto f2 = __riscv_vfwcvt_f(v2, vl);
auto res = __riscv_vfmul(f1, __riscv_vfmul(common::__riscv_vfrec(f2, vl), scale, vl), vl);
return __riscv_vfncvt_xu(res, vl);
}
template <> inline
vint32m4_t div_sat(const vint32m4_t &v1, const vint32m4_t &v2, const float scale, const int vl) {
auto f1 = __riscv_vfcvt_f(v1, vl);
auto f2 = __riscv_vfcvt_f(v2, vl);
auto res = __riscv_vfmul(f1, __riscv_vfmul(common::__riscv_vfrec(f2, vl), scale, vl), vl);
return __riscv_vfcvt_x(res, vl);
}
template <> inline
vuint32m4_t div_sat(const vuint32m4_t &v1, const vuint32m4_t &v2, const float scale, const int vl) {
auto f1 = __riscv_vfcvt_f(v1, vl);
auto f2 = __riscv_vfcvt_f(v2, vl);
auto res = __riscv_vfmul(f1, __riscv_vfmul(common::__riscv_vfrec(f2, vl), scale, vl), vl);
return __riscv_vfcvt_xu(res, vl);
}
template <typename VT> inline
VT recip_sat(const VT &v, const float scale, const int vl) {
return nclip(recip_sat(ext(v, vl), scale, vl), vl);
}
template <> inline
vint16m2_t recip_sat(const vint16m2_t &v, const float scale, const int vl) {
auto f = __riscv_vfwcvt_f(v, vl);
auto res = __riscv_vfmul(common::__riscv_vfrec(f, vl), scale, vl);
return __riscv_vfncvt_x(res, vl);
}
template <> inline
vuint16m2_t recip_sat(const vuint16m2_t &v, const float scale, const int vl) {
auto f = __riscv_vfwcvt_f(v, vl);
auto res = __riscv_vfmul(common::__riscv_vfrec(f, vl), scale, vl);
return __riscv_vfncvt_xu(res, vl);
}
template <> inline
vint32m4_t recip_sat(const vint32m4_t &v, const float scale, const int vl) {
auto f = __riscv_vfcvt_f(v, vl);
auto res = __riscv_vfmul(common::__riscv_vfrec(f, vl), scale, vl);
return __riscv_vfcvt_x(res, vl);
}
template <> inline
vuint32m4_t recip_sat(const vuint32m4_t &v, const float scale, const int vl) {
auto f = __riscv_vfcvt_f(v, vl);
auto res = __riscv_vfmul(common::__riscv_vfrec(f, vl), scale, vl);
return __riscv_vfcvt_xu(res, vl);
}
// Implementation
template <typename ST> inline
int div(const ST *src1, size_t step1, const ST *src2, size_t step2,
ST *dst, size_t step, int width, int height, float scale) {
float max_fval = static_cast<float>(std::numeric_limits<ST>::max());
if (scale == 0.f || ((scale * max_fval) < 1.f && (scale * max_fval) > -1.f)) {
for (int h = 0; h < height; h++) {
ST *dst_h = reinterpret_cast<ST*>((uchar*)dst + h * step);
std::memset(dst_h, 0, sizeof(ST) * width);
}
return CV_HAL_ERROR_OK;
}
for (int h = 0; h < height; h++) {
const ST *src1_h = reinterpret_cast<const ST*>((const uchar*)src1 + h * step1);
const ST *src2_h = reinterpret_cast<const ST*>((const uchar*)src2 + h * step2);
ST *dst_h = reinterpret_cast<ST*>((uchar*)dst + h * step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v1 = vle(src1_h + w, vl);
auto v2 = vle(src2_h + w, vl);
auto mask = __riscv_vmseq(v2, 0, vl);
vse(dst_h + w, __riscv_vmerge(div_sat(v1, v2, scale, vl), 0, mask, vl), vl);
}
}
return CV_HAL_ERROR_OK;
}
template <>
int div(const float *src1, size_t step1, const float *src2, size_t step2,
float *dst, size_t step, int width, int height, float scale) {
if (scale == 0.f) {
for (int h = 0; h < height; h++) {
float *dst_h = reinterpret_cast<float*>((uchar*)dst + h * step);
std::memset(dst_h, 0, sizeof(float) * width);
}
return CV_HAL_ERROR_OK;
}
if (std::fabs(scale - 1.f) < FLT_EPSILON) {
for (int h = 0; h < height; h++) {
const float *src1_h = reinterpret_cast<const float*>((const uchar*)src1 + h * step1);
const float *src2_h = reinterpret_cast<const float*>((const uchar*)src2 + h * step2);
float *dst_h = reinterpret_cast<float*>((uchar*)dst + h * step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v1 = vle(src1_h + w, vl);
auto v2 = vle(src2_h + w, vl);
vse(dst_h + w, __riscv_vfmul(v1, common::__riscv_vfrec(v2, vl), vl), vl);
}
}
} else {
for (int h = 0; h < height; h++) {
const float *src1_h = reinterpret_cast<const float*>((const uchar*)src1 + h * step1);
const float *src2_h = reinterpret_cast<const float*>((const uchar*)src2 + h * step2);
float *dst_h = reinterpret_cast<float*>((uchar*)dst + h * step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v1 = vle(src1_h + w, vl);
auto v2 = vle(src2_h + w, vl);
vse(dst_h + w, __riscv_vfmul(v1, __riscv_vfmul(common::__riscv_vfrec(v2, vl), scale, vl), vl), vl);
}
}
}
return CV_HAL_ERROR_OK;
}
template <typename ST> inline
int recip(const ST *src_data, size_t src_step, ST *dst_data, size_t dst_step,
int width, int height, float scale) {
if (scale == 0.f || (scale < 1.f && scale > -1.f)) {
for (int h = 0; h < height; h++) {
ST *dst_h = reinterpret_cast<ST*>((uchar*)dst_data + h * dst_step);
std::memset(dst_h, 0, sizeof(ST) * width);
}
return CV_HAL_ERROR_OK;
}
for (int h = 0; h < height; h++) {
const ST *src_h = reinterpret_cast<const ST*>((const uchar*)src_data + h * src_step);
ST *dst_h = reinterpret_cast<ST*>((uchar*)dst_data + h * dst_step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v = vle(src_h + w, vl);
auto mask = __riscv_vmseq(v, 0, vl);
vse(dst_h + w, __riscv_vmerge(recip_sat(v, scale, vl), 0, mask, vl), vl);
}
}
return CV_HAL_ERROR_OK;
}
template <>
int recip(const float *src_data, size_t src_step, float *dst_data, size_t dst_step,
int width, int height, float scale) {
if (scale == 0.f) {
for (int h = 0; h < height; h++) {
float *dst_h = reinterpret_cast<float*>((uchar*)dst_data + h * dst_step);
std::memset(dst_h, 0, sizeof(float) * width);
}
return CV_HAL_ERROR_OK;
}
if (std::fabs(scale - 1.f) < FLT_EPSILON) {
for (int h = 0; h < height; h++) {
const float *src_h = reinterpret_cast<const float*>((const uchar*)src_data + h * src_step);
float *dst_h = reinterpret_cast<float*>((uchar*)dst_data + h * dst_step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v = vle(src_h + w, vl);
vse(dst_h + w, common::__riscv_vfrec(v, vl), vl);
}
}
} else {
for (int h = 0; h < height; h++) {
const float *src_h = reinterpret_cast<const float*>((const uchar*)src_data + h * src_step);
float *dst_h = reinterpret_cast<float*>((uchar*)dst_data + h * dst_step);
int vl;
for (int w = 0; w < width; w += vl) {
vl = setvl(width - w);
auto v = vle(src_h + w, vl);
vse(dst_h + w, __riscv_vfmul(common::__riscv_vfrec(v, vl), scale, vl), vl);
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int div8u(const uchar *src1_data, size_t src1_step, const uchar *src2_data, size_t src2_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) {
return div<uchar>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int div8s(const schar *src1_data, size_t src1_step, const schar *src2_data, size_t src2_step, schar *dst_data, size_t dst_step, int width, int height, double scale) {
return div<schar>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int div16u(const ushort *src1_data, size_t src1_step, const ushort *src2_data, size_t src2_step, ushort *dst_data, size_t dst_step, int width, int height, double scale) {
return div<ushort>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int div16s(const short *src1_data, size_t src1_step, const short *src2_data, size_t src2_step, short *dst_data, size_t dst_step, int width, int height, double scale) {
return div<short>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int div32s(const int *src1_data, size_t src1_step, const int *src2_data, size_t src2_step, int *dst_data, size_t dst_step, int width, int height, double scale) {
return div<int>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int div32f(const float *src1_data, size_t src1_step, const float *src2_data, size_t src2_step, float *dst_data, size_t dst_step, int width, int height, double scale) {
return div<float>(src1_data, src1_step, src2_data, src2_step, dst_data, dst_step, width, height, scale);
}
int recip8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<uchar>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
int recip8s(const schar *src_data, size_t src_step, schar *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<schar>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
int recip16u(const ushort *src_data, size_t src_step, ushort *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<ushort>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
int recip16s(const short *src_data, size_t src_step, short *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<short>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
int recip32s(const int *src_data, size_t src_step, int *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<int>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
int recip32f(const float *src_data, size_t src_step, float *dst_data, size_t dst_step, int width, int height, double scale) {
return recip<float>(src_data, src_step, dst_data, dst_step, width, height, scale);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+221
View File
@@ -0,0 +1,221 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
#include <algorithm>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
static inline double dotProd_8u(const uchar *a, const uchar *b, int len) {
constexpr int block_size0 = (1 << 15);
double r = 0;
int i = 0;
while (i < len) {
int block_size = std::min(block_size0, len - i);
vuint32m1_t s = __riscv_vmv_v_x_u32m1(0, __riscv_vsetvlmax_e32m1());
int vl;
for (int j = 0; j < block_size; j += vl) {
vl = __riscv_vsetvl_e8m4(block_size - j);
auto va = __riscv_vle8_v_u8m4(a + j, vl);
auto vb = __riscv_vle8_v_u8m4(b + j, vl);
s = __riscv_vwredsumu(__riscv_vwmulu(va, vb, vl), s, vl);
}
r += (double)__riscv_vmv_x(s);
i += block_size;
a += block_size;
b += block_size;
}
return r;
}
static inline double dotProd_8s(const schar *a, const schar *b, int len) {
constexpr int block_size0 = (1 << 14);
double r = 0;
int i = 0;
while (i < len) {
int block_size = std::min(block_size0, len - i);
vint32m1_t s = __riscv_vmv_v_x_i32m1(0, __riscv_vsetvlmax_e32m1());
int vl;
for (int j = 0; j < block_size; j += vl) {
vl = __riscv_vsetvl_e8m4(block_size - j);
auto va = __riscv_vle8_v_i8m4(a + j, vl);
auto vb = __riscv_vle8_v_i8m4(b + j, vl);
s = __riscv_vwredsum(__riscv_vwmul(va, vb, vl), s, vl);
}
r += (double)__riscv_vmv_x(s);
i += block_size;
a += block_size;
b += block_size;
}
return r;
}
static inline double dotProd_16u(const ushort *a, const ushort *b, int len) {
constexpr int block_size0 = (1 << 24);
double r = 0;
int i = 0;
while (i < len) {
int block_size = std::min(block_size0, len - i);
vuint64m1_t s = __riscv_vmv_v_x_u64m1(0, __riscv_vsetvlmax_e64m1());
int vl;
for (int j = 0; j < block_size; j += vl) {
vl = __riscv_vsetvl_e16m4(block_size - j);
auto va = __riscv_vle16_v_u16m4(a + j, vl);
auto vb = __riscv_vle16_v_u16m4(b + j, vl);
s = __riscv_vwredsumu(__riscv_vwmulu(va, vb, vl), s, vl);
}
r += (double)__riscv_vmv_x(s);
i += block_size;
a += block_size;
b += block_size;
}
return r;
}
static inline double dotProd_16s(const short *a, const short *b, int len) {
constexpr int block_size0 = (1 << 24);
double r = 0;
int i = 0;
while (i < len) {
int block_size = std::min(block_size0, len - i);
vint64m1_t s = __riscv_vmv_v_x_i64m1(0, __riscv_vsetvlmax_e64m1());
int vl;
for (int j = 0; j < block_size; j += vl) {
vl = __riscv_vsetvl_e16m4(block_size - j);
auto va = __riscv_vle16_v_i16m4(a + j, vl);
auto vb = __riscv_vle16_v_i16m4(b + j, vl);
s = __riscv_vwredsum(__riscv_vwmul(va, vb, vl), s, vl);
}
r += (double)__riscv_vmv_x(s);
i += block_size;
a += block_size;
b += block_size;
}
return r;
}
static inline double dotProd_32s(const int *a, const int *b, int len) {
double r = 0;
vfloat64m8_t s = __riscv_vfmv_v_f_f64m8(0.f, __riscv_vsetvlmax_e64m8());
int vl;
for (int j = 0; j < len; j += vl) {
vl = __riscv_vsetvl_e32m4(len - j);
auto va = __riscv_vle32_v_i32m4(a + j, vl);
auto vb = __riscv_vle32_v_i32m4(b + j, vl);
s = __riscv_vfadd_vv_f64m8_tu(s, s, __riscv_vfcvt_f(__riscv_vwmul(va, vb, vl), vl), vl);
}
r = __riscv_vfmv_f(__riscv_vfredosum(s, __riscv_vfmv_v_f_f64m1(0.f, __riscv_vsetvlmax_e64m1()), __riscv_vsetvlmax_e64m8()));
return r;
}
static inline double dotProd_32f(const float *a, const float *b, int len) {
constexpr int block_size0 = (1 << 11);
double r = 0.f;
int i = 0;
while (i < len) {
int block_size = std::min(block_size0, len - i);
vfloat32m4_t s = __riscv_vfmv_v_f_f32m4(0.f, __riscv_vsetvlmax_e32m4());
int vl;
for (int j = 0; j < block_size; j += vl) {
vl = __riscv_vsetvl_e32m4(block_size - j);
auto va = __riscv_vle32_v_f32m4(a + j, vl);
auto vb = __riscv_vle32_v_f32m4(b + j, vl);
s = __riscv_vfmacc_vv_f32m4_tu(s, va, vb, vl);
}
r += (double)__riscv_vfmv_f(__riscv_vfredusum(s, __riscv_vfmv_v_f_f32m1(0.f, __riscv_vsetvlmax_e32m1()), __riscv_vsetvlmax_e32m4()));
i += block_size;
a += block_size;
b += block_size;
}
return r;
}
} // anonymous
using DotProdFunc = double (*)(const uchar *a, const uchar *b, int len);
int dotprod(const uchar *a_data, size_t a_step, const uchar *b_data, size_t b_step,
int width, int height, int type, double *dot_val) {
int depth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
static DotProdFunc dotprod_tab[CV_DEPTH_MAX] = {
(DotProdFunc)dotProd_8u, (DotProdFunc)dotProd_8s,
(DotProdFunc)dotProd_16u, (DotProdFunc)dotProd_16s,
(DotProdFunc)dotProd_32s, (DotProdFunc)dotProd_32f,
nullptr, nullptr
};
DotProdFunc func = dotprod_tab[depth];
if (func == nullptr) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
size_t elem_size1 = static_cast<size_t>(CV_ELEM_SIZE1(type));
bool a_continuous = (a_step == width * elem_size1 * cn);
bool b_continuous = (b_step == width * elem_size1 * cn);
size_t nplanes = 1;
size_t len = width * height;
if (!a_continuous || !b_continuous) {
nplanes = height;
len = width;
}
len *= cn;
double r = 0;
auto _a = a_data;
auto _b = b_data;
for (size_t i = 0; i < nplanes; i++) {
if (!a_continuous || !b_continuous) {
_a = a_data + a_step * i;
_b = b_data + b_step * i;
}
r += func(_a, _b, len);
}
*dot_val = r;
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+562
View File
@@ -0,0 +1,562 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
template<typename T> struct rvv;
template<> struct rvv<float> : RVV_F32MF2
{
using T = RVV_F32MF2::VecType;
using TabType = RVV_U32M8;
using TabTypeF = RVV_SameLen<float, TabType>;
static inline void vlseg(const float* a, T& b, T& c, size_t d) { auto x = __riscv_vlseg2e32_v_f32mf2x2(a, d); b = __riscv_vget_v_f32mf2x2_f32mf2(x, 0), c = __riscv_vget_v_f32mf2x2_f32mf2(x, 1); }
static inline void vlsseg(const float* a, ptrdiff_t b, T& c, T& d, size_t e) { auto x = __riscv_vlsseg2e32_v_f32mf2x2(a, b, e); c = __riscv_vget_v_f32mf2x2_f32mf2(x, 0), d = __riscv_vget_v_f32mf2x2_f32mf2(x, 1); }
static inline void vsseg(float* a, T b, T c, size_t d) { __riscv_vsseg2e32(a, __riscv_vset_v_f32mf2_f32mf2x2(__riscv_vset_v_f32mf2_f32mf2x2(vfloat32mf2x2_t(), 0, b), 1, c), d); }
};
template<> struct rvv<double> : RVV_F64M1
{
using T = RVV_F64M1::VecType;
using TabType = RVV_U32M4;
using TabTypeF = RVV_SameLen<double, TabType>;
static inline void vlseg(const double* a, T& b, T& c, size_t d) { auto x = __riscv_vlseg2e64_v_f64m1x2(a, d); b = __riscv_vget_v_f64m1x2_f64m1(x, 0), c = __riscv_vget_v_f64m1x2_f64m1(x, 1); }
static inline void vlsseg(const double* a, ptrdiff_t b, T& c, T& d, size_t e) { auto x = __riscv_vlsseg2e64_v_f64m1x2(a, b, e); c = __riscv_vget_v_f64m1x2_f64m1(x, 0), d = __riscv_vget_v_f64m1x2_f64m1(x, 1); }
static inline void vsseg(double* a, T b, T c, size_t d) { __riscv_vsseg2e64(a, __riscv_vset_v_f64m1_f64m1x2(__riscv_vset_v_f64m1_f64m1x2(vfloat64m1x2_t(), 0, b), 1, c), d); }
};
// the algorithm is copied from core/src/dxt.cpp,
// in the function template static void cv::DFT and cv::DFT_R2, cv::DFT_R3, cv::DFT_R5
template <typename T>
inline int dft(const Complex<T>* src, Complex<T>* dst, int nf, int *factors, T scale, int* itab,
const Complex<T>* wave, int tab_size, int len, bool isInverse, bool noPermute)
{
int n = len;
int f_idx, nx;
int dw0 = tab_size, dw;
int i, j, k;
Complex<T> t;
using VT = typename rvv<T>::VecType;
using TabType = typename rvv<T>::TabType;
using TabTypeF = typename rvv<T>::TabTypeF;
int tab_step = tab_size == n ? 1 : tab_size == n*2 ? 2 : tab_size/n;
int vl;
// 0. shuffle data
if( dst != src )
{
if( !isInverse )
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_itab = TabType::vload_stride(reinterpret_cast<const uint*>(itab + i * tab_step), sizeof(int) * tab_step, vl);
vec_itab = __riscv_vmul(vec_itab, sizeof(T) * 2, vl);
auto vec_src_re = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_itab = __riscv_vadd(vec_itab, sizeof(T), vl);
auto vec_src_im = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
else
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_itab = TabType::vload_stride(reinterpret_cast<const uint*>(itab + i * tab_step), sizeof(int) * tab_step, vl);
vec_itab = __riscv_vmul(vec_itab, sizeof(T) * 2, vl);
auto vec_src_re = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_itab = __riscv_vadd(vec_itab, sizeof(T), vl);
auto vec_src_im = __riscv_vloxei32(reinterpret_cast<const T*>(src), vec_itab, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
}
else
{
// copied from core/src/dxt.cpp, it is slow to swap elements by intrinsics
if( !noPermute )
{
if( nf == 1 )
{
if( (n & 3) == 0 )
{
int n2 = n/2;
Complex<T>* dsth = dst + n2;
for( i = 0; i < n2; i += 2, itab += tab_step*2 )
{
j = itab[0];
t = dst[i+1], dst[i+1] = dsth[j], dsth[j] = t;
if( j > i )
{
t = dst[i], dst[i] = dst[j], dst[j] = t;
t = dsth[i+1], dsth[i+1] = dsth[j+1], dsth[j+1] = t;
}
}
}
// else do nothing
}
else
{
for( i = 0; i < n; i++, itab += tab_step )
{
j = itab[0];
if( j > i )
t = dst[i], dst[i] = dst[j], dst[j] = t;
}
}
}
if( isInverse )
{
for( i = 0; i < n; i += vl )
{
vl = TabType::setvl(n - i);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
}
n = 1;
// 1. power-2 transforms
if( (factors[0] & 1) == 0 )
{
// radix-4 transform
for( ; n*4 <= factors[0]; )
{
nx = n;
n *= 4;
dw0 /= 4;
for( i = 0; i < len; i += n )
{
Complex<T> *v0, *v1;
T r0, i0, r1, i1, r2, i2, r3, i3, r4, i4;
v0 = dst + i;
v1 = v0 + nx*2;
r0 = v1[0].re; i0 = v1[0].im;
r4 = v1[nx].re; i4 = v1[nx].im;
r1 = r0 + r4; i1 = i0 + i4;
r3 = i0 - i4; i3 = r4 - r0;
r2 = v0[0].re; i2 = v0[0].im;
r4 = v0[nx].re; i4 = v0[nx].im;
r0 = r2 + r4; i0 = i2 + i4;
r2 -= r4; i2 -= i4;
v0[0].re = r0 + r1; v0[0].im = i0 + i1;
v1[0].re = r0 - r1; v1[0].im = i0 - i1;
v0[nx].re = r2 + r3; v0[nx].im = i2 + i3;
v1[nx].re = r2 - r3; v1[nx].im = i2 - i3;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v0 = dst + i + j;
v1 = v0 + nx*2;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v1), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 3), sizeof(T) * dw0 * 6, vec_w_re, vec_w_im, vl);
auto vec_r3 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i3 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_i0, vec_i3, vl);
auto vec_i1 = __riscv_vfadd(vec_r0, vec_r3, vl);
vec_r3 = __riscv_vfsub(vec_r0, vec_r3, vl);
vec_i3 = __riscv_vfsub(vec_i3, vec_i0, vl);
VT vec_r4, vec_i4;
rvv<T>::vlseg(reinterpret_cast<const T*>(v0), vec_r4, vec_i4, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v0 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
vec_r0 = __riscv_vfadd(vec_r4, vec_r2, vl);
vec_i0 = __riscv_vfadd(vec_i4, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1), __riscv_vfsub(vec_r0, vec_r1, vl), __riscv_vfsub(vec_i0, vec_i1, vl), vl);
vec_r2 = __riscv_vfsub(vec_r4, vec_r2, vl);
vec_i2 = __riscv_vfsub(vec_i4, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0 + nx), __riscv_vfadd(vec_r2, vec_r3, vl), __riscv_vfadd(vec_i2, vec_i3, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1 + nx), __riscv_vfsub(vec_r2, vec_r3, vl), __riscv_vfsub(vec_i2, vec_i3, vl), vl);
}
}
}
for( ; n < factors[0]; )
{
// do the remaining radix-2 transform
nx = n;
n *= 2;
dw0 /= 2;
for( i = 0; i < len; i += n )
{
Complex<T>* v = dst + i;
T r0 = v[0].re + v[nx].re;
T i0 = v[0].im + v[nx].im;
T r1 = v[0].re - v[nx].re;
T i1 = v[0].im - v[nx].im;
v[0].re = r0; v[0].im = i0;
v[nx].re = r1; v[nx].im = i1;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v = dst + i + j;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r1 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i1 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
VT vec_r0, vec_i0;
rvv<T>::vlseg(reinterpret_cast<const T*>(v), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx), __riscv_vfsub(vec_r0, vec_r1, vl), __riscv_vfsub(vec_i0, vec_i1, vl), vl);
}
}
}
}
// 2. all the other transforms
for( f_idx = (factors[0]&1) ? 0 : 1; f_idx < nf; f_idx++ )
{
int factor = factors[f_idx];
nx = n;
n *= factor;
dw0 /= factor;
if( factor == 3 )
{
const T sin_120 = 0.86602540378443864676372317075294;
for( i = 0; i < len; i += n )
{
Complex<T>* v = dst + i;
T r1 = v[nx].re + v[nx*2].re;
T i1 = v[nx].im + v[nx*2].im;
T r0 = v[0].re;
T i0 = v[0].im;
T r2 = sin_120*(v[nx].im - v[nx*2].im);
T i2 = sin_120*(v[nx*2].re - v[nx].re);
v[0].re = r0 + r1; v[0].im = i0 + i1;
r0 -= (T)0.5*r1; i0 -= (T)0.5*i1;
v[nx].re = r0 + r2; v[nx].im = i0 + i2;
v[nx*2].re = r0 - r2; v[nx*2].im = i0 - i2;
for( j = 1; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
v = dst + i + j;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v + nx * 2), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_i2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_r0, vec_i2, vl);
auto vec_i1 = __riscv_vfadd(vec_i0, vec_r2, vl);
vec_r2 = __riscv_vfmul(__riscv_vfsub(vec_i0, vec_r2, vl), sin_120, vl);
vec_i2 = __riscv_vfmul(__riscv_vfsub(vec_i2, vec_r0, vl), sin_120, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v), __riscv_vfadd(vec_r0, vec_r1, vl), __riscv_vfadd(vec_i0, vec_i1, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, __riscv_vfmul(vec_r1, 0.5, vl), vl);
vec_i0 = __riscv_vfsub(vec_i0, __riscv_vfmul(vec_i1, 0.5, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx), __riscv_vfadd(vec_r0, vec_r2, vl), __riscv_vfadd(vec_i0, vec_i2, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v + nx * 2), __riscv_vfsub(vec_r0, vec_r2, vl), __riscv_vfsub(vec_i0, vec_i2, vl), vl);
}
}
}
else if( factor == 5 )
{
const T fft5_2 = 0.559016994374947424102293417182819;
const T fft5_3 = -0.951056516295153572116439333379382;
const T fft5_4 = -1.538841768587626701285145288018455;
const T fft5_5 = 0.363271264002680442947733378740309;
for( i = 0; i < len; i += n )
{
for( j = 0; j < nx; j += vl )
{
vl = rvv<T>::setvl(nx - j);
Complex<T>* v0 = dst + i + j;
Complex<T>* v1 = v0 + nx*2;
Complex<T>* v2 = v1 + nx*2;
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlseg(reinterpret_cast<const T*>(v0 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0), sizeof(T) * dw0 * 2, vec_w_re, vec_w_im, vl);
auto vec_r3 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i3 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v2), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 4), sizeof(T) * dw0 * 8, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_r1 = __riscv_vfadd(vec_r3, vec_r2, vl);
auto vec_i1 = __riscv_vfadd(vec_i3, vec_i2, vl);
vec_r3 = __riscv_vfsub(vec_r3, vec_r2, vl);
vec_i3 = __riscv_vfsub(vec_i3, vec_i2, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1 + nx), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 3), sizeof(T) * dw0 * 6, vec_w_re, vec_w_im, vl);
auto vec_r4 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i4 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v1), vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + j * dw0 * 2), sizeof(T) * dw0 * 4, vec_w_re, vec_w_im, vl);
auto vec_r0 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i0 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
vec_r2 = __riscv_vfadd(vec_r4, vec_r0, vl);
vec_i2 = __riscv_vfadd(vec_i4, vec_i0, vl);
vec_r4 = __riscv_vfsub(vec_r4, vec_r0, vl);
vec_i4 = __riscv_vfsub(vec_i4, vec_i0, vl);
rvv<T>::vlseg(reinterpret_cast<const T*>(v0), vec_r0, vec_i0, vl);
auto vec_r5 = __riscv_vfadd(vec_r1, vec_r2, vl);
auto vec_i5 = __riscv_vfadd(vec_i1, vec_i2, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0), __riscv_vfadd(vec_r0, vec_r5, vl), __riscv_vfadd(vec_i0, vec_i5, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, __riscv_vfmul(vec_r5, 0.25, vl), vl);
vec_i0 = __riscv_vfsub(vec_i0, __riscv_vfmul(vec_i5, 0.25, vl), vl);
vec_r1 = __riscv_vfmul(__riscv_vfsub(vec_r1, vec_r2, vl), fft5_2, vl);
vec_i1 = __riscv_vfmul(__riscv_vfsub(vec_i1, vec_i2, vl), fft5_2, vl);
vec_r2 = __riscv_vfmul(__riscv_vfadd(vec_i3, vec_i4, vl), -fft5_3, vl);
vec_i2 = __riscv_vfmul(__riscv_vfadd(vec_r3, vec_r4, vl), fft5_3, vl);
vec_i3 = __riscv_vfmul(vec_i3, -fft5_5, vl);
vec_r3 = __riscv_vfmul(vec_r3, fft5_5, vl);
vec_i4 = __riscv_vfmul(vec_i4, -fft5_4, vl);
vec_r4 = __riscv_vfmul(vec_r4, fft5_4, vl);
vec_r5 = __riscv_vfadd(vec_r2, vec_i3, vl);
vec_i5 = __riscv_vfadd(vec_i2, vec_r3, vl);
vec_r2 = __riscv_vfsub(vec_r2, vec_i4, vl);
vec_i2 = __riscv_vfsub(vec_i2, vec_r4, vl);
vec_r3 = __riscv_vfadd(vec_r0, vec_r1, vl);
vec_i3 = __riscv_vfadd(vec_i0, vec_i1, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v0 + nx), __riscv_vfadd(vec_r3, vec_r2, vl), __riscv_vfadd(vec_i3, vec_i2, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v2), __riscv_vfsub(vec_r3, vec_r2, vl), __riscv_vfsub(vec_i3, vec_i2, vl), vl);
vec_r0 = __riscv_vfsub(vec_r0, vec_r1, vl);
vec_i0 = __riscv_vfsub(vec_i0, vec_i1, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1), __riscv_vfadd(vec_r0, vec_r5, vl), __riscv_vfadd(vec_i0, vec_i5, vl), vl);
rvv<T>::vsseg(reinterpret_cast<T*>(v1 + nx), __riscv_vfsub(vec_r0, vec_r5, vl), __riscv_vfsub(vec_i0, vec_i5, vl), vl);
}
}
}
else
{
// radix-"factor" - an odd number
int p, q, factor2 = (factor - 1)/2;
int dd, dw_f = tab_size/factor;
std::vector<Complex<T> > buf(factor2 * 2);
Complex<T>* a = buf.data();
Complex<T>* b = a + factor2;
for( i = 0; i < len; i += n )
{
for( j = 0, dw = 0; j < nx; j++, dw += dw0 )
{
Complex<T>* v = dst + i + j;
Complex<T> v_0 = v[0];
Complex<T> vn_0 = v_0;
if( j == 0 )
{
for( p = 1; p <= factor2; p += vl )
{
vl = rvv<T>::setvl(factor2 + 1 - p);
VT vec_a_re, vec_a_im, vec_b_re, vec_b_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + nx * p), sizeof(T) * nx * 2, vec_a_re, vec_a_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + n - nx * p), (ptrdiff_t)sizeof(T) * nx * -2, vec_b_re, vec_b_im, vl);
auto vec_r0 = __riscv_vfadd(vec_a_re, vec_b_re, vl);
auto vec_r1 = __riscv_vfsub(vec_a_re, vec_b_re, vl);
auto vec_i0 = __riscv_vfsub(vec_a_im, vec_b_im, vl);
auto vec_i1 = __riscv_vfadd(vec_a_im, vec_b_im, vl);
vn_0.re += __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
vn_0.im += __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
rvv<T>::vsseg(reinterpret_cast<T*>(a + p - 1), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(b + p - 1), vec_r1, vec_i1, vl);
}
}
else
{
const Complex<T>* wave_ = wave + dw*factor;
for( p = 1; p <= factor2; p += vl )
{
vl = rvv<T>::setvl(factor2 + 1 - p);
VT vec_re, vec_im, vec_w_re, vec_w_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + nx * p), sizeof(T) * nx * 2, vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave + p * dw), sizeof(T) * dw * 2, vec_w_re, vec_w_im, vl);
auto vec_r2 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i2 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(v + n - nx * p), (ptrdiff_t)sizeof(T) * nx * -2, vec_re, vec_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(wave_ - p * dw), (ptrdiff_t)sizeof(T) * dw * -2, vec_w_re, vec_w_im, vl);
auto vec_r1 = __riscv_vfsub(__riscv_vfmul(vec_re, vec_w_re, vl), __riscv_vfmul(vec_im, vec_w_im, vl), vl);
auto vec_i1 = __riscv_vfadd(__riscv_vfmul(vec_re, vec_w_im, vl), __riscv_vfmul(vec_im, vec_w_re, vl), vl);
auto vec_r0 = __riscv_vfadd(vec_r2, vec_r1, vl);
auto vec_i0 = __riscv_vfsub(vec_i2, vec_i1, vl);
vec_r1 = __riscv_vfsub(vec_r2, vec_r1, vl);
vec_i1 = __riscv_vfadd(vec_i2, vec_i1, vl);
vn_0.re += __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
vn_0.im += __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
rvv<T>::vsseg(reinterpret_cast<T*>(a + p - 1), vec_r0, vec_i0, vl);
rvv<T>::vsseg(reinterpret_cast<T*>(b + p - 1), vec_r1, vec_i1, vl);
}
}
v[0] = vn_0;
for( p = 1, k = nx; p <= factor2; p++, k += nx )
{
Complex<T> s0 = v_0, s1 = v_0;
dd = dw_f*p;
vl = __riscv_vsetvlmax_e32mf2();
auto vec_dd = __riscv_vid_v_u32mf2(vl);
vec_dd = __riscv_vmul(vec_dd, dd, vl);
vec_dd = __riscv_vremu(vec_dd, tab_size, vl);
for( q = 0; q < factor2; q += vl )
{
vl = rvv<T>::setvl(factor2 - q);
auto vec_d = __riscv_vadd(vec_dd, (q + 1) * dd % tab_size, vl);
auto vmask = __riscv_vmsgeu(vec_d, tab_size, vl);
vec_d = __riscv_vsub_mu(vmask, vec_d, vec_d, tab_size, vl);
vec_d = __riscv_vmul(vec_d, sizeof(T) * 2, vl);
auto vec_w = __riscv_vloxei32(reinterpret_cast<const T*>(wave), vec_d, vl);
VT vec_a_re, vec_a_im, vec_b_re, vec_b_im;
rvv<T>::vlsseg(reinterpret_cast<const T*>(a + q), sizeof(T) * 2, vec_a_re, vec_a_im, vl);
rvv<T>::vlsseg(reinterpret_cast<const T*>(b + q), sizeof(T) * 2, vec_b_re, vec_b_im, vl);
auto vec_r0 = __riscv_vfmul(vec_w, vec_a_re, vl);
auto vec_r1 = __riscv_vfmul(vec_w, vec_b_im, vl);
vec_w = __riscv_vloxei32(reinterpret_cast<const T*>(wave) + 1, vec_d, vl);
auto vec_i0 = __riscv_vfmul(vec_w, vec_a_im, vl);
auto vec_i1 = __riscv_vfmul(vec_w, vec_b_re, vl);
T r0 = __riscv_vfmv_f(__riscv_vfredosum(vec_r0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T i0 = __riscv_vfmv_f(__riscv_vfredosum(vec_i0, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T r1 = __riscv_vfmv_f(__riscv_vfredosum(vec_r1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
T i1 = __riscv_vfmv_f(__riscv_vfredosum(vec_i1, RVV<T, LMUL_1>::vmv_s(0, vl), vl));
s1.re += r0 + i0; s0.re += r0 - i0;
s1.im += r1 - i1; s0.im += r1 + i1;
}
v[k] = s0;
v[n-k] = s1;
}
}
}
}
}
if( scale != 1 )
{
T re_scale = scale, im_scale = scale;
if( isInverse )
im_scale = -im_scale;
for( i = 0; i < len; i += vl )
{
vl = TabType::setvl(len - i);
auto vec_src_re = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i), sizeof(T) * 2, vl);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_re = __riscv_vfmul(vec_src_re, re_scale, vl);
vec_src_im = __riscv_vfmul(vec_src_im, im_scale, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i), sizeof(T) * 2, vec_src_re, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
else if( isInverse )
{
for( i = 0; i < len; i += vl )
{
vl = TabType::setvl(len - i);
auto vec_src_im = TabTypeF::vload_stride(reinterpret_cast<const T*>(dst + i) + 1, sizeof(T) * 2, vl);
vec_src_im = __riscv_vfneg(vec_src_im, vl);
TabTypeF::vstore_stride(reinterpret_cast<T*>(dst + i) + 1, sizeof(T) * 2, vec_src_im, vl);
}
}
return CV_HAL_ERROR_OK;
}
int dft(const uchar* src, uchar* dst, int depth, int nf, int *factors, double scale,
int* itab, void* wave, int tab_size, int n, bool isInverse, bool noPermute)
{
if( n == 0 )
return CV_HAL_ERROR_OK;
switch( depth )
{
case CV_32F:
return dft(reinterpret_cast<const Complex<float>*>(src), reinterpret_cast<Complex<float>*>(dst), nf, factors, (float)scale,
itab, reinterpret_cast<const Complex<float>*>(wave), tab_size, n, isInverse, noPermute);
case CV_64F:
return dft(reinterpret_cast<const Complex<double>*>(src), reinterpret_cast<Complex<double>*>(dst), nf, factors, (double)scale,
itab, reinterpret_cast<const Complex<double>*>(wave), tab_size, n, isInverse, noPermute);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+202
View File
@@ -0,0 +1,202 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace detail {
static constexpr size_t exp_scale = 6;
static constexpr size_t exp_tab_size = 1 << exp_scale;
static constexpr size_t exp_mask = exp_tab_size - 1;
static constexpr double exp_prescale = 1.4426950408889634073599246810019 * (1 << exp_scale);
static constexpr double exp_postscale = 1. / (1 << exp_scale);
// log10(DBL_MAX) < 3000
static constexpr double exp_max_val = (3000. * (1 << exp_scale)) / exp_prescale;
static constexpr double exp_min_val = -exp_max_val;
static constexpr double exp32f_a0 = .9670371139572337719125840413672004409288e-2;
static constexpr double exp32f_a1 = .5550339366753125211915322047004666939128e-1 / exp32f_a0;
static constexpr double exp32f_a2 = .2402265109513301490103372422686535526573 / exp32f_a0;
static constexpr double exp32f_a3 = .6931471805521448196800669615864773144641 / exp32f_a0;
static constexpr double exp32f_a4 = 1.000000000000002438532970795181890933776 / exp32f_a0;
static constexpr double exp64f_a0 = .13369713757180123244806654839424e-2 / exp32f_a0;
static constexpr double exp64f_a1 = .96180973140732918010002372686186e-2 / exp32f_a0;
static constexpr double exp64f_a2 = .55504108793649567998466049042729e-1 / exp32f_a0;
static constexpr double exp64f_a3 = .24022650695886477918181338054308 / exp32f_a0;
static constexpr double exp64f_a4 = .69314718055994546743029643825322 / exp32f_a0;
static constexpr double exp64f_a5 = .99999999999999999998285227504999 / exp32f_a0;
#define EXP_TAB_VALUE \
{ \
1.0 * exp32f_a0, \
1.0108892860517004600204097905619 * exp32f_a0, \
1.0218971486541166782344801347833 * exp32f_a0, \
1.0330248790212284225001082839705 * exp32f_a0, \
1.0442737824274138403219664787399 * exp32f_a0, \
1.0556451783605571588083413251529 * exp32f_a0, \
1.0671404006768236181695211209928 * exp32f_a0, \
1.0787607977571197937406800374385 * exp32f_a0, \
1.0905077326652576592070106557607 * exp32f_a0, \
1.1023825833078409435564142094256 * exp32f_a0, \
1.1143867425958925363088129569196 * exp32f_a0, \
1.126521618608241899794798643787 * exp32f_a0, \
1.1387886347566916537038302838415 * exp32f_a0, \
1.151189229952982705817759635202 * exp32f_a0, \
1.1637248587775775138135735990922 * exp32f_a0, \
1.1763969916502812762846457284838 * exp32f_a0, \
1.1892071150027210667174999705605 * exp32f_a0, \
1.2021567314527031420963969574978 * exp32f_a0, \
1.2152473599804688781165202513388 * exp32f_a0, \
1.2284805361068700056940089577928 * exp32f_a0, \
1.2418578120734840485936774687266 * exp32f_a0, \
1.2553807570246910895793906574423 * exp32f_a0, \
1.2690509571917332225544190810323 * exp32f_a0, \
1.2828700160787782807266697810215 * exp32f_a0, \
1.2968395546510096659337541177925 * exp32f_a0, \
1.3109612115247643419229917863308 * exp32f_a0, \
1.3252366431597412946295370954987 * exp32f_a0, \
1.3396675240533030053600306697244 * exp32f_a0, \
1.3542555469368927282980147401407 * exp32f_a0, \
1.3690024229745906119296011329822 * exp32f_a0, \
1.3839098819638319548726595272652 * exp32f_a0, \
1.3989796725383111402095281367152 * exp32f_a0, \
1.4142135623730950488016887242097 * exp32f_a0, \
1.4296133383919700112350657782751 * exp32f_a0, \
1.4451808069770466200370062414717 * exp32f_a0, \
1.4609177941806469886513028903106 * exp32f_a0, \
1.476826145939499311386907480374 * exp32f_a0, \
1.4929077282912648492006435314867 * exp32f_a0, \
1.5091644275934227397660195510332 * exp32f_a0, \
1.5255981507445383068512536895169 * exp32f_a0, \
1.5422108254079408236122918620907 * exp32f_a0, \
1.5590044002378369670337280894749 * exp32f_a0, \
1.5759808451078864864552701601819 * exp32f_a0, \
1.5931421513422668979372486431191 * exp32f_a0, \
1.6104903319492543081795206673574 * exp32f_a0, \
1.628027421857347766848218522014 * exp32f_a0, \
1.6457554781539648445187567247258 * exp32f_a0, \
1.6636765803267364350463364569764 * exp32f_a0, \
1.6817928305074290860622509524664 * exp32f_a0, \
1.7001063537185234695013625734975 * exp32f_a0, \
1.7186192981224779156293443764563 * exp32f_a0, \
1.7373338352737062489942020818722 * exp32f_a0, \
1.7562521603732994831121606193753 * exp32f_a0, \
1.7753764925265212525505592001993 * exp32f_a0, \
1.7947090750031071864277032421278 * exp32f_a0, \
1.8142521755003987562498346003623 * exp32f_a0, \
1.8340080864093424634870831895883 * exp32f_a0, \
1.8539791250833855683924530703377 * exp32f_a0, \
1.8741676341102999013299989499544 * exp32f_a0, \
1.8945759815869656413402186534269 * exp32f_a0, \
1.9152065613971472938726112702958 * exp32f_a0, \
1.9360617934922944505980559045667 * exp32f_a0, \
1.9571441241754002690183222516269 * exp32f_a0, \
1.9784560263879509682582499181312 * exp32f_a0, \
}
static constexpr float exp_tab_32f[exp_tab_size] = EXP_TAB_VALUE;
static constexpr double exp_tab_64f[exp_tab_size] = EXP_TAB_VALUE;
#undef EXP_TAB_VALUE
} // namespace detail
int exp32f(const float* src, float* dst, int _len)
{
size_t vl = __riscv_vsetvlmax_e32m4();
auto exp_a2 = __riscv_vfmv_v_f_f32m4(detail::exp32f_a2, vl);
auto exp_a3 = __riscv_vfmv_v_f_f32m4(detail::exp32f_a3, vl);
auto exp_a4 = __riscv_vfmv_v_f_f32m4(detail::exp32f_a4, vl);
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = __riscv_vsetvl_e32m4(len);
auto x0 = __riscv_vle32_v_f32m4(src, vl);
x0 = __riscv_vfmax(x0, detail::exp_min_val, vl);
x0 = __riscv_vfmin(x0, detail::exp_max_val, vl);
x0 = __riscv_vfmul(x0, detail::exp_prescale, vl);
auto xi = __riscv_vfcvt_rtz_x_f_v_i32m4(x0, vl);
x0 = __riscv_vfsub(x0, __riscv_vfcvt_f_x_v_f32m4(xi, vl), vl);
x0 = __riscv_vfmul(x0, detail::exp_postscale, vl);
auto t = __riscv_vsra(xi, detail::exp_scale, vl);
t = __riscv_vadd(t, 127, vl);
t = __riscv_vmax(t, 0, vl);
t = __riscv_vmin(t, 255, vl);
auto buf = __riscv_vreinterpret_f32m4(__riscv_vsll(t, 23, vl));
auto _xi = __riscv_vreinterpret_u32m4(xi);
_xi = __riscv_vsll(__riscv_vand(_xi, detail::exp_mask, vl), 2, vl);
auto tab_v = __riscv_vluxei32(detail::exp_tab_32f, _xi, vl);
auto res = __riscv_vfmul(buf, tab_v, vl);
auto xn = __riscv_vfadd(x0, detail::exp32f_a1, vl);
xn = __riscv_vfmadd(xn, x0, exp_a2, vl);
xn = __riscv_vfmadd(xn, x0, exp_a3, vl);
xn = __riscv_vfmadd(xn, x0, exp_a4, vl);
res = __riscv_vfmul(res, xn, vl);
__riscv_vse32(dst, res, vl);
}
return CV_HAL_ERROR_OK;
}
int exp64f(const double* src, double* dst, int _len)
{
size_t vl = __riscv_vsetvlmax_e64m4();
// all vector registers are used up, so not load more constants
auto exp_a2 = __riscv_vfmv_v_f_f64m4(detail::exp64f_a2, vl);
auto exp_a3 = __riscv_vfmv_v_f_f64m4(detail::exp64f_a3, vl);
auto exp_a4 = __riscv_vfmv_v_f_f64m4(detail::exp64f_a4, vl);
auto exp_a5 = __riscv_vfmv_v_f_f64m4(detail::exp64f_a5, vl);
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = __riscv_vsetvl_e64m4(len);
auto x0 = __riscv_vle64_v_f64m4(src, vl);
x0 = __riscv_vfmax(x0, detail::exp_min_val, vl);
x0 = __riscv_vfmin(x0, detail::exp_max_val, vl);
x0 = __riscv_vfmul(x0, detail::exp_prescale, vl);
auto xi = __riscv_vfcvt_rtz_x_f_v_i64m4(x0, vl);
x0 = __riscv_vfsub(x0, __riscv_vfcvt_f_x_v_f64m4(xi, vl), vl);
x0 = __riscv_vfmul(x0, detail::exp_postscale, vl);
auto t = __riscv_vsra(xi, detail::exp_scale, vl);
t = __riscv_vadd(t, 1023, vl);
t = __riscv_vmax(t, 0, vl);
t = __riscv_vmin(t, 2047, vl);
auto buf = __riscv_vreinterpret_f64m4(__riscv_vsll(t, 52, vl));
auto _xi = __riscv_vreinterpret_u64m4(xi);
_xi = __riscv_vsll(__riscv_vand(_xi, detail::exp_mask, vl), 3, vl);
auto tab_v = __riscv_vluxei64(detail::exp_tab_64f, _xi, vl);
auto res = __riscv_vfmul(buf, tab_v, vl);
auto xn = __riscv_vfadd(__riscv_vfmul(x0, detail::exp64f_a0, vl), detail::exp64f_a1, vl);
xn = __riscv_vfmadd(xn, x0, exp_a2, vl);
xn = __riscv_vfmadd(xn, x0, exp_a3, vl);
xn = __riscv_vfmadd(xn, x0, exp_a4, vl);
xn = __riscv_vfmadd(xn, x0, exp_a5, vl);
res = __riscv_vfmul(res, xn, vl);
__riscv_vse64(dst, res, vl);
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+409
View File
@@ -0,0 +1,409 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
#include "rvv_hal.hpp"
#if defined (__clang__) && __clang_major__ < 18
#define OPENCV_HAL_IMPL_RVV_VCREATE_x3(suffix, width, v0, v1, v2) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(v, 0, v0); \
v = __riscv_vset(v, 1, v1); \
v = __riscv_vset(v, 2, v2);
#define __riscv_vcreate_v_u8m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u8, 2, v0, v1, v2)
#define __riscv_vcreate_v_u16m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u16, 2, v0, v1, v2)
#define __riscv_vcreate_v_u32m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u32, 2, v0, v1, v2)
#define __riscv_vcreate_v_u64m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u64, 2, v0, v1, v2)
#endif
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
#define CV_HAL_RVV_FLIP_C1(name, _Tps, RVV) \
inline void flip_##name(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int src_width, int src_height, int flip_mode) { \
for (int h = 0; h < src_height; h++) { \
const _Tps* src_row = (const _Tps*)(src_data + src_step * h); \
_Tps* dst_row = (_Tps*)(dst_data + dst_step * (flip_mode < 0 ? (src_height - h) : (h + 1))); \
int vl; \
for (int w = 0; w < src_width; w += vl) { \
vl = RVV::setvl(src_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v = RVV::vload(src_row + w, vl); \
RVV::vstore(dst_row - w - vl, __riscv_vrgather(v, indices, vl), vl); \
} \
} \
}
CV_HAL_RVV_FLIP_C1(8UC1, uchar, RVV_U8M8)
CV_HAL_RVV_FLIP_C1(16UC1, ushort, RVV_U16M8)
CV_HAL_RVV_FLIP_C1(32UC1, unsigned, RVV_U32M8)
CV_HAL_RVV_FLIP_C1(64UC1, uint64_t, RVV_U64M8)
#define CV_HAL_RVV_FLIP_INPLACE_C1(name, _Tps, RVV) \
inline void flip_inplace_##name(uchar* data, size_t step, int width, int height, int flip_mode) { \
auto new_height = (flip_mode < 0 ? height / 2 : height); \
auto new_width = (flip_mode < 0 ? width : width / 2); \
int h; \
for (h = 0; h < new_height; h++) { \
_Tps* row_begin = (_Tps*)(data + step * h); \
_Tps* row_end = (_Tps*)(data + step * (flip_mode < 0 ? (height - h) : (h + 1))); \
int vl; \
for (int w = 0; w < new_width; w += vl) { \
vl = RVV::setvl(new_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v_left = RVV::vload(row_begin + w, vl); \
auto v_right = RVV::vload(row_end - w - vl, vl); \
RVV::vstore(row_begin + w, __riscv_vrgather(v_right, indices, vl), vl); \
RVV::vstore(row_end - w - vl, __riscv_vrgather(v_left, indices, vl), vl); \
} \
} \
if (flip_mode == -1 && new_height * 2 != height) { \
_Tps* row_begin = (_Tps*)(data + step * h); \
_Tps* row_end = (_Tps*)(data + step * (h + 1)); \
new_width /= 2; \
int vl; \
for (int w = 0; w < new_width; w += vl) { \
vl = RVV::setvl(new_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v_left = RVV::vload(row_begin + w, vl); \
auto v_right = RVV::vload(row_end - w - vl, vl); \
RVV::vstore(row_begin + w, __riscv_vrgather(v_right, indices, vl), vl); \
RVV::vstore(row_end - w - vl, __riscv_vrgather(v_left, indices, vl), vl); \
} \
} \
}
CV_HAL_RVV_FLIP_INPLACE_C1(8UC1, uchar, RVV_U8M8)
CV_HAL_RVV_FLIP_INPLACE_C1(16UC1, ushort, RVV_U16M8)
CV_HAL_RVV_FLIP_INPLACE_C1(32UC1, unsigned, RVV_U32M8)
CV_HAL_RVV_FLIP_INPLACE_C1(64UC1, uint64_t, RVV_U64M8)
// Suppress warnings of "ignoring attributes applied to VecType after definition",
// VecType is vuint8m2x3_t, vuint16m2x3_t, vuint32m2x3_t or vuint64m2x3_t
#if defined (__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wattributes"
#endif
#define CV_HAL_RVV_FLIP_C3_TYPES(width) \
struct RVV_C3_U##width##M2 : RVV_U##width##M2 { \
static inline vuint##width##m2x3_t vload3(const uint##width##_t *base, size_t vl) { return __riscv_vlseg3e##width##_v_u##width##m2x3(base, vl); } \
static inline vuint##width##m2x3_t vflip3(const vuint##width##m2x3_t &v_tuple, const vuint##width##m2_t &indices, size_t vl) { \
auto v0 = __riscv_vrgather(__riscv_vget_u##width##m2(v_tuple, 0), indices, vl); \
auto v1 = __riscv_vrgather(__riscv_vget_u##width##m2(v_tuple, 1), indices, vl); \
auto v2 = __riscv_vrgather(__riscv_vget_u##width##m2(v_tuple, 2), indices, vl); \
vuint##width##m2x3_t v = __riscv_vcreate_v_u##width##m2x3(v0, v1, v2); \
return v; \
} \
static inline void vstore3(uint##width##_t *base, const vuint##width##m2x3_t &v_tuple, size_t vl) { __riscv_vsseg3e##width(base, v_tuple, vl); } \
};
CV_HAL_RVV_FLIP_C3_TYPES(8)
CV_HAL_RVV_FLIP_C3_TYPES(16)
CV_HAL_RVV_FLIP_C3_TYPES(32)
CV_HAL_RVV_FLIP_C3_TYPES(64)
#if defined (__GNUC__)
#pragma GCC diagnostic pop
#endif
#define CV_HAL_RVV_FLIP_C3(name, _Tps, RVV) \
inline void flip_##name(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int src_width, int src_height, int flip_mode) { \
for (int h = 0; h < src_height; h++) { \
const _Tps* src_row = (const _Tps*)(src_data + src_step * h); \
_Tps* dst_row = (_Tps*)(dst_data + dst_step * (flip_mode < 0 ? (src_height - h) : (h + 1))); \
int vl; \
for (int w = 0; w < src_width; w += vl) { \
vl = RVV::setvl(src_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v = RVV::vload3(src_row + 3 * w, vl); \
auto flipped = RVV::vflip3(v, indices, vl); \
RVV::vstore3(dst_row - 3 * (w + vl), flipped, vl); \
} \
} \
}
CV_HAL_RVV_FLIP_C3(8UC3, uchar, RVV_C3_U8M2)
CV_HAL_RVV_FLIP_C3(16UC3, ushort, RVV_C3_U16M2)
CV_HAL_RVV_FLIP_C3(32UC3, unsigned, RVV_C3_U32M2)
CV_HAL_RVV_FLIP_C3(64UC3, uint64_t, RVV_C3_U64M2)
#define CV_HAL_RVV_FLIP_INPLACE_C3(name, _Tps, RVV) \
inline void flip_inplace_##name(uchar* data, size_t step, int width, int height, int flip_mode) { \
auto new_height = (flip_mode < 0 ? height / 2 : height); \
auto new_width = (flip_mode < 0 ? width : width / 2); \
int h; \
for (h = 0; h < new_height; h++) { \
_Tps* row_begin = (_Tps*)(data + step * h); \
_Tps* row_end = (_Tps*)(data + step * (flip_mode < 0 ? (height - h) : (h + 1))); \
int vl; \
for (int w = 0; w < new_width; w += vl) { \
vl = RVV::setvl(new_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v_left = RVV::vload3(row_begin + 3 * w, vl); \
auto flipped_left = RVV::vflip3(v_left, indices, vl); \
auto v_right = RVV::vload3(row_end - 3 * (w + vl), vl); \
auto flipped_right = RVV::vflip3(v_right, indices, vl); \
RVV::vstore3(row_begin + 3 * w, flipped_right, vl); \
RVV::vstore3(row_end - 3 * (w + vl), flipped_left, vl); \
} \
} \
if (flip_mode == -1 && new_height * 2 != height) { \
_Tps* row_begin = (_Tps*)(data + step * h); \
_Tps* row_end = (_Tps*)(data + step * (h + 1)); \
new_width /= 2; \
int vl; \
for (int w = 0; w < new_width; w += vl) { \
vl = RVV::setvl(new_width - w); \
RVV::VecType indices = __riscv_vrsub(RVV::vid(vl), vl - 1, vl); \
auto v_left = RVV::vload3(row_begin + 3 * w, vl); \
auto flipped_left = RVV::vflip3(v_left, indices, vl); \
auto v_right = RVV::vload3(row_end - 3 * (w + vl), vl); \
auto flipped_right = RVV::vflip3(v_right, indices, vl); \
RVV::vstore3(row_begin + 3 * w, flipped_right, vl); \
RVV::vstore3(row_end - 3 * (w + vl), flipped_left, vl); \
} \
} \
}
CV_HAL_RVV_FLIP_INPLACE_C3(8UC3, uchar, RVV_C3_U8M2)
CV_HAL_RVV_FLIP_INPLACE_C3(16UC3, ushort, RVV_C3_U16M2)
CV_HAL_RVV_FLIP_INPLACE_C3(32UC3, unsigned, RVV_C3_U32M2)
CV_HAL_RVV_FLIP_INPLACE_C3(64UC3, uint64_t, RVV_C3_U64M2)
struct FlipVlen256
{
using SrcType = RVV_U8M8;
using TabType = RVV_U8M8;
using TabVecType = typename TabType::VecType;
static inline void gather(const uchar* src, TabVecType tab, uchar* dst, size_t vl)
{
auto src_v = SrcType::vload(src, vl);
SrcType::vstore(dst, __riscv_vrgather(src_v, tab, vl), vl);
}
};
struct FlipVlen512 : RVV_U8M8
{
using SrcType = RVV_U8M4;
using TabType = RVV_U16M8;
using TabVecType = typename TabType::VecType;
static inline void gather(const uchar* src, TabVecType tab, uchar* dst, size_t vl)
{
auto src_v = SrcType::vload(src, vl);
SrcType::vstore(dst, __riscv_vrgatherei16(src_v, tab, vl), vl);
}
};
template <typename T>
inline void flipFillBuffer(T* buf, size_t len, int esz)
{
for (int i = (int)len - esz; i >= 0; i -= esz, buf += esz)
for (int j = 0; j < esz; j++)
buf[j] = (T)(i + j);
}
template <typename FlipVlen,
typename SrcType = typename FlipVlen::SrcType,
typename TabType = typename FlipVlen::TabType>
inline void flipY(int esz,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step)
{
size_t w = (size_t)src_width * esz;
size_t vl = std::min(SrcType::setvlmax() / esz * esz, w);
typename TabType::VecType tab_v;
if (esz == 1)
tab_v = __riscv_vrsub(TabType::vid(vl), vl - 1, vl);
else
{
// max vlen supported is 1024 (vlmax of u8m4 for vlen 1024 is 512)
typename TabType::ElemType buf[512];
flipFillBuffer(buf, vl, esz);
tab_v = TabType::vload(buf, vl);
}
if (vl == w)
for (; src_height; src_height--, src_data += src_step, dst_data += dst_step)
FlipVlen::gather(src_data, tab_v, dst_data, vl);
else
for (; src_height; src_height--, src_data += src_step, dst_data += dst_step)
{
auto src0 = src_data, src1 = src_data + w - vl;
auto dst0 = dst_data, dst1 = dst_data + w - vl;
for (; src0 < src1 + vl; src0 += vl, src1 -= vl, dst0 += vl, dst1 -= vl)
{
FlipVlen::gather(src0, tab_v, dst1, vl);
FlipVlen::gather(src1, tab_v, dst0, vl);
}
}
}
template <typename FlipVlen,
typename SrcType = typename FlipVlen::SrcType,
typename TabType = typename FlipVlen::TabType>
inline void flipXY(int esz,
const uchar* src_data,
size_t src_step,
int src_width,
int src_height,
uchar* dst_data,
size_t dst_step)
{
size_t w = (size_t)src_width * esz;
size_t vl = std::min(SrcType::setvlmax() / esz * esz, w);
typename TabType::VecType tab_v;
if (esz == 1)
tab_v = __riscv_vrsub(TabType::vid(vl), vl - 1, vl);
else
{
// max vlen supported is 1024 (vlmax of u8m4 for vlen 1024 is 512)
typename TabType::ElemType buf[512];
flipFillBuffer(buf, vl, esz);
tab_v = TabType::vload(buf, vl);
}
auto src0 = src_data, src1 = src_data + src_step * (src_height - 1);
auto dst0 = dst_data, dst1 = dst_data + dst_step * (src_height - 1);
if (vl == w)
{
for (src_height -= 2; src_height >= 0;
src_height -= 2,
src0 += src_step,
dst0 += dst_step,
src1 -= src_step,
dst1 -= dst_step)
{
FlipVlen::gather(src0, tab_v, dst1, vl);
FlipVlen::gather(src1, tab_v, dst0, vl);
}
if (src_height == -1)
{
FlipVlen::gather(src1, tab_v, dst0, vl);
}
}
else
{
for (src_height -= 2; src_height >= 0;
src_height -= 2,
src0 += src_step,
dst0 += dst_step,
src1 -= src_step,
dst1 -= dst_step)
{
for (size_t i = 0; 2 * i < w; i += vl)
{
FlipVlen::gather(src0 + i, tab_v, dst1 + w - i - vl, vl);
FlipVlen::gather(src0 + w - i - vl, tab_v, dst1 + i, vl);
FlipVlen::gather(src1 + i, tab_v, dst0 + w - i - vl, vl);
FlipVlen::gather(src1 + w - i - vl, tab_v, dst0 + i, vl);
}
}
if (src_height == -1)
{
for (size_t i = 0; 2 * i < w; i += vl)
{
FlipVlen::gather(src1 + i, tab_v, dst0 + w - i - vl, vl);
FlipVlen::gather(src1 + w - i - vl, tab_v, dst0 + i, vl);
}
}
}
}
} // namespace anonymous
inline int flip_inplace(int esz, uchar* data, size_t step, int width, int height, int flip_mode) {
if (flip_mode == 0) {
for (int h = 0; h < (height / 2); h++) {
uchar* top_row = data + step * h;
uchar* bottom_row = data + step * (height - h - 1);
std::swap_ranges(top_row, top_row + esz * width, bottom_row);
}
return CV_HAL_ERROR_OK;
}
using FlipInplaceFunc = void (*)(uchar*, size_t, int, int, int);
static FlipInplaceFunc flip_inplace_func_tab[] = {
0, flip_inplace_8UC1, flip_inplace_16UC1, flip_inplace_8UC3,
flip_inplace_32UC1, 0, flip_inplace_16UC3, 0,
flip_inplace_64UC1, 0, 0, 0,
flip_inplace_32UC3, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
flip_inplace_64UC3, 0, 0, 0,
0, 0, 0, 0,
0
};
FlipInplaceFunc func = esz <= 32 ? flip_inplace_func_tab[esz] : nullptr;
if (!func) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
func(data, step, width, height, flip_mode);
return CV_HAL_ERROR_OK;
}
int flip(int src_type, const uchar* src_data, size_t src_step, int src_width, int src_height,
uchar* dst_data, size_t dst_step, int flip_mode)
{
int esz = CV_ELEM_SIZE(src_type);
if (src_width < 0 || src_height < 0 || esz > 32)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_data == dst_data) {
return flip_inplace(esz, dst_data, dst_step, src_width, src_height, flip_mode);
}
if (flip_mode == 0)
{
for (int h = 0; h < src_height; h++) {
const uchar* src_row = src_data + src_step * h;
uchar* dst_row = dst_data + dst_step * (src_height - h - 1);
std::memcpy(dst_row, src_row, esz * src_width);
}
return CV_HAL_ERROR_OK;
}
using FlipFunc = void (*)(const uchar*, size_t, uchar*, size_t, int, int, int);
static FlipFunc flip_func_tab[] = {
0, flip_8UC1, flip_16UC1, flip_8UC3,
flip_32UC1, 0, flip_16UC3, 0,
flip_64UC1, 0, 0, 0,
flip_32UC3, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
flip_64UC3, 0, 0, 0,
0, 0, 0, 0,
0
};
FlipFunc func = esz <= 32 ? flip_func_tab[esz] : nullptr;
if (func) {
func(src_data, src_step, dst_data, dst_step, src_width, src_height, flip_mode);
return CV_HAL_ERROR_OK;
}
if (flip_mode > 0)
{
if (__riscv_vlenb() * 8 <= 256)
flipY<FlipVlen256>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
else
flipY<FlipVlen512>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
}
else
{
if (__riscv_vlenb() * 8 <= 256)
flipXY<FlipVlen256>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
else
flipXY<FlipVlen512>(esz, src_data, src_step, src_width, src_height, dst_data, dst_step);
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+381
View File
@@ -0,0 +1,381 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace detail {
static constexpr size_t log_scale = 8;
static constexpr size_t log_tab_size = ((size_t)1 << log_scale) * 2;
static constexpr size_t log_mask = log_tab_size - 2;
static constexpr double ln_2 = 0.69314718055994530941723212145818;
static constexpr size_t log32f_mask = ((size_t)1 << (23 - log_scale)) - 1;
static constexpr double log32f_a0 = 0.3333333333333333333333333f;
static constexpr double log32f_a1 = -0.5f;
static constexpr double log32f_a2 = 1.f;
static constexpr size_t log64f_mask = ((size_t)1 << (52 - log_scale)) - 1;
static constexpr double log64f_a0 = -0.125;
static constexpr double log64f_a1 = 0.1428571428571428769682682968777953647077083587646484375;
static constexpr double log64f_a2 = -0.1666666666666666574148081281236954964697360992431640625;
static constexpr double log64f_a3 = 0.2;
static constexpr double log64f_a4 = -0.25;
static constexpr double log64f_a5 = 0.333333333333333314829616256247390992939472198486328125;
static constexpr double log64f_a6 = -0.5;
static constexpr double log64f_a7 = 1.0;
#define LOG_TAB_VALUE \
{ \
0.0000000000000000000000000000000000000000, 1.000000000000000000000000000000000000000, \
.00389864041565732288852075271279318258166, .9961089494163424124513618677042801556420, \
.00778214044205494809292034119607706088573, .9922480620155038759689922480620155038760, \
.01165061721997527263705585198749759001657, .9884169884169884169884169884169884169884, \
.01550418653596525274396267235488267033361, .9846153846153846153846153846153846153846, \
.01934296284313093139406447562578250654042, .9808429118773946360153256704980842911877, \
.02316705928153437593630670221500622574241, .9770992366412213740458015267175572519084, \
.02697658769820207233514075539915211265906, .9733840304182509505703422053231939163498, \
.03077165866675368732785500469617545604706, .9696969696969696969696969696969696969697, \
.03455238150665972812758397481047722976656, .9660377358490566037735849056603773584906, \
.03831886430213659461285757856785494368522, .9624060150375939849624060150375939849624, \
.04207121392068705056921373852674150839447, .9588014981273408239700374531835205992509, \
.04580953603129420126371940114040626212953, .9552238805970149253731343283582089552239, \
.04953393512227662748292900118940451648088, .9516728624535315985130111524163568773234, \
.05324451451881227759255210685296333394944, .9481481481481481481481481481481481481481, \
.05694137640013842427411105973078520037234, .9446494464944649446494464944649446494465, \
.06062462181643483993820353816772694699466, .9411764705882352941176470588235294117647, \
.06429435070539725460836422143984236754475, .9377289377289377289377289377289377289377, \
.06795066190850773679699159401934593915938, .9343065693430656934306569343065693430657, \
.07159365318700880442825962290953611955044, .9309090909090909090909090909090909090909, \
.07522342123758751775142172846244648098944, .9275362318840579710144927536231884057971, \
.07884006170777602129362549021607264876369, .9241877256317689530685920577617328519856, \
.08244366921107458556772229485432035289706, .9208633093525179856115107913669064748201, \
.08603433734180314373940490213499288074675, .9175627240143369175627240143369175627240, \
.08961215868968712416897659522874164395031, .9142857142857142857142857142857142857143, \
.09317722485418328259854092721070628613231, .9110320284697508896797153024911032028470, \
.09672962645855109897752299730200320482256, .9078014184397163120567375886524822695035, \
.10026945316367513738597949668474029749630, .9045936395759717314487632508833922261484, \
.10379679368164355934833764649738441221420, .9014084507042253521126760563380281690141, \
.10731173578908805021914218968959175981580, .8982456140350877192982456140350877192982, \
.11081436634029011301105782649756292812530, .8951048951048951048951048951048951048951, \
.11430477128005862852422325204315711744130, .8919860627177700348432055749128919860627, \
.11778303565638344185817487641543266363440, .8888888888888888888888888888888888888889, \
.12124924363286967987640707633545389398930, .8858131487889273356401384083044982698962, \
.12470347850095722663787967121606925502420, .8827586206896551724137931034482758620690, \
.12814582269193003360996385708858724683530, .8797250859106529209621993127147766323024, \
.13157635778871926146571524895989568904040, .8767123287671232876712328767123287671233, \
.13499516453750481925766280255629681050780, .8737201365187713310580204778156996587031, \
.13840232285911913123754857224412262439730, .8707482993197278911564625850340136054422, \
.14179791186025733629172407290752744302150, .8677966101694915254237288135593220338983, \
.14518200984449788903951628071808954700830, .8648648648648648648648648648648648648649, \
.14855469432313711530824207329715136438610, .8619528619528619528619528619528619528620, \
.15191604202584196858794030049466527998450, .8590604026845637583892617449664429530201, \
.15526612891112392955683674244937719777230, .8561872909698996655518394648829431438127, \
.15860503017663857283636730244325008243330, .8533333333333333333333333333333333333333, \
.16193282026931324346641360989451641216880, .8504983388704318936877076411960132890365, \
.16524957289530714521497145597095368430010, .8476821192052980132450331125827814569536, \
.16855536102980664403538924034364754334090, .8448844884488448844884488448844884488449, \
.17185025692665920060697715143760433420540, .8421052631578947368421052631578947368421, \
.17513433212784912385018287750426679849630, .8393442622950819672131147540983606557377, \
.17840765747281828179637841458315961062910, .8366013071895424836601307189542483660131, \
.18167030310763465639212199675966985523700, .8338762214983713355048859934853420195440, \
.18492233849401198964024217730184318497780, .8311688311688311688311688311688311688312, \
.18816383241818296356839823602058459073300, .8284789644012944983818770226537216828479, \
.19139485299962943898322009772527962923050, .8258064516129032258064516129032258064516, \
.19461546769967164038916962454095482826240, .8231511254019292604501607717041800643087, \
.19782574332991986754137769821682013571260, .8205128205128205128205128205128205128205, \
.20102574606059073203390141770796617493040, .8178913738019169329073482428115015974441, \
.20421554142869088876999228432396193966280, .8152866242038216560509554140127388535032, \
.20739519434607056602715147164417430758480, .8126984126984126984126984126984126984127, \
.21056476910734961416338251183333341032260, .8101265822784810126582278481012658227848, \
.21372432939771812687723695489694364368910, .8075709779179810725552050473186119873817, \
.21687393830061435506806333251006435602900, .8050314465408805031446540880503144654088, \
.22001365830528207823135744547471404075630, .8025078369905956112852664576802507836991, \
.22314355131420973710199007200571941211830, .8000000000000000000000000000000000000000, \
.22626367865045338145790765338460914790630, .7975077881619937694704049844236760124611, \
.22937410106484582006380890106811420992010, .7950310559006211180124223602484472049689, \
.23247487874309405442296849741978803649550, .7925696594427244582043343653250773993808, \
.23556607131276688371634975283086532726890, .7901234567901234567901234567901234567901, \
.23864773785017498464178231643018079921600, .7876923076923076923076923076923076923077, \
.24171993688714515924331749374687206000090, .7852760736196319018404907975460122699387, \
.24478272641769091566565919038112042471760, .7828746177370030581039755351681957186544, \
.24783616390458124145723672882013488560910, .7804878048780487804878048780487804878049, \
.25088030628580937353433455427875742316250, .7781155015197568389057750759878419452888, \
.25391520998096339667426946107298135757450, .7757575757575757575757575757575757575758, \
.25694093089750041913887912414793390780680, .7734138972809667673716012084592145015106, \
.25995752443692604627401010475296061486000, .7710843373493975903614457831325301204819, \
.26296504550088134477547896494797896593800, .7687687687687687687687687687687687687688, \
.26596354849713793599974565040611196309330, .7664670658682634730538922155688622754491, \
.26895308734550393836570947314612567424780, .7641791044776119402985074626865671641791, \
.27193371548364175804834985683555714786050, .7619047619047619047619047619047619047619, \
.27490548587279922676529508862586226314300, .7596439169139465875370919881305637982196, \
.27786845100345625159121709657483734190480, .7573964497041420118343195266272189349112, \
.28082266290088775395616949026589281857030, .7551622418879056047197640117994100294985, \
.28376817313064456316240580235898960381750, .7529411764705882352941176470588235294118, \
.28670503280395426282112225635501090437180, .7507331378299120234604105571847507331378, \
.28963329258304265634293983566749375313530, .7485380116959064327485380116959064327485, \
.29255300268637740579436012922087684273730, .7463556851311953352769679300291545189504, \
.29546421289383584252163927885703742504130, .7441860465116279069767441860465116279070, \
.29836697255179722709783618483925238251680, .7420289855072463768115942028985507246377, \
.30126133057816173455023545102449133992200, .7398843930635838150289017341040462427746, \
.30414733546729666446850615102448500692850, .7377521613832853025936599423631123919308, \
.30702503529491181888388950937951449304830, .7356321839080459770114942528735632183908, \
.30989447772286465854207904158101882785550, .7335243553008595988538681948424068767908, \
.31275571000389684739317885942000430077330, .7314285714285714285714285714285714285714, \
.31560877898630329552176476681779604405180, .7293447293447293447293447293447293447293, \
.31845373111853458869546784626436419785030, .7272727272727272727272727272727272727273, \
.32129061245373424782201254856772720813750, .7252124645892351274787535410764872521246, \
.32411946865421192853773391107097268104550, .7231638418079096045197740112994350282486, \
.32694034499585328257253991068864706903700, .7211267605633802816901408450704225352113, \
.32975328637246797969240219572384376078850, .7191011235955056179775280898876404494382, \
.33255833730007655635318997155991382896900, .7170868347338935574229691876750700280112, \
.33535554192113781191153520921943709254280, .7150837988826815642458100558659217877095, \
.33814494400871636381467055798566434532400, .7130919220055710306406685236768802228412, \
.34092658697059319283795275623560883104800, .7111111111111111111111111111111111111111, \
.34370051385331840121395430287520866841080, .7091412742382271468144044321329639889197, \
.34646676734620857063262633346312213689100, .7071823204419889502762430939226519337017, \
.34922538978528827602332285096053965389730, .7052341597796143250688705234159779614325, \
.35197642315717814209818925519357435405250, .7032967032967032967032967032967032967033, \
.35471990910292899856770532096561510115850, .7013698630136986301369863013698630136986, \
.35745588892180374385176833129662554711100, .6994535519125683060109289617486338797814, \
.36018440357500774995358483465679455548530, .6975476839237057220708446866485013623978, \
.36290549368936841911903457003063522279280, .6956521739130434782608695652173913043478, \
.36561919956096466943762379742111079394830, .6937669376693766937669376693766937669377, \
.36832556115870762614150635272380895912650, .6918918918918918918918918918918918918919, \
.37102461812787262962487488948681857436900, .6900269541778975741239892183288409703504, \
.37371640979358405898480555151763837784530, .6881720430107526881720430107526881720430, \
.37640097516425302659470730759494472295050, .6863270777479892761394101876675603217158, \
.37907835293496944251145919224654790014030, .6844919786096256684491978609625668449198, \
.38174858149084833769393299007788300514230, .6826666666666666666666666666666666666667, \
.38441169891033200034513583887019194662580, .6808510638297872340425531914893617021277, \
.38706774296844825844488013899535872042180, .6790450928381962864721485411140583554377, \
.38971675114002518602873692543653305619950, .6772486772486772486772486772486772486772, \
.39235876060286384303665840889152605086580, .6754617414248021108179419525065963060686, \
.39499380824086893770896722344332374632350, .6736842105263157894736842105263157894737, \
.39762193064713846624158577469643205404280, .6719160104986876640419947506561679790026, \
.40024316412701266276741307592601515352730, .6701570680628272251308900523560209424084, \
.40285754470108348090917615991202183067800, .6684073107049608355091383812010443864230, \
.40546510810816432934799991016916465014230, .6666666666666666666666666666666666666667, \
.40806588980822172674223224930756259709600, .6649350649350649350649350649350649350649, \
.41065992498526837639616360320360399782650, .6632124352331606217616580310880829015544, \
.41324724855021932601317757871584035456180, .6614987080103359173126614987080103359173, \
.41582789514371093497757669865677598863850, .6597938144329896907216494845360824742268, \
.41840189913888381489925905043492093682300, .6580976863753213367609254498714652956298, \
.42096929464412963239894338585145305842150, .6564102564102564102564102564102564102564, \
.42353011550580327293502591601281892508280, .6547314578005115089514066496163682864450, \
.42608439531090003260516141381231136620050, .6530612244897959183673469387755102040816, \
.42863216738969872610098832410585600882780, .6513994910941475826972010178117048346056, \
.43117346481837132143866142541810404509300, .6497461928934010152284263959390862944162, \
.43370832042155937902094819946796633303180, .6481012658227848101265822784810126582278, \
.43623676677491801667585491486534010618930, .6464646464646464646464646464646464646465, \
.43875883620762790027214350629947148263450, .6448362720403022670025188916876574307305, \
.44127456080487520440058801796112675219780, .6432160804020100502512562814070351758794, \
.44378397241030093089975139264424797147500, .6416040100250626566416040100250626566416, \
.44628710262841947420398014401143882423650, .6400000000000000000000000000000000000000, \
.44878398282700665555822183705458883196130, .6384039900249376558603491271820448877805, \
.45127464413945855836729492693848442286250, .6368159203980099502487562189054726368159, \
.45375911746712049854579618113348260521900, .6352357320099255583126550868486352357320, \
.45623743348158757315857769754074979573500, .6336633663366336633663366336633663366337, \
.45870962262697662081833982483658473938700, .6320987654320987654320987654320987654321, \
.46117571512217014895185229761409573256980, .6305418719211822660098522167487684729064, \
.46363574096303250549055974261136725544930, .6289926289926289926289926289926289926290, \
.46608972992459918316399125615134835243230, .6274509803921568627450980392156862745098, \
.46853771156323925639597405279346276074650, .6259168704156479217603911980440097799511, \
.47097971521879100631480241645476780831830, .6243902439024390243902439024390243902439, \
.47341577001667212165614273544633761048330, .6228710462287104622871046228710462287105, \
.47584590486996386493601107758877333253630, .6213592233009708737864077669902912621359, \
.47827014848147025860569669930555392056700, .6198547215496368038740920096852300242131, \
.48068852934575190261057286988943815231330, .6183574879227053140096618357487922705314, \
.48310107575113581113157579238759353756900, .6168674698795180722891566265060240963855, \
.48550781578170076890899053978500887751580, .6153846153846153846153846153846153846154, \
.48790877731923892879351001283794175833480, .6139088729016786570743405275779376498801, \
.49030398804519381705802061333088204264650, .6124401913875598086124401913875598086124, \
.49269347544257524607047571407747454941280, .6109785202863961813842482100238663484487, \
.49507726679785146739476431321236304938800, .6095238095238095238095238095238095238095, \
.49745538920281889838648226032091770321130, .6080760095011876484560570071258907363420, \
.49982786955644931126130359189119189977650, .6066350710900473933649289099526066350711, \
.50219473456671548383667413872899487614650, .6052009456264775413711583924349881796690, \
.50455601075239520092452494282042607665050, .6037735849056603773584905660377358490566, \
.50691172444485432801997148999362252652650, .6023529411764705882352941176470588235294, \
.50926190178980790257412536448100581765150, .6009389671361502347417840375586854460094, \
.51160656874906207391973111953120678663250, .5995316159250585480093676814988290398126, \
.51394575110223428282552049495279788970950, .5981308411214953271028037383177570093458, \
.51627947444845445623684554448118433356300, .5967365967365967365967365967365967365967, \
.51860776420804555186805373523384332656850, .5953488372093023255813953488372093023256, \
.52093064562418522900344441950437612831600, .5939675174013921113689095127610208816705, \
.52324814376454775732838697877014055848100, .5925925925925925925925925925925925925926, \
.52556028352292727401362526507000438869000, .5912240184757505773672055427251732101617, \
.52786708962084227803046587723656557500350, .5898617511520737327188940092165898617512, \
.53016858660912158374145519701414741575700, .5885057471264367816091954022988505747126, \
.53246479886947173376654518506256863474850, .5871559633027522935779816513761467889908, \
.53475575061602764748158733709715306758900, .5858123569794050343249427917620137299771, \
.53704146589688361856929077475797384977350, .5844748858447488584474885844748858447489, \
.53932196859560876944783558428753167390800, .5831435079726651480637813211845102505695, \
.54159728243274429804188230264117009937750, .5818181818181818181818181818181818181818, \
.54386743096728351609669971367111429572100, .5804988662131519274376417233560090702948, \
.54613243759813556721383065450936555862450, .5791855203619909502262443438914027149321, \
.54839232556557315767520321969641372561450, .5778781038374717832957110609480812641084, \
.55064711795266219063194057525834068655950, .5765765765765765765765765765765765765766, \
.55289683768667763352766542084282264113450, .5752808988764044943820224719101123595506, \
.55514150754050151093110798683483153581600, .5739910313901345291479820627802690582960, \
.55738115013400635344709144192165695130850, .5727069351230425055928411633109619686801, \
.55961578793542265941596269840374588966350, .5714285714285714285714285714285714285714, \
.56184544326269181269140062795486301183700, .5701559020044543429844097995545657015590, \
.56407013828480290218436721261241473257550, .5688888888888888888888888888888888888889, \
.56628989502311577464155334382667206227800, .5676274944567627494456762749445676274945, \
.56850473535266865532378233183408156037350, .5663716814159292035398230088495575221239, \
.57071468100347144680739575051120482385150, .5651214128035320088300220750551876379691, \
.57291975356178548306473885531886480748650, .5638766519823788546255506607929515418502, \
.57511997447138785144460371157038025558000, .5626373626373626373626373626373626373626, \
.57731536503482350219940144597785547375700, .5614035087719298245614035087719298245614, \
.57950594641464214795689713355386629700650, .5601750547045951859956236323851203501094, \
.58169173963462239562716149521293118596100, .5589519650655021834061135371179039301310, \
.58387276558098266665552955601015128195300, .5577342047930283224400871459694989106754, \
.58604904500357812846544902640744112432000, .5565217391304347826086956521739130434783, \
.58822059851708596855957011939608491957200, .5553145336225596529284164859002169197397, \
.59038744660217634674381770309992134571100, .5541125541125541125541125541125541125541, \
.59254960960667157898740242671919986605650, .5529157667386609071274298056155507559395, \
.59470710774669277576265358220553025603300, .5517241379310344827586206896551724137931, \
.59685996110779382384237123915227130055450, .5505376344086021505376344086021505376344, \
.59900818964608337768851242799428291618800, .5493562231759656652360515021459227467811, \
.60115181318933474940990890900138765573500, .5481798715203426124197002141327623126338, \
.60329085143808425240052883964381180703650, .5470085470085470085470085470085470085470, \
.60542532396671688843525771517306566238400, .5458422174840085287846481876332622601279, \
.60755525022454170969155029524699784815300, .5446808510638297872340425531914893617021, \
.60968064953685519036241657886421307921400, .5435244161358811040339702760084925690021, \
.61180154110599282990534675263916142284850, .5423728813559322033898305084745762711864, \
.61391794401237043121710712512140162289150, .5412262156448202959830866807610993657505, \
.61602987721551394351138242200249806046500, .5400843881856540084388185654008438818565, \
.61813735955507864705538167982012964785100, .5389473684210526315789473684210526315789, \
.62024040975185745772080281312810257077200, .5378151260504201680672268907563025210084, \
.62233904640877868441606324267922900617100, .5366876310272536687631027253668763102725, \
.62443328801189346144440150965237990021700, .5355648535564853556485355648535564853556, \
.62652315293135274476554741340805776417250, .5344467640918580375782881002087682672234, \
.62860865942237409420556559780379757285100, .5333333333333333333333333333333333333333, \
.63068982562619868570408243613201193511500, .5322245322245322245322245322245322245322, \
.63276666957103777644277897707070223987100, .5311203319502074688796680497925311203320, \
.63483920917301017716738442686619237065300, .5300207039337474120082815734989648033126, \
.63690746223706917739093569252872839570050, .5289256198347107438016528925619834710744, \
.63897144645792069983514238629140891134750, .5278350515463917525773195876288659793814, \
.64103117942093124081992527862894348800200, .5267489711934156378600823045267489711934, \
.64308667860302726193566513757104985415950, .5256673511293634496919917864476386036961, \
.64513796137358470073053240412264131009600, .5245901639344262295081967213114754098361, \
.64718504499530948859131740391603671014300, .5235173824130879345603271983640081799591, \
.64922794662510974195157587018911726772800, .5224489795918367346938775510204081632653, \
.65126668331495807251485530287027359008800, .5213849287169042769857433808553971486762, \
.65330127201274557080523663898929953575150, .5203252032520325203252032520325203252033, \
.65533172956312757406749369692988693714150, .5192697768762677484787018255578093306288, \
.65735807270835999727154330685152672231200, .5182186234817813765182186234817813765182, \
.65938031808912778153342060249997302889800, .5171717171717171717171717171717171717172, \
.66139848224536490484126716182800009846700, .5161290322580645161290322580645161290323, \
.66341258161706617713093692145776003599150, .5150905432595573440643863179074446680080, \
.66542263254509037562201001492212526500250, .5140562248995983935742971887550200803213, \
.66742865127195616370414654738851822912700, .5130260521042084168336673346693386773547, \
.66943065394262923906154583164607174694550, .5120000000000000000000000000000000000000, \
.67142865660530226534774556057527661323550, .5109780439121756487025948103792415169661, \
.67342267521216669923234121597488410770900, .5099601593625498007968127490039840637450, \
.67541272562017662384192817626171745359900, .5089463220675944333996023856858846918489, \
.67739882359180603188519853574689477682100, .5079365079365079365079365079365079365079, \
.67938098479579733801614338517538271844400, .5069306930693069306930693069306930693069, \
.68135922480790300781450241629499942064300, .5059288537549407114624505928853754940711, \
.68333355911162063645036823800182901322850, .5049309664694280078895463510848126232742, \
.68530400309891936760919861626462079584600, .5039370078740157480314960629921259842520, \
.68727057207096020619019327568821609020250, .5029469548133595284872298624754420432220, \
.68923328123880889251040571252815425395950, .5019607843137254901960784313725490196078, \
.69314718055994530941723212145818, 5.0e-01, \
}
static constexpr float log_tab_32f[log_tab_size] = LOG_TAB_VALUE;
static constexpr double log_tab_64f[log_tab_size] = LOG_TAB_VALUE;
#undef LOG_TAB_VALUE
} // namespace detail
int log32f(const float* src, float* dst, int _len)
{
size_t vl = __riscv_vsetvlmax_e32m4();
auto log_a2 = __riscv_vfmv_v_f_f32m4(detail::log32f_a2, vl);
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = __riscv_vsetvl_e32m4(len);
auto i0 = __riscv_vle32_v_i32m4((const int32_t*)src, vl);
auto buf_i = __riscv_vor(__riscv_vand(i0, detail::log32f_mask, vl), 127 << 23, vl);
auto idx = __riscv_vreinterpret_u32m4(__riscv_vand(
__riscv_vsra(i0, 23 - detail::log_scale - 1 - 2, vl),
detail::log_mask << 2,
vl));
auto tab_v = __riscv_vluxei32(detail::log_tab_32f, idx, vl);
auto y0_i = __riscv_vsub(__riscv_vand(__riscv_vsra(i0, 23, vl), 0xff, vl), 127, vl);
auto y0 = __riscv_vfmadd(__riscv_vfcvt_f_x_v_f32m4(y0_i, vl), detail::ln_2, tab_v, vl);
tab_v = __riscv_vluxei32(detail::log_tab_32f, __riscv_vadd(idx, 4, vl), vl);
auto buf_f = __riscv_vreinterpret_f32m4(buf_i);
auto x0 = __riscv_vfmul(__riscv_vfsub(buf_f, 1.f, vl), tab_v, vl);
x0 = __riscv_vfsub_mu(__riscv_vmseq(idx, (uint32_t)510 * 4, vl), x0, x0, 1.f / 512, vl);
auto res = __riscv_vfadd(__riscv_vfmul(x0, detail::log32f_a0, vl), detail::log32f_a1, vl);
res = __riscv_vfmadd(res, x0, log_a2, vl);
res = __riscv_vfmadd(res, x0, y0, vl);
__riscv_vse32(dst, res, vl);
}
return CV_HAL_ERROR_OK;
}
int log64f(const double* src, double* dst, int _len)
{
size_t vl = __riscv_vsetvlmax_e64m4();
// all vector registers are used up, so not load more constants
auto log_a5 = __riscv_vfmv_v_f_f64m4(detail::log64f_a5, vl);
auto log_a6 = __riscv_vfmv_v_f_f64m4(detail::log64f_a6, vl);
auto log_a7 = __riscv_vfmv_v_f_f64m4(detail::log64f_a7, vl);
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = __riscv_vsetvl_e64m4(len);
auto i0 = __riscv_vle64_v_i64m4((const int64_t*)src, vl);
auto buf_i = __riscv_vor(__riscv_vand(i0, detail::log64f_mask, vl), (size_t)1023 << 52, vl);
auto idx = __riscv_vreinterpret_u64m4(__riscv_vand(
__riscv_vsra(i0, 52 - detail::log_scale - 1 - 3, vl),
detail::log_mask << 3,
vl));
auto tab_v = __riscv_vluxei64(detail::log_tab_64f, idx, vl);
auto y0_i = __riscv_vsub(__riscv_vand(__riscv_vsra(i0, 52, vl), 0x7ff, vl), 1023, vl);
auto y0 = __riscv_vfmadd(__riscv_vfcvt_f_x_v_f64m4(y0_i, vl), detail::ln_2, tab_v, vl);
tab_v = __riscv_vluxei64(detail::log_tab_64f, __riscv_vadd(idx, 8, vl), vl);
auto buf_f = __riscv_vreinterpret_f64m4(buf_i);
auto x0 = __riscv_vfmul(__riscv_vfsub(buf_f, 1.0, vl), tab_v, vl);
x0 = __riscv_vfsub_mu(__riscv_vmseq(idx, (uint64_t)510 * 8, vl), x0, x0, 1. / 512, vl);
auto res = __riscv_vfadd(__riscv_vfmul(x0, detail::log64f_a0, vl), detail::log64f_a1, vl);
res = __riscv_vfadd(__riscv_vfmul(x0, res, vl), detail::log64f_a2, vl);
res = __riscv_vfadd(__riscv_vfmul(x0, res, vl), detail::log64f_a3, vl);
res = __riscv_vfadd(__riscv_vfmul(x0, res, vl), detail::log64f_a4, vl);
res = __riscv_vfmadd(res, x0, log_a5, vl);
res = __riscv_vfmadd(res, x0, log_a6, vl);
res = __riscv_vfmadd(res, x0, log_a7, vl);
res = __riscv_vfmadd(res, x0, y0, vl);
__riscv_vse64(dst, res, vl);
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+176
View File
@@ -0,0 +1,176 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include <cfloat>
#include <cmath>
#include <typeinfo>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from core/src/matrix_decomp.cpp,
// in the function template static int cv::LUImpl
template<typename RVV_T, typename T = typename RVV_T::ElemType>
inline int LU(T* src1, size_t src1_step, int m, T* src2, size_t src2_step, int n, int* info)
{
T eps;
if( typeid(T) == typeid(float) )
eps = FLT_EPSILON*10;
else if( typeid(T) == typeid(double) )
eps = DBL_EPSILON*100;
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
int i, j, k, p = 1;
src1_step /= sizeof(src1[0]);
src2_step /= sizeof(src2[0]);
int vlmax = RVV_T::setvlmax(), vl;
if( src2 )
{
for( i = 0; i < m; i++ )
{
k = i;
for( j = i+1; j < m; j++ )
if( std::abs(src1[j*src1_step + i]) > std::abs(src1[k*src1_step + i]) )
k = j;
if( std::abs(src1[k*src1_step + i]) < eps )
{
*info = 0;
return CV_HAL_ERROR_OK;
}
if( k != i )
{
for( j = i; j < m; j += vl )
{
vl = RVV_T::setvl(m - j);
auto vec_src1 = RVV_T::vload(src1 + i * src1_step + j, vl);
auto vec_src2 = RVV_T::vload(src1 + k * src1_step + j, vl);
RVV_T::vstore(src1 + k * src1_step + j, vec_src1, vl);
RVV_T::vstore(src1 + i * src1_step + j, vec_src2, vl);
}
for( j = 0; j < n; j += vl )
{
vl = RVV_T::setvl(n - j);
auto vec_src1 = RVV_T::vload(src2 + i * src2_step + j, vl);
auto vec_src2 = RVV_T::vload(src2 + k * src2_step + j, vl);
RVV_T::vstore(src2 + k * src2_step + j, vec_src1, vl);
RVV_T::vstore(src2 + i * src2_step + j, vec_src2, vl);
}
p = -p;
}
T d = -1/src1[i*src1_step + i];
for( j = i+1; j < m; j++ )
{
T alpha = src1[j*src1_step + i]*d;
for( k = i+1; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src = RVV_T::vload(src1 + i * src1_step + k, vl);
auto vec_dst = RVV_T::vload(src1 + j * src1_step + k, vl);
vec_dst = __riscv_vfmacc(vec_dst, alpha, vec_src, vl);
RVV_T::vstore(src1 + j * src1_step + k, vec_dst, vl);
}
for( k = 0; k < n; k += vl )
{
vl = RVV_T::setvl(n - k);
auto vec_src = RVV_T::vload(src2 + i * src2_step + k, vl);
auto vec_dst = RVV_T::vload(src2 + j * src2_step + k, vl);
vec_dst = __riscv_vfmacc(vec_dst, alpha, vec_src, vl);
RVV_T::vstore(src2 + j * src2_step + k, vec_dst, vl);
}
}
}
for( i = m-1; i >= 0; i-- )
for( j = 0; j < n; j++ )
{
T s = src2[i*src2_step + j];
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = i+1; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(src1 + i * src1_step + k, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + k * src2_step + j, sizeof(T) * src2_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
s -= __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
src2[i*src2_step + j] = s/src1[i*src1_step + i];
}
}
else
{
for( i = 0; i < m; i++ )
{
k = i;
for( j = i+1; j < m; j++ )
if( std::abs(src1[j*src1_step + i]) > std::abs(src1[k*src1_step + i]) )
k = j;
if( std::abs(src1[k*src1_step + i]) < eps )
{
*info = 0;
return CV_HAL_ERROR_OK;
}
if( k != i )
{
for( j = i; j < m; j += vl )
{
vl = RVV_T::setvl(m - j);
auto vec_src1 = RVV_T::vload(src1 + i * src1_step + j, vl);
auto vec_src2 = RVV_T::vload(src1 + k * src1_step + j, vl);
RVV_T::vstore(src1 + k * src1_step + j, vec_src1, vl);
RVV_T::vstore(src1 + i * src1_step + j, vec_src2, vl);
}
p = -p;
}
T d = -1/src1[i*src1_step + i];
for( j = i+1; j < m; j++ )
{
T alpha = src1[j*src1_step + i]*d;
for( k = i+1; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src = RVV_T::vload(src1 + i * src1_step + k, vl);
auto vec_dst = RVV_T::vload(src1 + j * src1_step + k, vl);
vec_dst = __riscv_vfmacc(vec_dst, alpha, vec_src, vl);
RVV_T::vstore(src1 + j * src1_step + k, vec_dst, vl);
}
}
}
}
*info = p;
return CV_HAL_ERROR_OK;
}
} // anonymous
int LU32f(float* src1, size_t src1_step, int m, float* src2, size_t src2_step, int n, int* info) {
return LU<RVV_F32M4>(src1, src1_step, m, src2, src2_step, n, info);
}
int LU64f(double* src1, size_t src1_step, int m, double* src2, size_t src2_step, int n, int* info) {
return LU<RVV_F64M4>(src1, src1_step, m, src2, src2_step, n, info);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+188
View File
@@ -0,0 +1,188 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
// need vlen >= 256
struct LUTCacheU8 : RVV_U8M8
{
using TabType = RVV_U8M8;
using SrcType = RVV_SameLen<uint8_t, TabType>;
using IdxType = RVV_SameLen<uint8_t, TabType>;
using ElemType = typename TabType::ElemType;
constexpr static size_t elem_size = sizeof(ElemType);
static inline typename TabType::VecType
gather(typename IdxType::VecType src_v, typename TabType::VecType lut_v, size_t vl)
{
return __riscv_vrgather(lut_v, src_v, vl);
}
};
// need vlen >= 512
struct LUTCacheU16 : RVV_U16M8
{
using TabType = RVV_U16M8;
using SrcType = RVV_SameLen<uint8_t, TabType>;
using IdxType = RVV_SameLen<uint16_t, TabType>;
using ElemType = typename TabType::ElemType;
constexpr static size_t elem_size = sizeof(ElemType);
static inline typename TabType::VecType
gather(typename IdxType::VecType src_v, typename TabType::VecType lut_v, size_t vl)
{
return __riscv_vrgather(lut_v, src_v, vl);
}
};
// need vlen >= 1024
struct LUTCacheU32 : RVV_U32M8
{
using TabType = RVV_U32M8;
using SrcType = RVV_SameLen<uint8_t, TabType>;
using IdxType = RVV_SameLen<uint16_t, TabType>;
using ElemType = typename TabType::ElemType;
constexpr static size_t elem_size = sizeof(ElemType);
static inline typename TabType::VecType
gather(typename IdxType::VecType src_v, typename TabType::VecType lut_v, size_t vl)
{
return __riscv_vrgatherei16(lut_v, src_v, vl);
}
};
template <typename LUT_TYPE>
class LUTParallelBody : public cv::ParallelLoopBody
{
using ElemType = typename LUT_TYPE::ElemType;
public:
const uchar* src_data;
const uchar* lut_data;
uchar* dst_data;
size_t src_step;
size_t dst_step;
size_t width;
LUTParallelBody(const uchar* _src_data,
size_t _src_step,
const uchar* _lut_data,
uchar* _dst_data,
size_t _dst_step,
size_t _width) :
src_data(_src_data), lut_data(_lut_data), dst_data(_dst_data), src_step(_src_step),
dst_step(_dst_step), width(_width)
{
}
void operator()(const cv::Range& range) const CV_OVERRIDE
{
auto src = src_data + range.start * src_step;
auto dst = dst_data + range.start * dst_step;
size_t h = range.size();
size_t w = width;
if (w == src_step && w * LUT_TYPE::elem_size == dst_step)
{
w = w * h;
h = 1;
}
auto lut = LUT_TYPE::vload((ElemType*)lut_data, 256);
size_t maxlv = LUT_TYPE::setvlmax();
for (; h; h--, src += src_step, dst += dst_step)
{
size_t vl = maxlv;
size_t l = w;
auto s = src;
auto d = (ElemType*)dst;
for (; l >= vl; l -= vl, s += vl, d += vl)
{
auto src_v = LUT_TYPE::SrcType::vload(s, vl);
auto idx_v = LUT_TYPE::IdxType::cast(src_v, vl);
auto dst_v = LUT_TYPE::gather(idx_v, lut, vl);
LUT_TYPE::vstore(d, dst_v, vl);
}
for (; l > 0; l -= vl, s += vl, d += vl)
{
vl = LUT_TYPE::setvl(l);
auto src_v = LUT_TYPE::SrcType::vload(s, vl);
auto idx_v = LUT_TYPE::IdxType::cast(src_v, vl);
auto dst_v = LUT_TYPE::gather(idx_v, lut, vl);
LUT_TYPE::vstore(d, dst_v, vl);
}
}
}
private:
LUTParallelBody(const LUTParallelBody&);
LUTParallelBody& operator=(const LUTParallelBody&);
};
int lut(const uchar* src_data,
size_t src_step,
size_t src_type,
const uchar* lut_data,
size_t lut_channel_size,
size_t lut_channels,
uchar* dst_data,
size_t dst_step,
int width,
int height)
{
if (width <= 0 || height <= 0)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
size_t w = width;
size_t h = height;
size_t vlen = __riscv_vsetvlmax_e8m8();
if (lut_channels == 1)
{
w *= CV_MAT_CN(src_type);
// Actually, vlen 128 can use four u8m4 vectors to load the whole table, gather and merge
// the result, but the performance is almost the same as the scalar.
if (lut_channel_size == 1 && vlen >= 256)
{
LUTParallelBody<LUTCacheU8> body(src_data, src_step, lut_data, dst_data, dst_step, w);
Range all(0, height);
if (w * h >= (1 << 18))
cv::parallel_for_(all, body);
else
body(all);
return CV_HAL_ERROR_OK;
}
else if (lut_channel_size == 2 && vlen >= 512)
{
LUTParallelBody<LUTCacheU16> body(src_data, src_step, lut_data, dst_data, dst_step, w);
Range all(0, height);
if (w * h >= (1 << 18))
cv::parallel_for_(all, body);
else
body(all);
return CV_HAL_ERROR_OK;
}
else if (lut_channel_size == 4 && vlen >= 1024)
{
LUTParallelBody<LUTCacheU32> body(src_data, src_step, lut_data, dst_data, dst_step, w);
Range all(0, height);
if (w * h >= (1 << 18))
cv::parallel_for_(all, body);
else
body(all);
return CV_HAL_ERROR_OK;
}
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+45
View File
@@ -0,0 +1,45 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template <typename SQRT_T, typename T = typename SQRT_T::T::ElemType>
inline int magnitude(const T* x, const T* y, T* dst, int len)
{
size_t vl;
for (; len > 0; len -= (int)vl, x += vl, y += vl, dst += vl)
{
vl = SQRT_T::T::setvl(len);
auto vx = SQRT_T::T::vload(x, vl);
auto vy = SQRT_T::T::vload(y, vl);
auto vmag = common::sqrt<SQRT_T::iter_times>(__riscv_vfmadd(vx, vx, __riscv_vfmul(vy, vy, vl), vl), vl);
SQRT_T::T::vstore(dst, vmag, vl);
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int magnitude32f(const float *x, const float *y, float *dst, int len) {
return magnitude<common::Sqrt32f<RVV_F32M8>>(x, y, dst, len);
}
int magnitude64f(const double *x, const double *y, double *dst, int len) {
return magnitude<common::Sqrt64f<RVV_F64M8>>(x, y, dst, len);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+227
View File
@@ -0,0 +1,227 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
inline int meanStdDev_8UC1(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
inline int meanStdDev_8UC4(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
inline int meanStdDev_32FC1(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step);
int meanStdDev(const uchar* src_data, size_t src_step, int width, int height, int src_type,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
switch (src_type)
{
case CV_8UC1:
return meanStdDev_8UC1(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
case CV_8UC4:
return meanStdDev_8UC4(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
case CV_32FC1:
return meanStdDev_32FC1(src_data, src_step, width, height, mean_val, stddev_val, mask, mask_step);
default:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
}
inline int meanStdDev_8UC1(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
int nz = 0;
int vlmax = __riscv_vsetvlmax_e64m8();
vuint64m8_t vec_sum = __riscv_vmv_v_x_u64m8(0, vlmax);
vuint64m8_t vec_sqsum = __riscv_vmv_v_x_u64m8(0, vlmax);
if (mask) {
for (int i = 0; i < height; ++i) {
const uchar* src_row = src_data + i * src_step;
const uchar* mask_row = mask + i * mask_step;
int j = 0, vl;
for ( ; j < width; j += vl) {
vl = __riscv_vsetvl_e8m1(width - j);
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
auto vmask_u8 = __riscv_vle8_v_u8m1(mask_row+j, vl);
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
auto vmask = __riscv_vmseq_vx_u8m1_b8(vmask_u8, 1, vl);
vec_sum = __riscv_vwaddu_wv_u64m8_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
nz += __riscv_vcpop_m_b8(vmask, vl);
}
}
} else {
for (int i = 0; i < height; i++) {
const uchar* src_row = src_data + i * src_step;
int j = 0, vl;
for ( ; j < width; j += vl) {
vl = __riscv_vsetvl_e8m1(width - j);
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
vec_sum = __riscv_vwaddu_wv_u64m8_tu(vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
}
}
nz = height * width;
}
if (nz == 0) {
if (mean_val) *mean_val = 0.0;
if (stddev_val) *stddev_val = 0.0;
return CV_HAL_ERROR_OK;
}
auto zero = __riscv_vmv_s_x_u64m1(0, vlmax);
auto vec_red = __riscv_vmv_v_x_u64m1(0, vlmax);
auto vec_reddev = __riscv_vmv_v_x_u64m1(0, vlmax);
vec_red = __riscv_vredsum(vec_sum, zero, vlmax);
vec_reddev = __riscv_vredsum(vec_sqsum, zero, vlmax);
double sum = __riscv_vmv_x(vec_red);
double mean = sum / nz;
if (mean_val) {
*mean_val = mean;
}
if (stddev_val) {
double sqsum = __riscv_vmv_x(vec_reddev);
double variance = std::max((sqsum / nz) - (mean * mean), 0.0);
double stddev = std::sqrt(variance);
*stddev_val = stddev;
}
return CV_HAL_ERROR_OK;
}
inline int meanStdDev_8UC4(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
int nz = 0;
int vlmax = __riscv_vsetvlmax_e64m8();
vuint64m8_t vec_sum = __riscv_vmv_v_x_u64m8(0, vlmax);
vuint64m8_t vec_sqsum = __riscv_vmv_v_x_u64m8(0, vlmax);
if (mask) {
for (int i = 0; i < height; ++i) {
const uchar* src_row = src_data + i * src_step;
const uchar* mask_row = mask + i * mask_step;
int j = 0, jm = 0, vl, vlm;
for ( ; j < width*4; j += vl, jm += vlm) {
vl = __riscv_vsetvl_e8m1(width*4 - j);
vlm = __riscv_vsetvl_e8mf4(width - jm);
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
auto vmask_u8mf4 = __riscv_vle8_v_u8mf4(mask_row + jm, vlm);
auto vmask_u32 = __riscv_vzext_vf4(vmask_u8mf4, vlm);
// 0 -> 0000; 1 -> 1111
vmask_u32 = __riscv_vmul(vmask_u32, 0b00000001000000010000000100000001, vlm);
auto vmask_u8 = __riscv_vreinterpret_u8m1(vmask_u32);
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
auto vmask = __riscv_vmseq_vx_u8m1_b8(vmask_u8, 1, vl);
vec_sum = __riscv_vwaddu_wv_u64m8_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
nz += __riscv_vcpop_m_b8(vmask, vl);
}
}
nz /= 4;
} else {
for (int i = 0; i < height; i++) {
const uchar* src_row = src_data + i * src_step;
int j = 0, vl;
for ( ; j < width*4; j += vl) {
vl = __riscv_vsetvl_e8m1(width*4 - j);
auto vec_pixel_u8 = __riscv_vle8_v_u8m1(src_row + j, vl);
auto vec_pixel = __riscv_vzext_vf4(vec_pixel_u8, vl);
vec_sum = __riscv_vwaddu_wv_u64m8_tu(vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vwmaccu_vv_u64m8_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
}
}
nz = height * width;
}
if (nz == 0) {
if (mean_val) *mean_val = 0.0;
if (stddev_val) *stddev_val = 0.0;
return CV_HAL_ERROR_OK;
}
uint64_t s[256], sq[256], sum[4] = {0}, sqsum[4] = {0};
__riscv_vse64(s, vec_sum, vlmax);
__riscv_vse64(sq, vec_sqsum, vlmax);
for (int i = 0; i < vlmax; ++i)
{
sum[i % 4] += s[i];
sqsum[i % 4] += sq[i];
}
if (mean_val) {
mean_val[0] = (double)sum[0] / nz;
mean_val[1] = (double)sum[1] / nz;
mean_val[2] = (double)sum[2] / nz;
mean_val[3] = (double)sum[3] / nz;
}
if (stddev_val) {
stddev_val[0] = std::sqrt(std::max(((double)sqsum[0] / nz) - (mean_val[0] * mean_val[0]), 0.0));
stddev_val[1] = std::sqrt(std::max(((double)sqsum[1] / nz) - (mean_val[1] * mean_val[1]), 0.0));
stddev_val[2] = std::sqrt(std::max(((double)sqsum[2] / nz) - (mean_val[2] * mean_val[2]), 0.0));
stddev_val[3] = std::sqrt(std::max(((double)sqsum[3] / nz) - (mean_val[3] * mean_val[3]), 0.0));
}
return CV_HAL_ERROR_OK;
}
inline int meanStdDev_32FC1(const uchar* src_data, size_t src_step, int width, int height,
double* mean_val, double* stddev_val, uchar* mask, size_t mask_step) {
int nz = 0;
int vlmax = __riscv_vsetvlmax_e64m4();
vfloat64m4_t vec_sum = __riscv_vfmv_v_f_f64m4(0, vlmax);
vfloat64m4_t vec_sqsum = __riscv_vfmv_v_f_f64m4(0, vlmax);
src_step /= sizeof(float);
if (mask) {
for (int i = 0; i < height; ++i) {
const float* src_row0 = reinterpret_cast<const float*>(src_data) + i * src_step;
const uchar* mask_row = mask + i * mask_step;
int j = 0, vl;
for ( ; j < width; j += vl) {
vl = __riscv_vsetvl_e32m2(width - j);
auto vec_pixel = __riscv_vle32_v_f32m2(src_row0 + j, vl);
auto vmask_u8 = __riscv_vle8_v_u8mf2(mask_row + j, vl);
auto vmask_u32 = __riscv_vzext_vf4(vmask_u8, vl);
auto vmask = __riscv_vmseq_vx_u32m2_b16(vmask_u32, 1, vl);
vec_sum = __riscv_vfwadd_wv_f64m4_tumu(vmask, vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vfwmacc_vv_f64m4_tumu(vmask, vec_sqsum, vec_pixel, vec_pixel, vl);
nz += __riscv_vcpop_m_b16(vmask, vl);
}
}
} else {
for (int i = 0; i < height; i++) {
const float* src_row0 = reinterpret_cast<const float*>(src_data) + i * src_step;
int j = 0, vl;
for ( ; j < width; j += vl) {
vl = __riscv_vsetvl_e32m2(width - j);
auto vec_pixel = __riscv_vle32_v_f32m2(src_row0 + j, vl);
vec_sum = __riscv_vfwadd_wv_f64m4_tu(vec_sum, vec_sum, vec_pixel, vl);
vec_sqsum = __riscv_vfwmacc_vv_f64m4_tu(vec_sqsum, vec_pixel, vec_pixel, vl);
}
}
nz = height * width;
}
if (nz == 0) {
if (mean_val) *mean_val = 0.0;
if (stddev_val) *stddev_val = 0.0;
return CV_HAL_ERROR_OK;
}
auto zero = __riscv_vfmv_v_f_f64m1(0, vlmax);
auto vec_red = __riscv_vfmv_v_f_f64m1(0, vlmax);
auto vec_reddev = __riscv_vfmv_v_f_f64m1(0, vlmax);
vec_red = __riscv_vfredusum(vec_sum, zero, vlmax);
vec_reddev = __riscv_vfredusum(vec_sqsum, zero, vlmax);
double sum = __riscv_vfmv_f(vec_red);
double mean = sum / nz;
if (mean_val) {
*mean_val = mean;
}
if (stddev_val) {
double sqsum = __riscv_vfmv_f(vec_reddev);
double variance = std::max((sqsum / nz) - (mean * mean), 0.0);
double stddev = std::sqrt(variance);
*stddev_val = stddev;
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+349
View File
@@ -0,0 +1,349 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#if defined __clang__ && __clang_major__ < 18
#define OPENCV_HAL_IMPL_RVV_VCREATE_x2(suffix, width, v0, v1) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x2(seg, 0, v0); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x2(seg, 1, v1);
#define OPENCV_HAL_IMPL_RVV_VCREATE_x3(suffix, width, v0, v1, v2) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 0, v0); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 1, v1); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x3(seg, 2, v2);
#define OPENCV_HAL_IMPL_RVV_VCREATE_x4(suffix, width, v0, v1, v2, v3) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 0, v0); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 1, v1); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 2, v2); \
seg = __riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(seg, 3, v3);
#define __riscv_vcreate_v_u8m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u8, 4, v0, v1)
#define __riscv_vcreate_v_u8m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u8, 2, v0, v1, v2)
#define __riscv_vcreate_v_u8m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u8, 2, v0, v1, v2, v3)
#define __riscv_vcreate_v_u16m4x2(v0, v1) OPENCV_HAL_IMPL_RVV_VCREATE_x2(u16, 4, v0, v1)
#define __riscv_vcreate_v_u16m2x3(v0, v1, v2) OPENCV_HAL_IMPL_RVV_VCREATE_x3(u16, 2, v0, v1, v2)
#define __riscv_vcreate_v_u16m2x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(u16, 2, v0, v1, v2, v3)
#endif // clang < 18
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
int merge8u(const uchar** src, uchar* dst, int len, int cn ) {
int vl = 0;
if (cn == 1)
{
const uchar* src0 = src[0];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m8(len - i);
__riscv_vse8_v_u8m8(dst + i, __riscv_vle8_v_u8m8(src0 + i, vl), vl);
}
}
else if (cn == 2)
{
const uchar *src0 = src[0], *src1 = src[1];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m4(len - i);
vuint8m4x2_t seg = __riscv_vcreate_v_u8m4x2(
__riscv_vle8_v_u8m4(src0 + i, vl),
__riscv_vle8_v_u8m4(src1 + i, vl)
);
__riscv_vsseg2e8_v_u8m4x2(dst + i * cn, seg, vl);
}
}
else if (cn == 3)
{
const uchar *src0 = src[0], *src1 = src[1], *src2 = src[2];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x3_t seg = __riscv_vcreate_v_u8m2x3(
__riscv_vle8_v_u8m2(src0 + i, vl),
__riscv_vle8_v_u8m2(src1 + i, vl),
__riscv_vle8_v_u8m2(src2 + i, vl)
);
__riscv_vsseg3e8_v_u8m2x3(dst + i * cn, seg, vl);
}
}
else if (cn == 4)
{
const uchar *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x4_t seg = __riscv_vcreate_v_u8m2x4(
__riscv_vle8_v_u8m2(src0 + i, vl),
__riscv_vle8_v_u8m2(src1 + i, vl),
__riscv_vle8_v_u8m2(src2 + i, vl),
__riscv_vle8_v_u8m2(src3 + i, vl)
);
__riscv_vsseg4e8_v_u8m2x4(dst + i * cn, seg, vl);
}
}
else
{
int k = 0;
for (; k <= cn - 4; k += 4)
{
const uchar *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x4_t seg = __riscv_vcreate_v_u8m2x4(
__riscv_vle8_v_u8m2(src0 + i, vl),
__riscv_vle8_v_u8m2(src1 + i, vl),
__riscv_vle8_v_u8m2(src2 + i, vl),
__riscv_vle8_v_u8m2(src3 + i, vl)
);
__riscv_vssseg4e8_v_u8m2x4(dst + k + i * cn, cn, seg, vl);
}
}
for (; k < cn; ++k)
{
const uchar* srcK = src[k];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2_t seg = __riscv_vle8_v_u8m2(srcK + i, vl);
__riscv_vsse8_v_u8m2(dst + k + i * cn, cn, seg, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
int merge16u(const ushort** src, ushort* dst, int len, int cn ) {
int vl = 0;
if (cn == 1)
{
const ushort* src0 = src[0];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m8(len - i);
__riscv_vse16_v_u16m8(dst + i, __riscv_vle16_v_u16m8(src0 + i, vl), vl);
}
}
else if (cn == 2)
{
const ushort *src0 = src[0], *src1 = src[1];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m4(len - i);
vuint16m4x2_t seg = __riscv_vcreate_v_u16m4x2(
__riscv_vle16_v_u16m4(src0 + i, vl),
__riscv_vle16_v_u16m4(src1 + i, vl)
);
__riscv_vsseg2e16_v_u16m4x2(dst + i * cn, seg, vl);
}
}
else if (cn == 3)
{
const ushort *src0 = src[0], *src1 = src[1], *src2 = src[2];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m2(len - i);
vuint16m2x3_t seg = __riscv_vcreate_v_u16m2x3(
__riscv_vle16_v_u16m2(src0 + i, vl),
__riscv_vle16_v_u16m2(src1 + i, vl),
__riscv_vle16_v_u16m2(src2 + i, vl)
);
__riscv_vsseg3e16_v_u16m2x3(dst + i * cn, seg, vl);
}
}
else if (cn == 4)
{
const ushort *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m2(len - i);
vuint16m2x4_t seg = __riscv_vcreate_v_u16m2x4(
__riscv_vle16_v_u16m2(src0 + i, vl),
__riscv_vle16_v_u16m2(src1 + i, vl),
__riscv_vle16_v_u16m2(src2 + i, vl),
__riscv_vle16_v_u16m2(src3 + i, vl)
);
__riscv_vsseg4e16_v_u16m2x4(dst + i * cn, seg, vl);
}
}
else
{
int k = 0;
for (; k <= cn - 4; k += 4)
{
const ushort *src0 = src[k], *src1 = src[k + 1], *src2 = src[k + 2], *src3 = src[k + 3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m2(len - i);
vuint16m2x4_t seg = __riscv_vcreate_v_u16m2x4(
__riscv_vle16_v_u16m2(src0 + i, vl),
__riscv_vle16_v_u16m2(src1 + i, vl),
__riscv_vle16_v_u16m2(src2 + i, vl),
__riscv_vle16_v_u16m2(src3 + i, vl)
);
__riscv_vssseg4e16_v_u16m2x4(dst + k + i * cn, cn * sizeof(ushort), seg, vl);
}
}
for (; k < cn; ++k)
{
const ushort* srcK = src[k];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e16m2(len - i);
vuint16m2_t seg = __riscv_vle16_v_u16m2(srcK + i, vl);
__riscv_vsse16_v_u16m2(dst + k + i * cn, cn * sizeof(ushort), seg, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
#if defined __GNUC__ && !defined(__clang__)
__attribute__((optimize("no-tree-vectorize")))
#endif
int merge32s(const int** src, int* dst, int len, int cn ) {
int k = cn % 4 ? cn % 4 : 4;
int i, j;
if( k == 1 )
{
const int* src0 = src[0];
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( i = j = 0; i < len; i++, j += cn )
dst[j] = src0[i];
}
else if( k == 2 )
{
const int *src0 = src[0], *src1 = src[1];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i];
dst[j+1] = src1[i];
}
}
else if( k == 3 )
{
const int *src0 = src[0], *src1 = src[1], *src2 = src[2];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i];
dst[j+1] = src1[i];
dst[j+2] = src2[i];
}
}
else
{
const int *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i]; dst[j+1] = src1[i];
dst[j+2] = src2[i]; dst[j+3] = src3[i];
}
}
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; k < cn; k += 4 )
{
const int *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
for( i = 0, j = k; i < len; i++, j += cn )
{
dst[j] = src0[i]; dst[j+1] = src1[i];
dst[j+2] = src2[i]; dst[j+3] = src3[i];
}
}
return CV_HAL_ERROR_OK;
}
#if defined __GNUC__ && !defined(__clang__)
__attribute__((optimize("no-tree-vectorize")))
#endif
int merge64s(const int64** src, int64* dst, int len, int cn ) {
int k = cn % 4 ? cn % 4 : 4;
int i, j;
if( k == 1 )
{
const int64* src0 = src[0];
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( i = j = 0; i < len; i++, j += cn )
dst[j] = src0[i];
}
else if( k == 2 )
{
const int64 *src0 = src[0], *src1 = src[1];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i];
dst[j+1] = src1[i];
}
}
else if( k == 3 )
{
const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i];
dst[j+1] = src1[i];
dst[j+2] = src2[i];
}
}
else
{
const int64 *src0 = src[0], *src1 = src[1], *src2 = src[2], *src3 = src[3];
i = j = 0;
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; i < len; i++, j += cn )
{
dst[j] = src0[i]; dst[j+1] = src1[i];
dst[j+2] = src2[i]; dst[j+3] = src3[i];
}
}
#if defined(__clang__)
#pragma clang loop vectorize(disable)
#endif
for( ; k < cn; k += 4 )
{
const int64 *src0 = src[k], *src1 = src[k+1], *src2 = src[k+2], *src3 = src[k+3];
for( i = 0, j = k; i < len; i++, j += cn )
{
dst[j] = src0[i]; dst[j+1] = src1[i];
dst[j+2] = src2[i]; dst[j+3] = src3[i];
}
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+293
View File
@@ -0,0 +1,293 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
template<typename VEC_T, typename BOOL_T, typename T = typename VEC_T::ElemType>
inline int minMaxIdxReadTwice(const uchar* src_data, size_t src_step, int width, int height, double* minVal, double* maxVal,
int* minIdx, int* maxIdx, uchar* mask, size_t mask_step)
{
int vlmax = VEC_T::setvlmax();
auto vec_min = VEC_T::vmv(std::numeric_limits<T>::max(), vlmax);
auto vec_max = VEC_T::vmv(std::numeric_limits<T>::lowest(), vlmax);
T val_min, val_max;
if (mask)
{
for (int i = 0; i < height; i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
const uchar* mask_row = mask + i * mask_step;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
auto vec_mask = BOOL_T::vload(mask_row + j, vl);
auto bool_mask = __riscv_vmsne(vec_mask, 0, vl);
vec_min = VEC_T::vmin_tumu(bool_mask, vec_min, vec_min, vec_src, vl);
vec_max = VEC_T::vmax_tumu(bool_mask, vec_max, vec_max, vec_src, vl);
}
}
auto sc_minval = VEC_T::vmv(std::numeric_limits<T>::max(), vlmax);
auto sc_maxval = VEC_T::vmv(std::numeric_limits<T>::lowest(), vlmax);
sc_minval = VEC_T::vredmin(vec_min, sc_minval, vlmax);
sc_maxval = VEC_T::vredmax(vec_max, sc_maxval, vlmax);
val_min = __riscv_vmv_x(sc_minval);
val_max = __riscv_vmv_x(sc_maxval);
bool found_min = !minIdx, found_max = !maxIdx;
for (int i = 0; i < height && (!found_min || !found_max); i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
const uchar* mask_row = mask + i * mask_step;
int vl;
for (int j = 0; j < width && (!found_min || !found_max); j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
auto vec_mask = BOOL_T::vload(mask_row + j, vl);
auto bool_mask = __riscv_vmsne(vec_mask, 0, vl);
auto bool_zero = __riscv_vmxor(bool_mask, bool_mask, vl);
if (!found_min)
{
auto bool_minpos = __riscv_vmseq_mu(bool_mask, bool_zero, vec_src, val_min, vl);
int index = __riscv_vfirst(bool_minpos, vl);
if (index != -1)
{
found_min = true;
minIdx[0] = i;
minIdx[1] = j + index;
if (src_step == sizeof(T) && width > 1)
std::swap(minIdx[0], minIdx[1]);
}
}
if (!found_max)
{
auto bool_maxpos = __riscv_vmseq_mu(bool_mask, bool_zero, vec_src, val_max, vl);
int index = __riscv_vfirst(bool_maxpos, vl);
if (index != -1)
{
found_max = true;
maxIdx[0] = i;
maxIdx[1] = j + index;
if (src_step == sizeof(T) && width > 1)
std::swap(maxIdx[0], maxIdx[1]);
}
}
}
}
}
else
{
for (int i = 0; i < height; i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
int vl;
for (int j = 0; j < width; j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
vec_min = VEC_T::vmin_tu(vec_min, vec_min, vec_src, vl);
vec_max = VEC_T::vmax_tu(vec_max, vec_max, vec_src, vl);
}
}
auto sc_minval = VEC_T::vmv(std::numeric_limits<T>::max(), vlmax);
auto sc_maxval = VEC_T::vmv(std::numeric_limits<T>::lowest(), vlmax);
sc_minval = VEC_T::vredmin(vec_min, sc_minval, vlmax);
sc_maxval = VEC_T::vredmax(vec_max, sc_maxval, vlmax);
val_min = __riscv_vmv_x(sc_minval);
val_max = __riscv_vmv_x(sc_maxval);
bool found_min = !minIdx, found_max = !maxIdx;
for (int i = 0; i < height && (!found_min || !found_max); i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
int vl;
for (int j = 0; j < width && (!found_min || !found_max); j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
if (!found_min)
{
auto bool_minpos = __riscv_vmseq(vec_src, val_min, vl);
int index = __riscv_vfirst(bool_minpos, vl);
if (index != -1)
{
found_min = true;
minIdx[0] = i;
minIdx[1] = j + index;
if (src_step == sizeof(T) && width > 1)
std::swap(minIdx[0], minIdx[1]);
}
}
if (!found_max)
{
auto bool_maxpos = __riscv_vmseq(vec_src, val_max, vl);
int index = __riscv_vfirst(bool_maxpos, vl);
if (index != -1)
{
found_max = true;
maxIdx[0] = i;
maxIdx[1] = j + index;
if (src_step == sizeof(T) && width > 1)
std::swap(maxIdx[0], maxIdx[1]);
}
}
}
}
}
if (minVal)
{
*minVal = val_min;
}
if (maxVal)
{
*maxVal = val_max;
}
return CV_HAL_ERROR_OK;
}
template<typename VEC_T, typename BOOL_T, typename IDX_T, typename T = typename VEC_T::ElemType>
inline int minMaxIdxReadOnce(const uchar* src_data, size_t src_step, int width, int height, double* minVal, double* maxVal,
int* minIdx, int* maxIdx, uchar* mask, size_t mask_step)
{
int vlmax = VEC_T::setvlmax();
auto vec_min = VEC_T::vmv(std::numeric_limits<T>::max(), vlmax);
auto vec_max = VEC_T::vmv(std::numeric_limits<T>::lowest(), vlmax);
auto vec_pos = IDX_T::vid(vlmax);
auto vec_minpos = IDX_T::vundefined(), vec_maxpos = IDX_T::vundefined();
T val_min, val_max;
if (mask)
{
for (int i = 0; i < height; i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
const uchar* mask_row = mask + i * mask_step;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
auto vec_mask = BOOL_T::vload(mask_row + j, vl);
auto bool_mask = __riscv_vmsne(vec_mask, 0, vl);
auto bool_zero = __riscv_vmxor(bool_mask, bool_mask, vl);
auto bool_minpos = VEC_T::vmlt_mu(bool_mask, bool_zero, vec_src, vec_min, vl);
auto bool_maxpos = VEC_T::vmgt_mu(bool_mask, bool_zero, vec_src, vec_max, vl);
vec_minpos = __riscv_vmerge_tu(vec_minpos, vec_minpos, vec_pos, bool_minpos, vl);
vec_maxpos = __riscv_vmerge_tu(vec_maxpos, vec_maxpos, vec_pos, bool_maxpos, vl);
vec_min = __riscv_vmerge_tu(vec_min, vec_min, vec_src, bool_minpos, vl);
vec_max = __riscv_vmerge_tu(vec_max, vec_max, vec_src, bool_maxpos, vl);
vec_pos = __riscv_vadd(vec_pos, vl, vlmax);
}
}
}
else
{
for (int i = 0; i < height; i++)
{
const T* src_row = reinterpret_cast<const T*>(src_data + i * src_step);
int vl;
for (int j = 0; j < width; j += vl)
{
vl = VEC_T::setvl(width - j);
auto vec_src = VEC_T::vload(src_row + j, vl);
auto bool_minpos = VEC_T::vmlt(vec_src, vec_min, vl);
auto bool_maxpos = VEC_T::vmgt(vec_src, vec_max, vl);
vec_minpos = __riscv_vmerge_tu(vec_minpos, vec_minpos, vec_pos, bool_minpos, vl);
vec_maxpos = __riscv_vmerge_tu(vec_maxpos, vec_maxpos, vec_pos, bool_maxpos, vl);
vec_min = __riscv_vmerge_tu(vec_min, vec_min, vec_src, bool_minpos, vl);
vec_max = __riscv_vmerge_tu(vec_max, vec_max, vec_src, bool_maxpos, vl);
vec_pos = __riscv_vadd(vec_pos, vl, vlmax);
}
}
}
val_min = std::numeric_limits<T>::max();
val_max = std::numeric_limits<T>::lowest();
for (int i = 0; i < vlmax; i++)
{
if (val_min > VEC_T::vmv_x(vec_min))
{
val_min = VEC_T::vmv_x(vec_min);
if (minIdx)
{
minIdx[0] = __riscv_vmv_x(vec_minpos) / width;
minIdx[1] = __riscv_vmv_x(vec_minpos) % width;
if (src_step == sizeof(T) && width > 1)
std::swap(minIdx[0], minIdx[1]);
}
}
if (val_max < VEC_T::vmv_x(vec_max))
{
val_max = VEC_T::vmv_x(vec_max);
if (maxIdx)
{
maxIdx[0] = __riscv_vmv_x(vec_maxpos) / width;
maxIdx[1] = __riscv_vmv_x(vec_maxpos) % width;
if (src_step == sizeof(T) && width > 1)
std::swap(maxIdx[0], maxIdx[1]);
}
}
vec_min = __riscv_vslidedown(vec_min, 1, vlmax);
vec_max = __riscv_vslidedown(vec_max, 1, vlmax);
vec_minpos = __riscv_vslidedown(vec_minpos, 1, vlmax);
vec_maxpos = __riscv_vslidedown(vec_maxpos, 1, vlmax);
}
if (minVal)
{
*minVal = val_min;
}
if (maxVal)
{
*maxVal = val_max;
}
return CV_HAL_ERROR_OK;
}
int minMaxIdx(const uchar* src_data, size_t src_step, int width, int height, int depth,
double* minVal, double* maxVal, int* minIdx, int* maxIdx, uchar* mask, size_t mask_step)
{
if (!mask_step)
mask_step = src_step;
switch (depth)
{
case CV_8UC1:
return minMaxIdxReadTwice<RVV_U8M1, RVV_U8M1>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_8SC1:
return minMaxIdxReadTwice<RVV_I8M1, RVV_U8M1>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_16UC1:
return minMaxIdxReadTwice<RVV_U16M1, RVV_U8MF2>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_16SC1:
return minMaxIdxReadTwice<RVV_I16M1, RVV_U8MF2>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_32SC1:
return minMaxIdxReadOnce<RVV_I32M4, RVV_U8M1, RVV_U32M4>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_32FC1:
return minMaxIdxReadOnce<RVV_F32M4, RVV_U8M1, RVV_U32M4>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
case CV_64FC1:
return minMaxIdxReadOnce<RVV_F64M4, RVV_U8MF2, RVV_U32M2>(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+181
View File
@@ -0,0 +1,181 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
template <typename CellType>
inline void normHammingCnt_m8(vuint8m8_t v, vbool1_t mask, size_t len_bool, size_t& result)
{
auto v_bool0 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 0));
auto v_bool1 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 1));
auto v_bool2 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 2));
auto v_bool3 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 3));
auto v_bool4 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 4));
auto v_bool5 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 5));
auto v_bool6 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 6));
auto v_bool7 = __riscv_vreinterpret_b1(__riscv_vget_u8m1(v, 7));
result += CellType::popcount(v_bool0, mask, len_bool);
result += CellType::popcount(v_bool1, mask, len_bool);
result += CellType::popcount(v_bool2, mask, len_bool);
result += CellType::popcount(v_bool3, mask, len_bool);
result += CellType::popcount(v_bool4, mask, len_bool);
result += CellType::popcount(v_bool5, mask, len_bool);
result += CellType::popcount(v_bool6, mask, len_bool);
result += CellType::popcount(v_bool7, mask, len_bool);
}
template <typename CellType>
inline void normHammingCnt_m1(vuint8m1_t v, vbool1_t mask, size_t len_bool, size_t& result)
{
auto v_bool = __riscv_vreinterpret_b1(v);
result += CellType::popcount(v_bool, mask, len_bool);
}
struct NormHammingCell1
{
static inline vbool1_t generateMask([[maybe_unused]] size_t len)
{
return vbool1_t();
}
template <typename T>
static inline void preprocess([[maybe_unused]] T& v, [[maybe_unused]] size_t len)
{
}
template <typename T>
static inline size_t popcount(T v, [[maybe_unused]] vbool1_t mask, size_t len_bool)
{
return __riscv_vcpop(v, len_bool);
}
};
struct NormHammingCell2
{
static inline vbool1_t generateMask(size_t len)
{
return __riscv_vreinterpret_b1(__riscv_vmv_v_x_u8m1(0x55, len));
}
template <typename T>
static inline void preprocess(T& v, size_t len)
{
v = __riscv_vor(v, __riscv_vsrl(v, 1, len), len);
}
template <typename T>
static inline size_t popcount(T v, vbool1_t mask, size_t len_bool)
{
return __riscv_vcpop(mask, v, len_bool);
}
};
struct NormHammingCell4
{
static inline vbool1_t generateMask(size_t len)
{
return __riscv_vreinterpret_b1(__riscv_vmv_v_x_u8m1(0x11, len));
}
template <typename T>
static inline void preprocess(T& v, size_t len)
{
v = __riscv_vor(v, __riscv_vsrl(v, 2, len), len);
v = __riscv_vor(v, __riscv_vsrl(v, 1, len), len);
}
template <typename T>
static inline size_t popcount(T v, vbool1_t mask, size_t len_bool)
{
return __riscv_vcpop(mask, v, len_bool);
}
};
template <typename CellType>
inline void normHamming8uLoop(const uchar* a, size_t n, size_t& result)
{
size_t len = __riscv_vsetvlmax_e8m8();
size_t len_bool = len * 8;
vbool1_t mask = CellType::generateMask(len);
for (; n >= len; n -= len, a += len)
{
auto v = __riscv_vle8_v_u8m8(a, len);
CellType::preprocess(v, len);
normHammingCnt_m8<CellType>(v, mask, len_bool, result);
}
for (; n > 0; n -= len, a += len)
{
len = __riscv_vsetvl_e8m1(n);
auto v = __riscv_vle8_v_u8m1(a, len);
CellType::preprocess(v, len);
normHammingCnt_m1<CellType>(v, mask, len * 8, result);
}
}
template <typename CellType>
inline void normHammingDiff8uLoop(const uchar* a, const uchar* b, size_t n, size_t& result)
{
size_t len = __riscv_vsetvlmax_e8m8();
size_t len_bool = len * 8;
vbool1_t mask = CellType::generateMask(len);
for (; n >= len; n -= len, a += len, b += len)
{
auto v_a = __riscv_vle8_v_u8m8(a, len);
auto v_b = __riscv_vle8_v_u8m8(b, len);
auto v = __riscv_vxor(v_a, v_b, len);
CellType::preprocess(v, len);
normHammingCnt_m8<CellType>(v, mask, len_bool, result);
}
for (; n > 0; n -= len, a += len, b += len)
{
len = __riscv_vsetvl_e8m1(n);
auto v_a = __riscv_vle8_v_u8m1(a, len);
auto v_b = __riscv_vle8_v_u8m1(b, len);
auto v = __riscv_vxor(v_a, v_b, len);
CellType::preprocess(v, len);
normHammingCnt_m1<CellType>(v, mask, len * 8, result);
}
}
int normHamming8u(const uchar* a, int n, int cellSize, int* result)
{
size_t _result = 0;
switch (cellSize)
{
case 1: normHamming8uLoop<NormHammingCell1>(a, n, _result); break;
case 2: normHamming8uLoop<NormHammingCell2>(a, n, _result); break;
case 4: normHamming8uLoop<NormHammingCell4>(a, n, _result); break;
default: return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
*result = static_cast<int>(_result);
return CV_HAL_ERROR_OK;
}
int normHammingDiff8u(const uchar* a, const uchar* b, int n, int cellSize, int* result)
{
size_t _result = 0;
switch (cellSize)
{
case 1: normHammingDiff8uLoop<NormHammingCell1>(a, b, n, _result); break;
case 2: normHammingDiff8uLoop<NormHammingCell2>(a, b, n, _result); break;
case 4: normHammingDiff8uLoop<NormHammingCell4>(a, b, n, _result); break;
default: return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
*result = static_cast<int>(_result);
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+110
View File
@@ -0,0 +1,110 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
static constexpr size_t sincos_mask = 0x3;
static constexpr float sincos_rad_scale = 2.f / CV_PI;
static constexpr float sincos_deg_scale = 2.f / 180.f;
// Taylor expansion coefficients for sin(x*pi/2) and cos(x*pi/2)
static constexpr double sincos_sin_p7 = -0.004681754135319;
static constexpr double sincos_sin_p5 = 0.079692626246167;
static constexpr double sincos_sin_p3 = -0.645964097506246;
static constexpr double sincos_sin_p1 = 1.570796326794897;
static constexpr double sincos_cos_p8 = 0.000919260274839;
static constexpr double sincos_cos_p6 = -0.020863480763353;
static constexpr double sincos_cos_p4 = 0.253669507901048;
static constexpr double sincos_cos_p2 = -1.233700550136170;
static constexpr double sincos_cos_p0 = 1.000000000000000;
// Taylor expansion and angle sum identity
// Use 7 LMUL registers (can be reduced to 5 by splitting fmadd to fadd and fmul)
template <typename RVV_T, typename T = typename RVV_T::VecType>
static inline void
SinCos32f(T angle, T& sinval, T& cosval, float scale, T cos_p2, T cos_p0, size_t vl)
{
angle = __riscv_vfmul(angle, scale, vl);
auto round_angle = RVV_ToInt<RVV_T>::cast(angle, vl);
auto delta_angle = __riscv_vfsub(angle, RVV_T::cast(round_angle, vl), vl);
auto delta_angle2 = __riscv_vfmul(delta_angle, delta_angle, vl);
auto sin = __riscv_vfadd(__riscv_vfmul(delta_angle2, sincos_sin_p7, vl), sincos_sin_p5, vl);
sin = __riscv_vfadd(__riscv_vfmul(delta_angle2, sin, vl), sincos_sin_p3, vl);
sin = __riscv_vfadd(__riscv_vfmul(delta_angle2, sin, vl), sincos_sin_p1, vl);
sin = __riscv_vfmul(delta_angle, sin, vl);
auto cos = __riscv_vfadd(__riscv_vfmul(delta_angle2, sincos_cos_p8, vl), sincos_cos_p6, vl);
cos = __riscv_vfadd(__riscv_vfmul(delta_angle2, cos, vl), sincos_cos_p4, vl);
cos = __riscv_vfmadd(cos, delta_angle2, cos_p2, vl);
cos = __riscv_vfmadd(cos, delta_angle2, cos_p0, vl);
// idx = 0: sinval = sin, cosval = cos
// idx = 1: sinval = cos, cosval = -sin
// idx = 2: sinval = -sin, cosval = -cos
// idx = 3: sinval = -cos, cosval = sin
auto idx = __riscv_vand(round_angle, sincos_mask, vl);
auto idx1 = __riscv_vmseq(idx, 1, vl);
auto idx2 = __riscv_vmseq(idx, 2, vl);
auto idx3 = __riscv_vmseq(idx, 3, vl);
auto idx13 = __riscv_vmor(idx1, idx3, vl);
sinval = __riscv_vmerge(sin, cos, idx13, vl);
cosval = __riscv_vmerge(cos, sin, idx13, vl);
sinval = __riscv_vfneg_mu(__riscv_vmor(idx2, idx3, vl), sinval, sinval, vl);
cosval = __riscv_vfneg_mu(__riscv_vmor(idx1, idx2, vl), cosval, cosval, vl);
}
template <typename RVV_T, typename Elem = typename RVV_T::ElemType>
inline int polarToCart(const Elem* mag, const Elem* angle, Elem* x, Elem* y, int len, bool angleInDegrees)
{
using T = RVV_F32M4;
const auto sincos_scale = angleInDegrees ? sincos_deg_scale : sincos_rad_scale;
size_t vl;
auto cos_p2 = T::vmv(sincos_cos_p2, T::setvlmax());
auto cos_p0 = T::vmv(sincos_cos_p0, T::setvlmax());
for (; len > 0; len -= (int)vl, angle += vl, x += vl, y += vl)
{
vl = RVV_T::setvl(len);
auto vangle = T::cast(RVV_T::vload(angle, vl), vl);
T::VecType vsin, vcos;
SinCos32f<T>(vangle, vsin, vcos, sincos_scale, cos_p2, cos_p0, vl);
if (mag)
{
auto vmag = T::cast(RVV_T::vload(mag, vl), vl);
vsin = __riscv_vfmul(vsin, vmag, vl);
vcos = __riscv_vfmul(vcos, vmag, vl);
mag += vl;
}
RVV_T::vstore(x, RVV_T::cast(vcos, vl), vl);
RVV_T::vstore(y, RVV_T::cast(vsin, vl), vl);
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int polarToCart32f(const float* mag, const float* angle, float* x, float* y, int len, bool angleInDegrees) {
return polarToCart<RVV_F32M4>(mag, angle, x, y, len, angleInDegrees);
}
int polarToCart64f(const double* mag, const double* angle, double* x, double* y, int len, bool angleInDegrees) {
return polarToCart<RVV_F64M8>(mag, angle, x, y, len, angleInDegrees);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+180
View File
@@ -0,0 +1,180 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include <cfloat>
#include <cmath>
#include <typeinfo>
#include <vector>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from core/src/matrix_decomp.cpp,
// in the function template static int cv::QRImpl
template<typename RVV_T, typename T = typename RVV_T::ElemType>
inline int QR(T* src1, size_t src1_step, int m, int n, int k, T* src2, size_t src2_step, T* dst, int* info)
{
T eps;
if (typeid(T) == typeid(float))
eps = FLT_EPSILON*10;
else if (typeid(T) == typeid(double))
eps = DBL_EPSILON*400;
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
src1_step /= sizeof(T);
src2_step /= sizeof(T);
size_t buf_size = m ? m + n : dst != NULL;
std::vector<T> buffer(buf_size);
T* val = buffer.data();
if (dst == NULL)
dst = val + m;
int vlmax = RVV_T::setvlmax(), vl;
for (int l = 0; l < n; l++)
{
//generate val
int vlSize = m - l;
auto vec_sum = RVV_T::vmv(0, vlmax);
for (int i = 0; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload_stride(src1 + (l + i) * src1_step + l, sizeof(T) * src1_step, vl);
RVV_T::vstore(val + i, vec_src, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src, vec_src, vl);
}
T vlNorm = __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
T tmpV = val[0];
val[0] = val[0] + (val[0] >= 0 ? 1 : -1) * std::sqrt(vlNorm);
vlNorm = std::sqrt(vlNorm + val[0] * val[0] - tmpV*tmpV);
for (int i = 0; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload(val + i, vl);
vec_src = __riscv_vfdiv(vec_src, vlNorm, vl);
RVV_T::vstore(val + i, vec_src, vl);
}
//multiply A_l*val
for (int j = l; j < n; j++)
{
vec_sum = RVV_T::vmv(0, vlmax);
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
T v_lA = 2 * __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vl);
vec_src2 = __riscv_vfnmsac(vec_src2, v_lA, vec_src1, vl);
RVV_T::vstore_stride(src1 + i * src1_step + j, sizeof(T) * src1_step, vec_src2, vl);
}
}
//save val and factors
dst[l] = val[0] * val[0];
for (int i = 1; i < vlSize; i += vl)
{
vl = RVV_T::setvl(vlSize - i);
auto vec_src = RVV_T::vload(val + i, vl);
vec_src = __riscv_vfdiv(vec_src, val[0], vl);
RVV_T::vstore_stride(src1 + (l + i) * src1_step + l, sizeof(T) * src1_step, vec_src, vl);
}
}
if (src2)
{
//generate new rhs
for (int l = 0; l < n; l++)
{
//unpack val
val[0] = (T)1;
for (int j = 1; j < m - l; j += vl)
{
vl = RVV_T::setvl(m - l - j);
auto vec_src = RVV_T::vload_stride(src1 + (j + l) * src1_step + l, sizeof(T) * src1_step, vl);
RVV_T::vstore(val + j, vec_src, vl);
}
//h_l*x
for (int j = 0; j < k; j++)
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
T v_lB = 2 * dst[l] * __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
for (int i = l; i < m; i += vl)
{
vl = RVV_T::setvl(m - i);
auto vec_src1 = RVV_T::vload(val + i - l, vl);
auto vec_src2 = RVV_T::vload_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vl);
vec_src2 = __riscv_vfnmsac(vec_src2, v_lB, vec_src1, vl);
RVV_T::vstore_stride(src2 + i * src2_step + j, sizeof(T) * src2_step, vec_src2, vl);
}
}
}
//do back substitution
for (int i = n - 1; i >= 0; i--)
{
for (int j = n - 1; j > i; j--)
{
for (int p = 0; p < k; p += vl)
{
vl = RVV_T::setvl(k - p);
auto vec_src1 = RVV_T::vload(src2 + i * src2_step + p, vl);
auto vec_src2 = RVV_T::vload(src2 + j * src2_step + p, vl);
vec_src1 = __riscv_vfnmsac(vec_src1, src1[i*src1_step + j], vec_src2, vl);
RVV_T::vstore(src2 + i * src2_step + p, vec_src1, vl);
}
}
if (std::abs(src1[i*src1_step + i]) < eps)
{
*info = 0;
return CV_HAL_ERROR_OK;
}
for (int p = 0; p < k; p += vl)
{
vl = RVV_T::setvl(k - p);
auto vec_src = RVV_T::vload(src2 + i * src2_step + p, vl);
vec_src = __riscv_vfdiv(vec_src, src1[i*src1_step + i], vl);
RVV_T::vstore(src2 + i * src2_step + p, vec_src, vl);
}
}
}
*info = 1;
return CV_HAL_ERROR_OK;
}
} // anonymous
int QR32f(float* src1, size_t src1_step, int m, int n, int k, float* src2, size_t src2_step, float* dst, int* info) {
return QR<RVV_F32M4>(src1, src1_step, m, n, k, src2, src2_step, dst, info);
}
int QR64f(double* src1, size_t src1_step, int m, int n, int k, double* src2, size_t src2_step, double* dst, int* info) {
return QR<RVV_F64M4>(src1, src1_step, m, n, k, src2, src2_step, dst, info);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+91
View File
@@ -0,0 +1,91 @@
// 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.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
int split8u(const uchar* src, uchar** dst, int len, int cn)
{
int vl = 0;
if (cn == 1)
{
uchar* dst0 = dst[0];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m8(len - i);
__riscv_vse8_v_u8m8(dst0 + i, __riscv_vle8_v_u8m8(src + i, vl), vl);
}
}
else if (cn == 2)
{
uchar *dst0 = dst[0], *dst1 = dst[1];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m4(len - i);
vuint8m4x2_t seg = __riscv_vlseg2e8_v_u8m4x2(src + i * cn, vl);
__riscv_vse8_v_u8m4(dst0 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 0), vl);
__riscv_vse8_v_u8m4(dst1 + i, __riscv_vget_v_u8m4x2_u8m4(seg, 1), vl);
}
}
else if (cn == 3)
{
uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x3_t seg = __riscv_vlseg3e8_v_u8m2x3(src + i * cn, vl);
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 0), vl);
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 1), vl);
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x3_u8m2(seg, 2), vl);
}
}
else if (cn == 4)
{
uchar *dst0 = dst[0], *dst1 = dst[1], *dst2 = dst[2], *dst3 = dst[3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x4_t seg = __riscv_vlseg4e8_v_u8m2x4(src + i * cn, vl);
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl);
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl);
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl);
__riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl);
}
}
else
{
int k = 0;
for (; k <= cn - 4; k += 4)
{
uchar *dst0 = dst[k], *dst1 = dst[k + 1], *dst2 = dst[k + 2], *dst3 = dst[k + 3];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2x4_t seg = __riscv_vlsseg4e8_v_u8m2x4(src + k + i * cn, cn, vl);
__riscv_vse8_v_u8m2(dst0 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 0), vl);
__riscv_vse8_v_u8m2(dst1 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 1), vl);
__riscv_vse8_v_u8m2(dst2 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 2), vl);
__riscv_vse8_v_u8m2(dst3 + i, __riscv_vget_v_u8m2x4_u8m2(seg, 3), vl);
}
}
for (; k < cn; ++k)
{
uchar* dstK = dst[k];
for (int i = 0; i < len; i += vl)
{
vl = __riscv_vsetvl_e8m2(len - i);
vuint8m2_t seg = __riscv_vlse8_v_u8m2(src + k + i * cn, cn, vl);
__riscv_vse8_v_u8m2(dstK + i, seg, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+74
View File
@@ -0,0 +1,74 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template <typename SQRT_T, typename Elem = typename SQRT_T::T::ElemType>
inline int sqrt(const Elem* src, Elem* dst, int _len)
{
size_t vl;
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = SQRT_T::T::setvl(len);
auto x = SQRT_T::T::vload(src, vl);
SQRT_T::T::vstore(dst, common::sqrt<SQRT_T::iter_times>(x, vl), vl);
}
return CV_HAL_ERROR_OK;
}
template <typename SQRT_T, typename Elem = typename SQRT_T::T::ElemType>
inline int invSqrt(const Elem* src, Elem* dst, int _len)
{
size_t vl;
for (size_t len = _len; len > 0; len -= vl, src += vl, dst += vl)
{
vl = SQRT_T::T::setvl(len);
auto x = SQRT_T::T::vload(src, vl);
SQRT_T::T::vstore(dst, common::invSqrt<SQRT_T::iter_times>(x, vl), vl);
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int sqrt32f(const float* src, float* dst, int len) {
return sqrt<common::Sqrt32f<RVV_F32M8>>(src, dst, len);
}
int sqrt64f(const double* src, double* dst, int len) {
return sqrt<common::Sqrt64f<RVV_F64M8>>(src, dst, len);
}
int invSqrt32f(const float* src, float* dst, int len) {
#ifdef __clang__
// Strange bug in clang: invSqrt use 2 LMUL registers to store mask, which will cause memory access.
// So a smaller LMUL is used here.
return invSqrt<common::Sqrt32f<RVV_F32M4>>(src, dst, len);
#else
return invSqrt<common::Sqrt32f<RVV_F32M8>>(src, dst, len);
#endif
}
int invSqrt64f(const double* src, double* dst, int len) {
#ifdef __clang__
// Strange bug in clang: invSqrt use 2 LMUL registers to store mask, which will cause memory access.
// So a smaller LMUL is used here.
return invSqrt<common::Sqrt64f<RVV_F64M4>>(src, dst, len);
#else
return invSqrt<common::Sqrt64f<RVV_F64M8>>(src, dst, len);
#endif
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+277
View File
@@ -0,0 +1,277 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include <cfloat>
#include <cmath>
#include <typeinfo>
#include <vector>
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from core/src/lapack.cpp,
// in the function template static void cv::JacobiSVDImpl_
template<typename RVV_T, typename T = typename RVV_T::ElemType>
inline int SVD(T* src, size_t src_step, T* w, T*, size_t, T* vt, size_t vt_step, int m, int n, int flags)
{
T minval, eps;
if( typeid(T) == typeid(float) )
{
minval = FLT_MIN;
eps = FLT_EPSILON*2;
}
else if( typeid(T) == typeid(double) )
{
minval = DBL_MIN;
eps = DBL_EPSILON*10;
}
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
int n1;
if( flags == CV_HAL_SVD_NO_UV )
n1 = 0;
else if( flags == (CV_HAL_SVD_SHORT_UV | CV_HAL_SVD_MODIFY_A) )
n1 = n;
else if( flags == (CV_HAL_SVD_FULL_UV | CV_HAL_SVD_MODIFY_A) )
n1 = m;
else
return CV_HAL_ERROR_NOT_IMPLEMENTED;
std::vector<double> Wbuf(n);
double* W = Wbuf.data();
int i, j, k, iter, max_iter = std::max(m, 30);
T c, s;
double sd;
src_step /= sizeof(src[0]);
vt_step /= sizeof(vt[0]);
int vlmax = RVV_T::setvlmax(), vl;
for( i = 0; i < n; i++ )
{
for( k = 0, sd = 0; k < m; k++ )
{
T t = src[i*src_step + k];
sd += (double)t*t;
}
W[i] = sd;
if( vt )
{
for( k = 0; k < n; k++ )
vt[i*vt_step + k] = 0;
vt[i*vt_step + i] = 1;
}
}
for( iter = 0; iter < max_iter; iter++ )
{
bool changed = false;
for( i = 0; i < n-1; i++ )
for( j = i+1; j < n; j++ )
{
T *Ai = src + i*src_step, *Aj = src + j*src_step;
double a = W[i], p = 0, b = W[j];
auto vec_sum1 = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(Ai + k, vl);
auto vec_src2 = RVV_T::vload(Aj + k, vl);
vec_sum1 = __riscv_vfmacc_tu(vec_sum1, vec_src1, vec_src2, vl);
}
p = __riscv_vfmv_f(__riscv_vfredosum(vec_sum1, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
if( std::abs(p) <= eps*std::sqrt((double)a*b) )
continue;
p *= 2;
double beta = a - b, gamma = hypot((double)p, beta);
if( beta < 0 )
{
double delta = (gamma - beta)*0.5;
s = (T)std::sqrt(delta/gamma);
c = (T)(p/(gamma*s*2));
}
else
{
c = (T)std::sqrt((gamma + beta)/(gamma*2));
s = (T)(p/(gamma*c*2));
}
vec_sum1 = RVV_T::vmv(0, vlmax);
auto vec_sum2 = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(Ai + k, vl);
auto vec_src2 = RVV_T::vload(Aj + k, vl);
auto vec_t0 = __riscv_vfadd(__riscv_vfmul(vec_src1, c, vl), __riscv_vfmul(vec_src2, s, vl), vl);
auto vec_t1 = __riscv_vfsub(__riscv_vfmul(vec_src2, c, vl), __riscv_vfmul(vec_src1, s, vl), vl);
RVV_T::vstore(Ai + k, vec_t0, vl);
RVV_T::vstore(Aj + k, vec_t1, vl);
vec_sum1 = __riscv_vfmacc_tu(vec_sum1, vec_t0, vec_t0, vl);
vec_sum2 = __riscv_vfmacc_tu(vec_sum2, vec_t1, vec_t1, vl);
}
W[i] = __riscv_vfmv_f(__riscv_vfredosum(vec_sum1, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
W[j] = __riscv_vfmv_f(__riscv_vfredosum(vec_sum2, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
changed = true;
if( vt )
{
T *Vi = vt + i*vt_step, *Vj = vt + j*vt_step;
for( k = 0; k < n; k += vl )
{
vl = RVV_T::setvl(n - k);
auto vec_src1 = RVV_T::vload(Vi + k, vl);
auto vec_src2 = RVV_T::vload(Vj + k, vl);
auto vec_t0 = __riscv_vfadd(__riscv_vfmul(vec_src1, c, vl), __riscv_vfmul(vec_src2, s, vl), vl);
auto vec_t1 = __riscv_vfsub(__riscv_vfmul(vec_src2, c, vl), __riscv_vfmul(vec_src1, s, vl), vl);
RVV_T::vstore(Vi + k, vec_t0, vl);
RVV_T::vstore(Vj + k, vec_t1, vl);
}
}
}
if( !changed )
break;
}
for( i = 0; i < n; i++ )
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src = RVV_T::vload(src + i * src_step + k, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src, vec_src, vl);
}
W[i] = std::sqrt(__riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax)));
}
for( i = 0; i < n-1; i++ )
{
j = i;
for( k = i+1; k < n; k++ )
{
if( W[j] < W[k] )
j = k;
}
if( i != j )
{
std::swap(W[i], W[j]);
if( vt )
{
for( k = 0; k < m; k++ )
std::swap(src[i*src_step + k], src[j*src_step + k]);
for( k = 0; k < n; k++ )
std::swap(vt[i*vt_step + k], vt[j*vt_step + k]);
}
}
}
for( i = 0; i < n; i++ )
w[i] = (T)W[i];
if( !vt )
return CV_HAL_ERROR_OK;
uint64 rng = 0x12345678;
auto next = [&rng]{ return (unsigned)(rng = (uint64)(unsigned)rng * 4164903690U + (unsigned)(rng >> 32)); };
for( i = 0; i < n1; i++ )
{
sd = i < n ? W[i] : 0;
for( int ii = 0; ii < 100 && sd <= minval; ii++ )
{
// if we got a zero singular value, then in order to get the corresponding left singular vector
// we generate a random vector, project it to the previously computed left singular vectors,
// subtract the projection and normalize the difference.
const T val0 = (T)(1./m);
for( k = 0; k < m; k++ )
{
T val = (next() & 256) != 0 ? val0 : -val0;
src[i*src_step + k] = val;
}
for( iter = 0; iter < 2; iter++ )
{
for( j = 0; j < i; j++ )
{
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(src + i * src_step + k, vl);
auto vec_src2 = RVV_T::vload(src + j * src_step + k, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
sd = __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(src + i * src_step + k, vl);
auto vec_src2 = RVV_T::vload(src + j * src_step + k, vl);
vec_src1 = __riscv_vfnmsac(vec_src1, sd, vec_src2, vl);
RVV_T::vstore(src + i * src_step + k, vec_src1, vl);
vec_sum = __riscv_vfadd_tu(vec_sum, vec_sum, __riscv_vfabs(vec_src1, vl), vl);
}
T asum = __riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax));
asum = asum > eps*100 ? 1/asum : 0;
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src = RVV_T::vload(src + i * src_step + k, vl);
vec_src = __riscv_vfmul(vec_src, asum, vl);
RVV_T::vstore(src + i * src_step + k, vec_src, vl);
}
}
}
auto vec_sum = RVV_T::vmv(0, vlmax);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src1 = RVV_T::vload(src + i * src_step + k, vl);
auto vec_src2 = RVV_T::vload(src + j * src_step + k, vl);
vec_sum = __riscv_vfmacc_tu(vec_sum, vec_src1, vec_src2, vl);
}
sd = std::sqrt(__riscv_vfmv_f(__riscv_vfredosum(vec_sum, RVV_BaseType<RVV_T>::vmv_s(0, vlmax), vlmax)));
}
s = (T)(sd > minval ? 1/sd : 0.);
for( k = 0; k < m; k += vl )
{
vl = RVV_T::setvl(m - k);
auto vec_src = RVV_T::vload(src + i * src_step + k, vl);
vec_src = __riscv_vfmul(vec_src, s, vl);
RVV_T::vstore(src + i * src_step + k, vec_src, vl);
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int SVD32f(float* src, size_t src_step, float* w, float* u, size_t u_step, float* vt, size_t vt_step, int m, int n, int flags) {
return SVD<RVV_F32M4>(src, src_step, w, u, u_step, vt, vt_step, m, n, flags);
}
int SVD64f(double* src, size_t src_step, double* w, double* u, size_t u_step, double* vt, size_t vt_step, int m, int n, int flags) {
return SVD<RVV_F64M4>(src, src_step, w, u, u_step, vt, vt_step, m, n, flags);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+216
View File
@@ -0,0 +1,216 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
#if defined (__clang__) && __clang_major__ < 18
#define OPENCV_HAL_IMPL_RVV_VCREATE_x4(suffix, width, v0, v1, v2, v3) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x4(v, 0, v0); \
v = __riscv_vset(v, 1, v1); \
v = __riscv_vset(v, 2, v2); \
v = __riscv_vset(v, 3, v3);
#define OPENCV_HAL_IMPL_RVV_VCREATE_x8(suffix, width, v0, v1, v2, v3, v4, v5, v6, v7) \
__riscv_vset_v_##suffix##m##width##_##suffix##m##width##x8(v, 0, v0); \
v = __riscv_vset(v, 1, v1); \
v = __riscv_vset(v, 2, v2); \
v = __riscv_vset(v, 3, v3); \
v = __riscv_vset(v, 4, v4); \
v = __riscv_vset(v, 5, v5); \
v = __riscv_vset(v, 6, v6); \
v = __riscv_vset(v, 7, v7);
#define __riscv_vcreate_v_u8m1x8(v0, v1, v2, v3, v4, v5, v6, v7) OPENCV_HAL_IMPL_RVV_VCREATE_x8(u8, 1, v0, v1, v2, v3, v4, v5, v6, v7)
#define __riscv_vcreate_v_u16m1x8(v0, v1, v2, v3, v4, v5, v6, v7) OPENCV_HAL_IMPL_RVV_VCREATE_x8(u16, 1, v0, v1, v2, v3, v4, v5, v6, v7)
#define __riscv_vcreate_v_i32m1x4(v0, v1, v2, v3) OPENCV_HAL_IMPL_RVV_VCREATE_x4(i32, 1, v0, v1, v2, v3)
#define __riscv_vcreate_v_i64m1x8(v0, v1, v2, v3, v4, v5, v6, v7) OPENCV_HAL_IMPL_RVV_VCREATE_x8(i64, 1, v0, v1, v2, v3, v4, v5, v6, v7)
#endif
namespace cv { namespace rvv_hal { namespace core {
#if CV_HAL_RVV_1P0_ENABLED
static void transpose2d_8u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int src_width, int src_height) {
auto transpose_8u_8xVl = [](const uchar *src, size_t sstep, uchar *dst, size_t dstep, const int vl) {
auto v0 = __riscv_vle8_v_u8m1(src, vl);
auto v1 = __riscv_vle8_v_u8m1(src + sstep, vl);
auto v2 = __riscv_vle8_v_u8m1(src + 2 * sstep, vl);
auto v3 = __riscv_vle8_v_u8m1(src + 3 * sstep, vl);
auto v4 = __riscv_vle8_v_u8m1(src + 4 * sstep, vl);
auto v5 = __riscv_vle8_v_u8m1(src + 5 * sstep, vl);
auto v6 = __riscv_vle8_v_u8m1(src + 6 * sstep, vl);
auto v7 = __riscv_vle8_v_u8m1(src + 7 * sstep, vl);
vuint8m1x8_t v = __riscv_vcreate_v_u8m1x8(v0, v1, v2, v3, v4, v5, v6, v7);
__riscv_vssseg8e8(dst, dstep, v, vl);
};
int h = 0, w = 0;
for (; h <= src_height - 8; h += 8) {
const uchar *src = src_data + h * src_step;
uchar *dst = dst_data + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e8m1(src_width - w);
transpose_8u_8xVl(src + w, src_step, dst + w * dst_step, dst_step, vl);
}
}
for (; h < src_height; h++) {
const uchar *src = src_data + h * src_step;
uchar *dst = dst_data + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e8m8(src_width - w);
auto v = __riscv_vle8_v_u8m8(src + w, vl);
__riscv_vsse8(dst + w * dst_step, dst_step, v, vl);
}
}
}
static void transpose2d_16u(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int src_width, int src_height) {
auto transpose_16u_8xVl = [](const ushort *src, size_t sstep, ushort *dst, size_t dstep, const int vl) {
auto v0 = __riscv_vle16_v_u16m1(src, vl);
auto v1 = __riscv_vle16_v_u16m1(src + sstep, vl);
auto v2 = __riscv_vle16_v_u16m1(src + 2 * sstep, vl);
auto v3 = __riscv_vle16_v_u16m1(src + 3 * sstep, vl);
auto v4 = __riscv_vle16_v_u16m1(src + 4 * sstep, vl);
auto v5 = __riscv_vle16_v_u16m1(src + 5 * sstep, vl);
auto v6 = __riscv_vle16_v_u16m1(src + 6 * sstep, vl);
auto v7 = __riscv_vle16_v_u16m1(src + 7 * sstep, vl);
vuint16m1x8_t v = __riscv_vcreate_v_u16m1x8(v0, v1, v2, v3, v4, v5, v6, v7);
__riscv_vssseg8e16(dst, dstep, v, vl);
};
size_t src_step_base = src_step / sizeof(ushort);
size_t dst_step_base = dst_step / sizeof(ushort);
int h = 0, w = 0;
for (; h <= src_height - 8; h += 8) {
const ushort *src = (const ushort*)(src_data) + h * src_step_base;
ushort *dst = (ushort*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e16m1(src_width - w);
transpose_16u_8xVl(src + w, src_step_base, dst + w * dst_step_base, dst_step, vl);
}
}
for (; h < src_height; h++) {
const ushort *src = (const ushort*)(src_data) + h * src_step_base;
ushort *dst = (ushort*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e16m8(src_width - w);
auto v = __riscv_vle16_v_u16m8(src + w, vl);
__riscv_vsse16(dst + w * dst_step_base, dst_step, v, vl);
}
}
}
static void transpose2d_32s(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int src_width, int src_height) {
auto transpose_32s_4xVl = [](const int *src, size_t sstep, int *dst, size_t dstep, const int vl) {
auto v0 = __riscv_vle32_v_i32m1(src, vl);
auto v1 = __riscv_vle32_v_i32m1(src + sstep, vl);
auto v2 = __riscv_vle32_v_i32m1(src + 2 * sstep, vl);
auto v3 = __riscv_vle32_v_i32m1(src + 3 * sstep, vl);
vint32m1x4_t v = __riscv_vcreate_v_i32m1x4(v0, v1, v2, v3);
__riscv_vssseg4e32(dst, dstep, v, vl);
};
size_t src_step_base = src_step / sizeof(int);
size_t dst_step_base = dst_step / sizeof(int);
int h = 0, w = 0;
for (; h <= src_height - 4; h += 4) {
const int *src = (const int*)(src_data) + h * src_step_base;
int *dst = (int*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e32m1(src_width - w);
transpose_32s_4xVl(src + w, src_step_base, dst + w * dst_step_base, dst_step, vl);
}
}
for (; h < src_height; h++) {
const int *src = (const int*)(src_data) + h * src_step_base;
int *dst = (int*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e32m8(src_width - w);
auto v = __riscv_vle32_v_i32m8(src + w, vl);
__riscv_vsse32(dst + w * dst_step_base, dst_step, v, vl);
}
}
}
static void transpose2d_32sC2(const uchar *src_data, size_t src_step, uchar *dst_data, size_t dst_step, int src_width, int src_height) {
auto transpose_64s_8xVl = [](const int64_t *src, size_t sstep, int64_t *dst, size_t dstep, const int vl) {
auto v0 = __riscv_vle64_v_i64m1(src, vl);
auto v1 = __riscv_vle64_v_i64m1(src + sstep, vl);
auto v2 = __riscv_vle64_v_i64m1(src + 2 * sstep, vl);
auto v3 = __riscv_vle64_v_i64m1(src + 3 * sstep, vl);
auto v4 = __riscv_vle64_v_i64m1(src + 4 * sstep, vl);
auto v5 = __riscv_vle64_v_i64m1(src + 5 * sstep, vl);
auto v6 = __riscv_vle64_v_i64m1(src + 6 * sstep, vl);
auto v7 = __riscv_vle64_v_i64m1(src + 7 * sstep, vl);
vint64m1x8_t v = __riscv_vcreate_v_i64m1x8(v0, v1, v2, v3, v4, v5, v6, v7);
__riscv_vssseg8e64(dst, dstep, v, vl);
};
size_t src_step_base = src_step / sizeof(int64_t);
size_t dst_step_base = dst_step / sizeof(int64_t);
int h = 0, w = 0;
for (; h <= src_height - 8; h += 8) {
const int64_t *src = (const int64_t*)(src_data) + h * src_step_base;
int64_t *dst = (int64_t*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e64m1(src_width - w);
transpose_64s_8xVl(src + w, src_step_base, dst + w * dst_step_base, dst_step, vl);
}
}
for (; h < src_height; h++) {
const int64_t *src = (const int64_t*)(src_data) + h * src_step_base;
int64_t *dst = (int64_t*)(dst_data) + h;
int vl;
for (w = 0; w < src_width; w += vl) {
vl = __riscv_vsetvl_e64m8(src_width - w);
auto v = __riscv_vle64_v_i64m8(src + w, vl);
__riscv_vsse64(dst + w * dst_step_base, dst_step, v, vl);
}
}
}
using Transpose2dFunc = void (*)(const uchar*, size_t, uchar*, size_t, int, int);
int transpose2d(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int src_width, int src_height, int element_size) {
if (src_data == dst_data) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
static Transpose2dFunc tab[] = {
0, transpose2d_8u, transpose2d_16u, 0,
transpose2d_32s, 0, 0, 0,
transpose2d_32sC2, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0
};
Transpose2dFunc func = element_size <= 32 ? tab[element_size] : nullptr;
if (!func) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
func(src_data, src_step, dst_data, dst_step, src_width, src_height);
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::core
+23
View File
@@ -0,0 +1,23 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Third party copyrights are property of their respective owners.
#ifndef OPENCV_HAL_RVV_FEATURES2D_COMMON_HPP_INCLUDED
#define OPENCV_HAL_RVV_FEATURES2D_COMMON_HPP_INCLUDED
#include <riscv_vector.h>
#include "opencv2/features/hal/interface.h"
namespace cv { namespace rvv_hal { namespace features2d { namespace common {
#if CV_HAL_RVV_1P0_ENABLED
#endif // CV_HAL_RVV_1P0_ENABLED
}}}} // cv::rvv_hal::core::common
#endif // OPENCV_HAL_RVV_CORE_COMMON_HPP_INCLUDED
+305
View File
@@ -0,0 +1,305 @@
#include "rvv_hal.hpp"
#include "common.hpp"
#include <cstring>
#include <vector>
#include <algorithm>
namespace cv { namespace rvv_hal { namespace features2d {
inline int fast_16(const uchar* src_data, size_t src_step,
int width, int height,
std::vector<cvhalKeyPoint> &keypoints,
int threshold, bool nonmax_suppression)
{
constexpr int patternSize = 16;
constexpr int K = patternSize / 2, N = patternSize + K + 1;
int pixel[N] = {0};
pixel[0] = 0 + (int)src_step * 3;
pixel[1] = 1 + (int)src_step * 3;
pixel[2] = 2 + (int)src_step * 2;
pixel[3] = 3 + (int)src_step * 1;
pixel[4] = 3 + (int)src_step * 0;
pixel[5] = 3 + (int)src_step * -1;
pixel[6] = 2 + (int)src_step * -2;
pixel[7] = 1 + (int)src_step * -3;
pixel[8] = 0 + (int)src_step * -3;
pixel[9] = -1 + (int)src_step * -3;
pixel[10] = -2 + (int)src_step * -2;
pixel[11] = -3 + (int)src_step * -1;
pixel[12] = -3 + (int)src_step * 0;
pixel[13] = -3 + (int)src_step * 1;
pixel[14] = -2 + (int)src_step * 2;
pixel[15] = -1 + (int)src_step * 3;
for (int k = 16; k < N; k++)
pixel[k] = pixel[k - 16];
/* Three-row score buffer (int16) + corner position buffer */
std::vector<int16_t> _sbuf((width + 16) * 3, 0);
int16_t *sbuf[3] = { _sbuf.data(), _sbuf.data() + width, _sbuf.data() + 2 * width };
std::vector<int> _cpbuf((width + 2) * 3, 0);
int *cpbuf[3] = { _cpbuf.data() + 1, _cpbuf.data() + (width + 2) + 1,
_cpbuf.data() + 2 * (width + 2) + 1 };
for (int i = 3; i < height - 2; i++)
{
const uchar *ptr = src_data + i * src_step + 3;
int16_t *curr = sbuf[(i - 3) % 3];
int *cornerpos = cpbuf[(i - 3) % 3];
int ncorners = 0;
std::fill(curr, curr + width, (int16_t)0);
if (i < height - 3)
{
int j = 3;
size_t vl;
for (; j < width - 3; j += vl, ptr += vl)
{
vl = __riscv_vsetvl_e16m1(width - 3 - j);
/* Load center pixel and widen to int16 */
vint16m1_t vcen = __riscv_vreinterpret_v_u16m1_i16m1(
__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr, vl), vl));
vint16m1_t vlo = __riscv_vsub_vx_i16m1(vcen, threshold, vl);
vint16m1_t vhi = __riscv_vadd_vx_i16m1(vcen, threshold, vl);
/* 4-direction quick reject */
vint16m1_t vk0 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[0], vl), vl));
vint16m1_t vk4 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[4], vl), vl));
vint16m1_t vk8 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[8], vl), vl));
vint16m1_t vk12 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[12], vl), vl));
vbool16_t bright = __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk0, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk4, vhi, vl), vl);
vbool16_t dark = __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk0, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk4, vl), vl);
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk4, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk8, vhi, vl), vl), vl);
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk4, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk8, vl), vl), vl);
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk8, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk12, vhi, vl), vl), vl);
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk8, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk12, vl), vl), vl);
bright = __riscv_vmor_mm_b16(bright, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vk12, vhi, vl), __riscv_vmsgt_vv_i16m1_b16(vk0, vhi, vl), vl), vl);
dark = __riscv_vmor_mm_b16(dark, __riscv_vmand_mm_b16(__riscv_vmsgt_vv_i16m1_b16(vlo, vk12, vl), __riscv_vmsgt_vv_i16m1_b16(vlo, vk0, vl), vl), vl);
if (__riscv_vfirst_m_b16(__riscv_vmor_mm_b16(bright, dark, vl), vl) < 0)
continue;
/* Load remaining 12 neighbors */
vint16m1_t vk1 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[1], vl), vl));
vint16m1_t vk2 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[2], vl), vl));
vint16m1_t vk3 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[3], vl), vl));
vint16m1_t vk5 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[5], vl), vl));
vint16m1_t vk6 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[6], vl), vl));
vint16m1_t vk7 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[7], vl), vl));
vint16m1_t vk9 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[9], vl), vl));
vint16m1_t vk10 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[10], vl), vl));
vint16m1_t vk11 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[11], vl), vl));
vint16m1_t vk13 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[13], vl), vl));
vint16m1_t vk14 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[14], vl), vl));
vint16m1_t vk15 = __riscv_vreinterpret_v_u16m1_i16m1(__riscv_vzext_vf2(__riscv_vle8_v_u8mf2(ptr + pixel[15], vl), vl));
/* Compute differences: d[i] = center - neighbor[i] */
vint16m1_t d0 = __riscv_vsub_vv_i16m1(vcen, vk0, vl);
vint16m1_t d1 = __riscv_vsub_vv_i16m1(vcen, vk1, vl);
vint16m1_t d2 = __riscv_vsub_vv_i16m1(vcen, vk2, vl);
vint16m1_t d3 = __riscv_vsub_vv_i16m1(vcen, vk3, vl);
vint16m1_t d4 = __riscv_vsub_vv_i16m1(vcen, vk4, vl);
vint16m1_t d5 = __riscv_vsub_vv_i16m1(vcen, vk5, vl);
vint16m1_t d6 = __riscv_vsub_vv_i16m1(vcen, vk6, vl);
vint16m1_t d7 = __riscv_vsub_vv_i16m1(vcen, vk7, vl);
vint16m1_t d8 = __riscv_vsub_vv_i16m1(vcen, vk8, vl);
vint16m1_t d9 = __riscv_vsub_vv_i16m1(vcen, vk9, vl);
vint16m1_t d10 = __riscv_vsub_vv_i16m1(vcen, vk10, vl);
vint16m1_t d11 = __riscv_vsub_vv_i16m1(vcen, vk11, vl);
vint16m1_t d12 = __riscv_vsub_vv_i16m1(vcen, vk12, vl);
vint16m1_t d13 = __riscv_vsub_vv_i16m1(vcen, vk13, vl);
vint16m1_t d14 = __riscv_vsub_vv_i16m1(vcen, vk14, vl);
vint16m1_t d15 = __riscv_vsub_vv_i16m1(vcen, vk15, vl);
/* __E: multi-level share (binary tree with named nodes) */
/* Bright score (min tree) */
vint16m1_t va0 = __riscv_vmin_vv_i16m1(d7, d8, vl);
vint16m1_t va00 = __riscv_vmin_vv_i16m1(va0, d6, vl);
va00 = __riscv_vmin_vv_i16m1(va00, d5, vl);
va00 = __riscv_vmin_vv_i16m1(va00, d4, vl);
va00 = __riscv_vmin_vv_i16m1(va00, d3, vl); /* d3~d8 */
vint16m1_t va000 = __riscv_vmin_vv_i16m1(va00, d2, vl);
va000 = __riscv_vmin_vv_i16m1(va000, d1, vl); /* d1~d8 */
vint16m1_t va001 = __riscv_vmin_vv_i16m1(va00, d9, vl);
va001 = __riscv_vmin_vv_i16m1(va001, d10, vl); /* d3~d10 */
vint16m1_t va01 = __riscv_vmin_vv_i16m1(va0, d9, vl);
va01 = __riscv_vmin_vv_i16m1(va01, d10, vl);
va01 = __riscv_vmin_vv_i16m1(va01, d11, vl);
va01 = __riscv_vmin_vv_i16m1(va01, d12, vl); /* d7~d12 */
vint16m1_t va010 = __riscv_vmin_vv_i16m1(va01, d6, vl);
va010 = __riscv_vmin_vv_i16m1(va010, d5, vl); /* d5~d12 */
vint16m1_t va011 = __riscv_vmin_vv_i16m1(va01, d13, vl);
va011 = __riscv_vmin_vv_i16m1(va011, d14, vl); /* d7~d14 */
vint16m1_t min_max = __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va000, d0, vl), __riscv_vmin_vv_i16m1(va000, d9, vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va001, d2, vl), __riscv_vmin_vv_i16m1(va001, d11, vl), vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va010, d4, vl), __riscv_vmin_vv_i16m1(va010, d13, vl), vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va011, d6, vl), __riscv_vmin_vv_i16m1(va011, d15, vl), vl), vl);
vint16m1_t va1 = __riscv_vmin_vv_i16m1(d15, d0, vl);
vint16m1_t va10 = __riscv_vmin_vv_i16m1(va1, d14, vl);
va10 = __riscv_vmin_vv_i16m1(va10, d13, vl);
va10 = __riscv_vmin_vv_i16m1(va10, d12, vl);
va10 = __riscv_vmin_vv_i16m1(va10, d11, vl); /* d0,d11~d15 */
vint16m1_t va100 = __riscv_vmin_vv_i16m1(va10, d10, vl);
va100 = __riscv_vmin_vv_i16m1(va100, d9, vl); /* d0,d9~d15 */
vint16m1_t va101 = __riscv_vmin_vv_i16m1(va10, d1, vl);
va101 = __riscv_vmin_vv_i16m1(va101, d2, vl); /* d0~d2,d11~d15 */
vint16m1_t va11 = __riscv_vmin_vv_i16m1(va1, d1, vl);
va11 = __riscv_vmin_vv_i16m1(va11, d2, vl);
va11 = __riscv_vmin_vv_i16m1(va11, d3, vl);
va11 = __riscv_vmin_vv_i16m1(va11, d4, vl); /* d0~d4,d15 */
vint16m1_t va110 = __riscv_vmin_vv_i16m1(va11, d14, vl);
va110 = __riscv_vmin_vv_i16m1(va110, d13, vl); /* d0~d4,d13~d15 */
vint16m1_t va111 = __riscv_vmin_vv_i16m1(va11, d5, vl);
va111 = __riscv_vmin_vv_i16m1(va111, d6, vl); /* d0~d6,d15 */
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va100, d8, vl), __riscv_vmin_vv_i16m1(va100, d1, vl), vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va101, d10, vl), __riscv_vmin_vv_i16m1(va101, d3, vl), vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va110, d12, vl), __riscv_vmin_vv_i16m1(va110, d5, vl), vl), vl);
min_max = __riscv_vmax_vv_i16m1(min_max, __riscv_vmax_vv_i16m1(__riscv_vmin_vv_i16m1(va111, d14, vl), __riscv_vmin_vv_i16m1(va111, d7, vl), vl), vl);
/* Dark score (max tree) */
vint16m1_t vb0 = __riscv_vmax_vv_i16m1(d7, d8, vl);
vint16m1_t vb00 = __riscv_vmax_vv_i16m1(vb0, d6, vl);
vb00 = __riscv_vmax_vv_i16m1(vb00, d5, vl);
vb00 = __riscv_vmax_vv_i16m1(vb00, d4, vl);
vb00 = __riscv_vmax_vv_i16m1(vb00, d3, vl);
vint16m1_t vb000 = __riscv_vmax_vv_i16m1(vb00, d2, vl);
vb000 = __riscv_vmax_vv_i16m1(vb000, d1, vl);
vint16m1_t vb001 = __riscv_vmax_vv_i16m1(vb00, d9, vl);
vb001 = __riscv_vmax_vv_i16m1(vb001, d10, vl);
vint16m1_t vb01 = __riscv_vmax_vv_i16m1(vb0, d9, vl);
vb01 = __riscv_vmax_vv_i16m1(vb01, d10, vl);
vb01 = __riscv_vmax_vv_i16m1(vb01, d11, vl);
vb01 = __riscv_vmax_vv_i16m1(vb01, d12, vl);
vint16m1_t vb010 = __riscv_vmax_vv_i16m1(vb01, d6, vl);
vb010 = __riscv_vmax_vv_i16m1(vb010, d5, vl);
vint16m1_t vb011 = __riscv_vmax_vv_i16m1(vb01, d13, vl);
vb011 = __riscv_vmax_vv_i16m1(vb011, d14, vl);
vint16m1_t max_min = __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb000, d0, vl), __riscv_vmax_vv_i16m1(vb000, d9, vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb001, d2, vl), __riscv_vmax_vv_i16m1(vb001, d11, vl), vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb010, d4, vl), __riscv_vmax_vv_i16m1(vb010, d13, vl), vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb011, d6, vl), __riscv_vmax_vv_i16m1(vb011, d15, vl), vl), vl);
vint16m1_t vb1 = __riscv_vmax_vv_i16m1(d15, d0, vl);
vint16m1_t vb10 = __riscv_vmax_vv_i16m1(vb1, d14, vl);
vb10 = __riscv_vmax_vv_i16m1(vb10, d13, vl);
vb10 = __riscv_vmax_vv_i16m1(vb10, d12, vl);
vb10 = __riscv_vmax_vv_i16m1(vb10, d11, vl);
vint16m1_t vb100 = __riscv_vmax_vv_i16m1(vb10, d10, vl);
vb100 = __riscv_vmax_vv_i16m1(vb100, d9, vl);
vint16m1_t vb101 = __riscv_vmax_vv_i16m1(vb10, d1, vl);
vb101 = __riscv_vmax_vv_i16m1(vb101, d2, vl);
vint16m1_t vb11 = __riscv_vmax_vv_i16m1(vb1, d1, vl);
vb11 = __riscv_vmax_vv_i16m1(vb11, d2, vl);
vb11 = __riscv_vmax_vv_i16m1(vb11, d3, vl);
vb11 = __riscv_vmax_vv_i16m1(vb11, d4, vl);
vint16m1_t vb110 = __riscv_vmax_vv_i16m1(vb11, d14, vl);
vb110 = __riscv_vmax_vv_i16m1(vb110, d13, vl);
vint16m1_t vb111 = __riscv_vmax_vv_i16m1(vb11, d5, vl);
vb111 = __riscv_vmax_vv_i16m1(vb111, d6, vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb100, d8, vl), __riscv_vmax_vv_i16m1(vb100, d1, vl), vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb101, d10, vl), __riscv_vmax_vv_i16m1(vb101, d3, vl), vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb110, d12, vl), __riscv_vmax_vv_i16m1(vb110, d5, vl), vl), vl);
max_min = __riscv_vmin_vv_i16m1(max_min, __riscv_vmin_vv_i16m1(__riscv_vmax_vv_i16m1(vb111, d14, vl), __riscv_vmax_vv_i16m1(vb111, d7, vl), vl), vl);
/* Final score: max(bright, -dark) - 1 */
vint16m1_t score_v = __riscv_vsub_vx_i16m1(
__riscv_vmax_vv_i16m1(min_max, __riscv_vneg_v_i16m1(max_min, vl), vl), 1, vl);
if (nonmax_suppression)
__riscv_vse16_v_i16m1(curr + j, score_v, vl);
vbool16_t mask = __riscv_vmsge_vx_i16m1_b16(score_v, threshold, vl);
vuint16m1_t vresult = __riscv_vcompress_vm_u16m1(__riscv_vid_v_u16m1(vl), mask, vl);
size_t count = __riscv_vcpop_m_b16(mask, vl);
__riscv_vse32_v_i32m2(&cornerpos[ncorners],
__riscv_vreinterpret_v_u32m2_i32m2(__riscv_vwaddu_vx_u32m2(vresult, (uint16_t)j, vl)), count);
ncorners += count;
}
}
cornerpos[-1] = ncorners;
if (i == 3) continue;
const int16_t *prev = sbuf[(i - 4 + 3) % 3];
const int16_t *pprev = sbuf[(i - 5 + 3) % 3];
cornerpos = cpbuf[(i - 4 + 3) % 3];
ncorners = cornerpos[-1];
for (int k = 0; k < ncorners; k++)
{
int j = cornerpos[k];
int score = prev[j];
if (!nonmax_suppression ||
(score > prev[j+1] && score > prev[j-1] &&
score > pprev[j-1] && score > pprev[j] && score > pprev[j+1] &&
score > curr[j-1] && score > curr[j] && score > curr[j+1]))
{
cvhalKeyPoint kp;
kp.x = (float)j;
kp.y = (float)(i - 1);
kp.size = 7.f;
kp.angle = -1.f;
kp.response = (float)score;
kp.octave = 0;
kp.class_id = -1;
keypoints.push_back(kp);
}
}
}
return CV_HAL_ERROR_OK;
}
int FAST(const uchar* src_data, size_t src_step,
int width, int height, void** keypoints_data,
size_t* keypoints_count, int threshold,
bool nonmax_suppression, int detector_type, void* (*realloc_func)(void*, size_t))
{
int res = CV_HAL_ERROR_UNKNOWN;
switch(detector_type) {
case CV_HAL_TYPE_5_8:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_HAL_TYPE_7_12:
return CV_HAL_ERROR_NOT_IMPLEMENTED;
case CV_HAL_TYPE_9_16: {
std::vector<cvhalKeyPoint> keypoints;
res = fast_16(src_data, src_step, width, height, keypoints, threshold, nonmax_suppression);
if (res == CV_HAL_ERROR_OK) {
if (keypoints.size() > *keypoints_count) {
*keypoints_count = keypoints.size();
uchar *tmp = (uchar*)realloc_func(*keypoints_data, sizeof(cvhalKeyPoint)*(*keypoints_count));
memcpy(tmp, (uchar*)keypoints.data(), sizeof(cvhalKeyPoint)*(*keypoints_count));
*keypoints_data = tmp;
} else {
*keypoints_count = keypoints.size();
memcpy(*keypoints_data, (uchar*)keypoints.data(), sizeof(cvhalKeyPoint)*(*keypoints_count));
}
}
return res;
}
default:
return res;
}
}
}}} // namespace cv::rvv_hal::features2d
@@ -0,0 +1,361 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from imgproc/src/bilateral_filter.simd.cpp
// in the functor BilateralFilter_8u_Invoker
static inline int bilateralFilter8UC1(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int radius, int maxk, const int* space_ofs, const float* space_weight, const float* color_weight)
{
constexpr int align = 31;
std::vector<float> _sum(width + align), _wsum(width + align);
float* sum = reinterpret_cast<float*>(((size_t)_sum.data() + align) & ~align);
float* wsum = reinterpret_cast<float*>(((size_t)_wsum.data() + align) & ~align);
for (int i = start; i < end; i++)
{
const uchar* sptr = src_data + (i+radius) * src_step + radius;
memset(sum, 0, sizeof(float) * width);
memset(wsum, 0, sizeof(float) * width);
for(int k = 0; k < maxk; k++)
{
const uchar* ksptr = sptr + space_ofs[k];
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m2(width - j);
auto src = __riscv_vle8_v_u8m2(sptr + j, vl);
auto ksrc = __riscv_vle8_v_u8m2(ksptr + j, vl);
auto diff = __riscv_vsub(__riscv_vmaxu(src, ksrc, vl), __riscv_vminu(src, ksrc, vl), vl);
auto w = __riscv_vloxei16_v_f32m8(color_weight, __riscv_vmul(__riscv_vzext_vf2(diff, vl), sizeof(float), vl), vl);
w = __riscv_vfmul(w, space_weight[k], vl);
__riscv_vse32(wsum + j, __riscv_vfadd(w, __riscv_vle32_v_f32m8(wsum + j, vl), vl), vl);
__riscv_vse32(sum + j, __riscv_vfmadd(w, __riscv_vfwcvt_f(__riscv_vzext_vf2(ksrc, vl), vl), __riscv_vle32_v_f32m8(sum + j, vl), vl), vl);
}
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m2(width - j);
auto dst = __riscv_vfncvt_xu(__riscv_vfdiv(__riscv_vle32_v_f32m8(sum + j, vl), __riscv_vle32_v_f32m8(wsum + j, vl), vl), vl);
__riscv_vse8(dst_data + i * dst_step + j, __riscv_vncvt_x(dst, vl), vl);
}
}
return CV_HAL_ERROR_OK;
}
static inline int bilateralFilter8UC3(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int radius, int maxk, const int* space_ofs, const float* space_weight, const float* color_weight)
{
constexpr int align = 31;
std::vector<float> _sum_b(width + align), _sum_g(width + align), _sum_r(width + align), _wsum(width + align);
float* sum_b = reinterpret_cast<float*>(((size_t)_sum_b.data() + align) & ~align);
float* sum_g = reinterpret_cast<float*>(((size_t)_sum_g.data() + align) & ~align);
float* sum_r = reinterpret_cast<float*>(((size_t)_sum_r.data() + align) & ~align);
float* wsum = reinterpret_cast<float*>(((size_t)_wsum.data() + align) & ~align);
for (int i = start; i < end; i++)
{
const uchar* sptr = src_data + (i+radius) * src_step + radius*3;
memset(sum_b, 0, sizeof(float) * width);
memset(sum_g, 0, sizeof(float) * width);
memset(sum_r, 0, sizeof(float) * width);
memset(wsum, 0, sizeof(float) * width);
for(int k = 0; k < maxk; k++)
{
const uchar* ksptr = sptr + space_ofs[k];
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m2(width - j);
auto src = __riscv_vlseg3e8_v_u8m2x3(sptr + j * 3, vl);
auto src0 = __riscv_vget_v_u8m2x3_u8m2(src, 0);
auto src1 = __riscv_vget_v_u8m2x3_u8m2(src, 1);
auto src2 = __riscv_vget_v_u8m2x3_u8m2(src, 2);
src = __riscv_vlseg3e8_v_u8m2x3(ksptr + j * 3, vl);
auto ksrc0 = __riscv_vget_v_u8m2x3_u8m2(src, 0);
auto ksrc1 = __riscv_vget_v_u8m2x3_u8m2(src, 1);
auto ksrc2 = __riscv_vget_v_u8m2x3_u8m2(src, 2);
auto diff0 = __riscv_vsub(__riscv_vmaxu(src0, ksrc0, vl), __riscv_vminu(src0, ksrc0, vl), vl);
auto diff1 = __riscv_vsub(__riscv_vmaxu(src1, ksrc1, vl), __riscv_vminu(src1, ksrc1, vl), vl);
auto diff2 = __riscv_vsub(__riscv_vmaxu(src2, ksrc2, vl), __riscv_vminu(src2, ksrc2, vl), vl);
auto w = __riscv_vloxei16_v_f32m8(color_weight, __riscv_vmul(__riscv_vadd(__riscv_vadd(__riscv_vzext_vf2(diff0, vl), __riscv_vzext_vf2(diff1, vl), vl), __riscv_vzext_vf2(diff2, vl), vl), sizeof(float), vl), vl);
w = __riscv_vfmul(w, space_weight[k], vl);
__riscv_vse32(wsum + j, __riscv_vfadd(w, __riscv_vle32_v_f32m8(wsum + j, vl), vl), vl);
__riscv_vse32(sum_b + j, __riscv_vfmadd(w, __riscv_vfwcvt_f(__riscv_vzext_vf2(ksrc0, vl), vl), __riscv_vle32_v_f32m8(sum_b + j, vl), vl), vl);
__riscv_vse32(sum_g + j, __riscv_vfmadd(w, __riscv_vfwcvt_f(__riscv_vzext_vf2(ksrc1, vl), vl), __riscv_vle32_v_f32m8(sum_g + j, vl), vl), vl);
__riscv_vse32(sum_r + j, __riscv_vfmadd(w, __riscv_vfwcvt_f(__riscv_vzext_vf2(ksrc2, vl), vl), __riscv_vle32_v_f32m8(sum_r + j, vl), vl), vl);
}
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m2(width - j);
auto w = __riscv_vfrdiv(__riscv_vle32_v_f32m8(wsum + j, vl), 1.0f, vl);
vuint8m2x3_t dst{};
dst = __riscv_vset_v_u8m2_u8m2x3(dst, 0,__riscv_vncvt_x(__riscv_vfncvt_xu(__riscv_vfmul(__riscv_vle32_v_f32m8(sum_b + j, vl), w, vl), vl), vl));
dst = __riscv_vset_v_u8m2_u8m2x3(dst, 1,__riscv_vncvt_x(__riscv_vfncvt_xu(__riscv_vfmul(__riscv_vle32_v_f32m8(sum_g + j, vl), w, vl), vl), vl));
dst = __riscv_vset_v_u8m2_u8m2x3(dst, 2,__riscv_vncvt_x(__riscv_vfncvt_xu(__riscv_vfmul(__riscv_vle32_v_f32m8(sum_r + j, vl), w, vl), vl), vl));
__riscv_vsseg3e8(dst_data + i * dst_step + j * 3, dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
// the algorithm is copied from imgproc/src/bilateral_filter.simd.cpp
// in the functor BilateralFilter_32f_Invoker
static inline int bilateralFilter32FC1(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int radius, int maxk, const int* space_ofs, const float* space_weight, const float* expLUT, float scale_index)
{
constexpr int align = 31;
std::vector<float> _sum(width + align), _wsum(width + align);
float* sum = reinterpret_cast<float*>(((size_t)_sum.data() + align) & ~align);
float* wsum = reinterpret_cast<float*>(((size_t)_wsum.data() + align) & ~align);
for (int i = start; i < end; i++)
{
const float* sptr = reinterpret_cast<const float*>(src_data + (i+radius) * src_step) + radius;
memset(sum, 0, sizeof(float) * width);
memset(wsum, 0, sizeof(float) * width);
for(int k = 0; k < maxk; k++)
{
const float* ksptr = sptr + space_ofs[k];
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m4(width - j);
auto src = __riscv_vle32_v_f32m4(sptr + j, vl);
auto ksrc = __riscv_vle32_v_f32m4(ksptr + j, vl);
auto diff = __riscv_vfmul(__riscv_vfabs(__riscv_vfsub(src, ksrc, vl), vl), scale_index, vl);
auto idx = __riscv_vfcvt_rtz_x(diff, vl);
auto alpha = __riscv_vfsub(diff, __riscv_vfcvt_f(idx, vl), vl);
auto exp = __riscv_vloxseg2ei32_v_f32m4x2(expLUT, __riscv_vreinterpret_v_i32m4_u32m4(__riscv_vmul(idx, sizeof(float), vl)), vl);
auto w = __riscv_vfmadd(alpha, __riscv_vfsub(__riscv_vget_v_f32m4x2_f32m4(exp, 1), __riscv_vget_v_f32m4x2_f32m4(exp, 0), vl), __riscv_vget_v_f32m4x2_f32m4(exp, 0), vl);
w = __riscv_vfmul(w, space_weight[k], vl);
__riscv_vse32(wsum + j, __riscv_vfadd(w, __riscv_vle32_v_f32m4(wsum + j, vl), vl), vl);
__riscv_vse32(sum + j, __riscv_vfmadd(w, ksrc, __riscv_vle32_v_f32m4(sum + j, vl), vl), vl);
}
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m4(width - j);
auto src = __riscv_vle32_v_f32m4(sptr + j, vl);
auto dst = __riscv_vfdiv(__riscv_vfadd(__riscv_vle32_v_f32m4(sum + j, vl), src, vl), __riscv_vfadd(__riscv_vle32_v_f32m4(wsum + j, vl), 1, vl), vl);
__riscv_vse32(reinterpret_cast<float*>(dst_data + i * dst_step) + j, dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
static inline int bilateralFilter32FC3(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int radius, int maxk, const int* space_ofs, const float* space_weight, const float* expLUT, float scale_index)
{
constexpr int align = 31;
std::vector<float> _sum_b(width + align), _sum_g(width + align), _sum_r(width + align), _wsum(width + align);
float* sum_b = reinterpret_cast<float*>(((size_t)_sum_b.data() + align) & ~align);
float* sum_g = reinterpret_cast<float*>(((size_t)_sum_g.data() + align) & ~align);
float* sum_r = reinterpret_cast<float*>(((size_t)_sum_r.data() + align) & ~align);
float* wsum = reinterpret_cast<float*>(((size_t)_wsum.data() + align) & ~align);
for (int i = start; i < end; i++)
{
const float* sptr = reinterpret_cast<const float*>(src_data + (i+radius) * src_step) + radius*3;
memset(sum_b, 0, sizeof(float) * width);
memset(sum_g, 0, sizeof(float) * width);
memset(sum_r, 0, sizeof(float) * width);
memset(wsum, 0, sizeof(float) * width);
for(int k = 0; k < maxk; k++)
{
const float* ksptr = sptr + space_ofs[k];
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m2(width - j);
auto src = __riscv_vlseg3e32_v_f32m2x3(sptr + j * 3, vl);
auto src0 = __riscv_vget_v_f32m2x3_f32m2(src, 0);
auto src1 = __riscv_vget_v_f32m2x3_f32m2(src, 1);
auto src2 = __riscv_vget_v_f32m2x3_f32m2(src, 2);
src = __riscv_vlseg3e32_v_f32m2x3(ksptr + j * 3, vl);
auto ksrc0 = __riscv_vget_v_f32m2x3_f32m2(src, 0);
auto ksrc1 = __riscv_vget_v_f32m2x3_f32m2(src, 1);
auto ksrc2 = __riscv_vget_v_f32m2x3_f32m2(src, 2);
auto diff = __riscv_vfmul(__riscv_vfadd(__riscv_vfadd(__riscv_vfabs(__riscv_vfsub(src0, ksrc0, vl), vl), __riscv_vfabs(__riscv_vfsub(src1, ksrc1, vl), vl), vl), __riscv_vfabs(__riscv_vfsub(src2, ksrc2, vl), vl), vl), scale_index, vl);
auto idx = __riscv_vfcvt_rtz_x(diff, vl);
auto alpha = __riscv_vfsub(diff, __riscv_vfcvt_f(idx, vl), vl);
auto exp = __riscv_vloxseg2ei32_v_f32m2x2(expLUT, __riscv_vreinterpret_v_i32m2_u32m2(__riscv_vmul(idx, sizeof(float), vl)), vl);
auto w = __riscv_vfmadd(alpha, __riscv_vfsub(__riscv_vget_v_f32m2x2_f32m2(exp, 1), __riscv_vget_v_f32m2x2_f32m2(exp, 0), vl), __riscv_vget_v_f32m2x2_f32m2(exp, 0), vl);
w = __riscv_vfmul(w, space_weight[k], vl);
__riscv_vse32(wsum + j, __riscv_vfadd(w, __riscv_vle32_v_f32m2(wsum + j, vl), vl), vl);
__riscv_vse32(sum_b + j, __riscv_vfmadd(w, ksrc0, __riscv_vle32_v_f32m2(sum_b + j, vl), vl), vl);
__riscv_vse32(sum_g + j, __riscv_vfmadd(w, ksrc1, __riscv_vle32_v_f32m2(sum_g + j, vl), vl), vl);
__riscv_vse32(sum_r + j, __riscv_vfmadd(w, ksrc2, __riscv_vle32_v_f32m2(sum_r + j, vl), vl), vl);
}
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m2(width - j);
auto w = __riscv_vfrdiv(__riscv_vfadd(__riscv_vle32_v_f32m2(wsum + j, vl), 1, vl), 1, vl);
auto src = __riscv_vlseg3e32_v_f32m2x3(sptr + j * 3, vl);
auto src0 = __riscv_vget_v_f32m2x3_f32m2(src, 0);
auto src1 = __riscv_vget_v_f32m2x3_f32m2(src, 1);
auto src2 = __riscv_vget_v_f32m2x3_f32m2(src, 2);
vfloat32m2x3_t dst{};
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 0, __riscv_vfmul(w, __riscv_vfadd(__riscv_vle32_v_f32m2(sum_b + j, vl), src0, vl), vl));
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 1, __riscv_vfmul(w, __riscv_vfadd(__riscv_vle32_v_f32m2(sum_g + j, vl), src1, vl), vl));
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 2, __riscv_vfmul(w, __riscv_vfadd(__riscv_vle32_v_f32m2(sum_r + j, vl), src2, vl), vl));
__riscv_vsseg3e32(reinterpret_cast<float*>(dst_data + i * dst_step) + j * 3, dst, vl);
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
// the algorithm is copied from imgproc/src/bilateral_filter.dispatch.cpp
// in the function static void bilateralFilter_8u and bilateralFilter_32f
int bilateralFilter(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step,
int width, int height, int depth, int cn, int d, double sigma_color, double sigma_space, int border_type)
{
const int type = CV_MAKETYPE(depth, cn);
if (type != CV_8UC1 && type != CV_8UC3 && type != CV_32FC1 && type != CV_32FC3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (type == CV_32FC1 && width * height > 1 << 20)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_data == dst_data || border_type & BORDER_ISOLATED)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
sigma_color = sigma_color <= 0 ? 1 : sigma_color;
sigma_space = sigma_space <= 0 ? 1 : sigma_space;
double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
int radius = d <= 0 ? std::round(sigma_space*1.5) : d/2;
radius = std::max(radius, 1);
d = radius*2 + 1;
const int size = depth == CV_32F ? cn * sizeof(float) : cn;
const int temp_step = (width + radius * 2) * size;
std::vector<uchar> _temp((width + radius * 2) * (height + radius * 2) * size, 0);
uchar* temp = _temp.data();
std::vector<int> width_interpolate(radius * 2);
for (int j = 0; j < radius; j++)
{
width_interpolate[j] = common::borderInterpolate(j - radius, width, border_type);
width_interpolate[j + radius] = common::borderInterpolate(width + j, width, border_type);
}
for (int i = 0; i < height + radius * 2; i++)
{
int x = common::borderInterpolate(i - radius, height, border_type);
if (x != -1)
{
for (int j = 0; j < radius; j++)
{
int y = width_interpolate[j];
if (y != -1)
memcpy(temp + i * temp_step + j * size, src_data + x * src_step + y * size, size);
y = width_interpolate[j + radius];
if (y != -1)
memcpy(temp + i * temp_step + (width + j + radius) * size, src_data + x * src_step + y * size, size);
}
memcpy(temp + i * temp_step + radius * size, src_data + x * src_step, width * size);
}
}
std::vector<float> _space_weight(d*d);
std::vector<int> _space_ofs(d*d);
float* space_weight = _space_weight.data();
int* space_ofs = _space_ofs.data();
int maxk = 0;
for (int i = -radius; i <= radius; i++)
{
for (int j = -radius; j <= radius; j++)
{
double r = std::sqrt((double)i*i + (double)j*j);
if (r <= radius && (depth == CV_8U || i != 0 || j != 0))
{
space_weight[maxk] = static_cast<float>(r*r*gauss_space_coeff);
space_ofs[maxk++] = (i * (temp_step / size) + j) * cn;
}
}
}
cv::rvv_hal::core::exp32f(space_weight, space_weight, maxk);
if (depth == CV_8U)
{
std::vector<float> _color_weight(cn*256);
float* color_weight = _color_weight.data();
for (int i = 0; i < 256*cn; i++)
color_weight[i] = static_cast<float>(i*i*gauss_color_coeff);
cv::rvv_hal::core::exp32f(color_weight, color_weight, 256*cn);
switch (cn)
{
case 1:
return common::invoke(height, {bilateralFilter8UC1}, temp, temp_step, dst_data, dst_step, width, radius, maxk, space_ofs, space_weight, color_weight);
case 3:
return common::invoke(height, {bilateralFilter8UC3}, temp, temp_step, dst_data, dst_step, width, radius, maxk, space_ofs, space_weight, color_weight);
}
}
else
{
double minValSrc = -1, maxValSrc = 1;
cv::rvv_hal::core::minMaxIdx(src_data, src_step, width * cn, height, CV_32F, &minValSrc, &maxValSrc, nullptr, nullptr, nullptr);
if(std::abs(minValSrc - maxValSrc) < FLT_EPSILON)
{
for (int i = 0; i < width; i++)
memcpy(dst_data + i * dst_step, src_data + i * src_step, width * size);
return CV_HAL_ERROR_OK;
}
const int kExpNumBinsPerChannel = 1 << 12;
const int kExpNumBins = kExpNumBinsPerChannel * cn;
const float scale_index = kExpNumBins / static_cast<float>((maxValSrc - minValSrc) * cn);
std::vector<float> _expLUT(kExpNumBins+2, 0);
float* expLUT = _expLUT.data();
for (int i = 0; i < kExpNumBins+2; i++)
{
double val = i / scale_index;
expLUT[i] = static_cast<float>(val * val * gauss_color_coeff);
}
cv::rvv_hal::core::exp32f(expLUT, expLUT, kExpNumBins+2);
switch (cn)
{
case 1:
return common::invoke(height, {bilateralFilter32FC1}, temp, temp_step, dst_data, dst_step, width, radius, maxk, space_ofs, space_weight, expLUT, scale_index);
case 3:
return common::invoke(height, {bilateralFilter32FC3}, temp, temp_step, dst_data, dst_step, width, radius, maxk, space_ofs, space_weight, expLUT, scale_index);
}
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+392
View File
@@ -0,0 +1,392 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template<typename T> struct rvv;
template<> struct rvv<uchar>
{
static inline vuint16m8_t vcvt0(vuint8m4_t a, size_t b) { return __riscv_vzext_vf2(a, b); }
static inline vuint8m4_t vcvt1(vuint16m8_t a, size_t b) { return __riscv_vnclipu(a, 0, __RISCV_VXRM_RNU, b); }
static inline vuint16m8_t vdiv(vuint16m8_t a, ushort b, size_t c) { return __riscv_vdivu(__riscv_vadd(a, b / 2, c), b, c); }
};
template<> struct rvv<short>
{
static inline vint32m8_t vcvt0(vint16m4_t a, size_t b) { return __riscv_vsext_vf2(a, b); }
static inline vint16m4_t vcvt1(vint32m8_t a, size_t b) { return __riscv_vnclip(a, 0, __RISCV_VXRM_RNU, b); }
static inline vint32m8_t vdiv(vint32m8_t a, int b, size_t c) { return __riscv_vdiv(__riscv_vadd(a, b / 2, c), b, c); }
};
template<> struct rvv<int>
{
static inline vint32m8_t vcvt0(vint32m8_t a, size_t) { return a; }
static inline vint32m8_t vcvt1(vint32m8_t a, size_t) { return a; }
static inline vint32m8_t vdiv(vint32m8_t a, int b, size_t c) { return __riscv_vdiv(__riscv_vadd(a, b / 2, c), b, c); }
};
template<> struct rvv<float>
{
static inline vfloat32m8_t vcvt0(vfloat32m8_t a, size_t) { return a; }
static inline vfloat32m8_t vcvt1(vfloat32m8_t a, size_t) { return a; }
static inline vfloat32m8_t vdiv(vfloat32m8_t a, float b, size_t c) { return __riscv_vfdiv(a, b, c); }
};
// the algorithm is same as cv_hal_sepFilter
template<int ksize, typename helperT, typename helperWT, bool cast>
static inline int boxFilterC1(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int full_width, int full_height, int offset_x, int offset_y, int anchor_x, int anchor_y, bool normalize, int border_type)
{
using T = typename helperT::ElemType;
using WT = typename helperWT::ElemType;
constexpr int noval = std::numeric_limits<int>::max();
auto accessX = [&](int x) {
int pi = common::borderInterpolate(offset_y + x - anchor_y, full_height, border_type);
return pi < 0 ? noval : pi - offset_y;
};
auto accessY = [&](int y) {
int pj = common::borderInterpolate(offset_x + y - anchor_x, full_width, border_type);
return pj < 0 ? noval : pj - offset_x;
};
auto p2idx = [&](int x, int y){ return (x + ksize) % ksize * width + y; };
std::vector<WT> res(width * ksize);
auto process = [&](int x, int y) {
WT sum = 0;
for (int i = 0; i < ksize; i++)
{
int p = accessY(y + i);
if (p != noval)
{
sum += reinterpret_cast<const T*>(src_data + x * src_step)[p];
}
}
res[p2idx(x, y)] = sum;
};
const int left = anchor_x, right = width - (ksize - 1 - anchor_x);
for (int i = start - anchor_y; i < end + (ksize - 1 - anchor_y); i++)
{
if (i + offset_y >= 0 && i + offset_y < full_height)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = helperT::setvl(right - j);
const T* extra = reinterpret_cast<const T*>(src_data + i * src_step) + j - anchor_x;
auto src = rvv<T>::vcvt0(helperT::vload(extra, vl), vl);
extra += vl;
auto sum = src;
src = helperWT::vslide1down(src, extra[0], vl);
sum = helperWT::vadd(sum, src, vl);
src = helperWT::vslide1down(src, extra[1], vl);
sum = helperWT::vadd(sum, src, vl);
if (ksize == 5)
{
src = helperWT::vslide1down(src, extra[2], vl);
sum = helperWT::vadd(sum, src, vl);
src = helperWT::vslide1down(src, extra[3], vl);
sum = helperWT::vadd(sum, src, vl);
}
helperWT::vstore(res.data() + p2idx(i, j), sum, vl);
}
}
}
int cur = i - (ksize - 1 - anchor_y);
if (cur >= start)
{
const WT* row0 = accessX(cur ) == noval ? nullptr : res.data() + p2idx(accessX(cur ), 0);
const WT* row1 = accessX(cur + 1) == noval ? nullptr : res.data() + p2idx(accessX(cur + 1), 0);
const WT* row2 = accessX(cur + 2) == noval ? nullptr : res.data() + p2idx(accessX(cur + 2), 0);
const WT* row3 = nullptr, *row4 = nullptr;
if (ksize == 5)
{
row3 = accessX(cur + 3) == noval ? nullptr : res.data() + p2idx(accessX(cur + 3), 0);
row4 = accessX(cur + 4) == noval ? nullptr : res.data() + p2idx(accessX(cur + 4), 0);
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = helperWT::setvl(width - j);
auto sum = row0 ? helperWT::vload(row0 + j, vl) : helperWT::vmv(0, vl);
if (row1) sum = helperWT::vadd(sum, helperWT::vload(row1 + j, vl), vl);
if (row2) sum = helperWT::vadd(sum, helperWT::vload(row2 + j, vl), vl);
if (row3) sum = helperWT::vadd(sum, helperWT::vload(row3 + j, vl), vl);
if (row4) sum = helperWT::vadd(sum, helperWT::vload(row4 + j, vl), vl);
if (normalize) sum = rvv<T>::vdiv(sum, ksize * ksize, vl);
if (cast)
{
helperT::vstore(reinterpret_cast<T*>(dst_data + cur * dst_step) + j, rvv<T>::vcvt1(sum, vl), vl);
}
else
{
helperWT::vstore(reinterpret_cast<WT*>(dst_data + cur * dst_step) + j, sum, vl);
}
}
}
}
return CV_HAL_ERROR_OK;
}
template<int ksize>
static inline int boxFilterC3(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int full_width, int full_height, int offset_x, int offset_y, int anchor_x, int anchor_y, bool normalize, int border_type)
{
constexpr int noval = std::numeric_limits<int>::max();
auto accessX = [&](int x) {
int pi = common::borderInterpolate(offset_y + x - anchor_y, full_height, border_type);
return pi < 0 ? noval : pi - offset_y;
};
auto accessY = [&](int y) {
int pj = common::borderInterpolate(offset_x + y - anchor_x, full_width, border_type);
return pj < 0 ? noval : pj - offset_x;
};
auto p2idx = [&](int x, int y){ return ((x + ksize) % ksize * width + y) * 3; };
std::vector<float> res(width * ksize * 3);
auto process = [&](int x, int y) {
float sum0, sum1, sum2;
sum0 = sum1 = sum2 = 0;
for (int i = 0; i < ksize; i++)
{
int p = accessY(y + i);
if (p != noval)
{
sum0 += reinterpret_cast<const float*>(src_data + x * src_step)[p * 3 ];
sum1 += reinterpret_cast<const float*>(src_data + x * src_step)[p * 3 + 1];
sum2 += reinterpret_cast<const float*>(src_data + x * src_step)[p * 3 + 2];
}
}
res[p2idx(x, y) ] = sum0;
res[p2idx(x, y) + 1] = sum1;
res[p2idx(x, y) + 2] = sum2;
};
const int left = anchor_x, right = width - (ksize - 1 - anchor_x);
for (int i = start - anchor_y; i < end + (ksize - 1 - anchor_y); i++)
{
if (i + offset_y >= 0 && i + offset_y < full_height)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e32m2(right - j);
const float* extra = reinterpret_cast<const float*>(src_data + i * src_step) + (j - anchor_x) * 3;
auto src = __riscv_vlseg3e32_v_f32m2x3(extra, vl);
auto src0 = __riscv_vget_v_f32m2x3_f32m2(src, 0);
auto src1 = __riscv_vget_v_f32m2x3_f32m2(src, 1);
auto src2 = __riscv_vget_v_f32m2x3_f32m2(src, 2);
extra += vl * 3;
auto sum0 = src0, sum1 = src1, sum2 = src2;
src0 = __riscv_vfslide1down(src0, extra[0], vl);
src1 = __riscv_vfslide1down(src1, extra[1], vl);
src2 = __riscv_vfslide1down(src2, extra[2], vl);
sum0 = __riscv_vfadd(sum0, src0, vl);
sum1 = __riscv_vfadd(sum1, src1, vl);
sum2 = __riscv_vfadd(sum2, src2, vl);
src0 = __riscv_vfslide1down(src0, extra[3], vl);
src1 = __riscv_vfslide1down(src1, extra[4], vl);
src2 = __riscv_vfslide1down(src2, extra[5], vl);
sum0 = __riscv_vfadd(sum0, src0, vl);
sum1 = __riscv_vfadd(sum1, src1, vl);
sum2 = __riscv_vfadd(sum2, src2, vl);
if (ksize == 5)
{
src0 = __riscv_vfslide1down(src0, extra[6], vl);
src1 = __riscv_vfslide1down(src1, extra[7], vl);
src2 = __riscv_vfslide1down(src2, extra[8], vl);
sum0 = __riscv_vfadd(sum0, src0, vl);
sum1 = __riscv_vfadd(sum1, src1, vl);
sum2 = __riscv_vfadd(sum2, src2, vl);
src0 = __riscv_vfslide1down(src0, extra[ 9], vl);
src1 = __riscv_vfslide1down(src1, extra[10], vl);
src2 = __riscv_vfslide1down(src2, extra[11], vl);
sum0 = __riscv_vfadd(sum0, src0, vl);
sum1 = __riscv_vfadd(sum1, src1, vl);
sum2 = __riscv_vfadd(sum2, src2, vl);
}
vfloat32m2x3_t dst{};
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 0, sum0);
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 1, sum1);
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 2, sum2);
__riscv_vsseg3e32(res.data() + p2idx(i, j), dst, vl);
}
}
}
int cur = i - (ksize - 1 - anchor_y);
if (cur >= start)
{
const float* row0 = accessX(cur ) == noval ? nullptr : res.data() + p2idx(accessX(cur ), 0);
const float* row1 = accessX(cur + 1) == noval ? nullptr : res.data() + p2idx(accessX(cur + 1), 0);
const float* row2 = accessX(cur + 2) == noval ? nullptr : res.data() + p2idx(accessX(cur + 2), 0);
const float* row3 = nullptr, *row4 = nullptr;
if (ksize == 5)
{
row3 = accessX(cur + 3) == noval ? nullptr : res.data() + p2idx(accessX(cur + 3), 0);
row4 = accessX(cur + 4) == noval ? nullptr : res.data() + p2idx(accessX(cur + 4), 0);
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m2(width - j);
vfloat32m2_t sum0, sum1, sum2;
sum0 = sum1 = sum2 = __riscv_vfmv_v_f_f32m2(0, vl);
auto loadres = [&](const float* row) {
if (!row) return;
auto src = __riscv_vlseg3e32_v_f32m2x3(row + j * 3, vl);
sum0 = __riscv_vfadd(sum0, __riscv_vget_v_f32m2x3_f32m2(src, 0), vl);
sum1 = __riscv_vfadd(sum1, __riscv_vget_v_f32m2x3_f32m2(src, 1), vl);
sum2 = __riscv_vfadd(sum2, __riscv_vget_v_f32m2x3_f32m2(src, 2), vl);
};
loadres(row0);
loadres(row1);
loadres(row2);
loadres(row3);
loadres(row4);
if (normalize)
{
sum0 = __riscv_vfdiv(sum0, ksize * ksize, vl);
sum1 = __riscv_vfdiv(sum1, ksize * ksize, vl);
sum2 = __riscv_vfdiv(sum2, ksize * ksize, vl);
}
vfloat32m2x3_t dst{};
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 0, sum0);
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 1, sum1);
dst = __riscv_vset_v_f32m2_f32m2x3(dst, 2, sum2);
__riscv_vsseg3e32(reinterpret_cast<float*>(dst_data + cur * dst_step) + j * 3, dst, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int boxFilter(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int src_depth, int dst_depth, int cn, int margin_left, int margin_top, int margin_right, int margin_bottom, size_t ksize_width, size_t ksize_height, int anchor_x, int anchor_y, bool normalize, int border_type)
{
const int src_type = CV_MAKETYPE(src_depth, cn), dst_type = CV_MAKETYPE(dst_depth, cn);
if (ksize_width != ksize_height || (ksize_width != 3 && ksize_width != 5))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (border_type & BORDER_ISOLATED || border_type == BORDER_WRAP)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
uchar* _dst_data = dst_data;
size_t _dst_step = dst_step;
const size_t size = CV_ELEM_SIZE(dst_type);
std::vector<uchar> dst;
if (src_data == _dst_data)
{
dst = std::vector<uchar>(width * height * size);
dst_data = dst.data();
dst_step = width * size;
}
int res = CV_HAL_ERROR_NOT_IMPLEMENTED;
anchor_x = anchor_x < 0 ? ksize_width / 2 : anchor_x;
anchor_y = anchor_y < 0 ? ksize_height / 2 : anchor_y;
if (src_type != dst_type)
{
if (src_type == CV_8UC1 && dst_type == CV_16UC1)
{
if (ksize_width == 3)
{
res = common::invoke(height, {boxFilterC1<3, RVV_U8M4, RVV_U16M8, false>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
}
if (ksize_width == 5)
{
res = common::invoke(height, {boxFilterC1<5, RVV_U8M4, RVV_U16M8, false>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
}
}
}
else
{
switch (ksize_width*100 + src_type)
{
case 300 + CV_8UC1:
res = common::invoke(height, {boxFilterC1<3, RVV_U8M4, RVV_U16M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 500 + CV_8UC1:
res = common::invoke(height, {boxFilterC1<5, RVV_U8M4, RVV_U16M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 300 + CV_16SC1:
res = common::invoke(height, {boxFilterC1<3, RVV_I16M4, RVV_I32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 500 + CV_16SC1:
res = common::invoke(height, {boxFilterC1<5, RVV_I16M4, RVV_I32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 300 + CV_32SC1:
res = common::invoke(height, {boxFilterC1<3, RVV_I32M8, RVV_I32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 500 + CV_32SC1:
res = common::invoke(height, {boxFilterC1<5, RVV_I32M8, RVV_I32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 300 + CV_32FC1:
res = common::invoke(height, {boxFilterC1<3, RVV_F32M8, RVV_F32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 500 + CV_32FC1:
res = common::invoke(height, {boxFilterC1<5, RVV_F32M8, RVV_F32M8, true>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 300 + CV_32FC3:
res = common::invoke(height, {boxFilterC3<3>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
case 500 + CV_32FC3:
res = common::invoke(height, {boxFilterC3<5>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, anchor_x, anchor_y, normalize, border_type);
break;
}
}
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_data == _dst_data)
{
for (int i = 0; i < height; i++)
memcpy(_dst_data + i * _dst_step, dst.data() + i * dst_step, dst_step);
}
return res;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+426
View File
@@ -0,0 +1,426 @@
// 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.
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv
{
namespace rvv_hal
{
namespace imgproc
{
#if CV_HAL_RVV_1P0_ENABLED
typedef struct
{
int *buffer;
int *prev;
int *curr;
int *next;
size_t size;
} LineBuffer;
LineBuffer *createLineBuffer(size_t width, size_t align);
void rotateLineBuffer(LineBuffer *buf);
void freeLineBuffer(LineBuffer *buf);
LineBuffer *createLineBuffer(size_t width, size_t align)
{
LineBuffer *buf = (LineBuffer *)malloc(sizeof(LineBuffer));
if (!buf)
return NULL;
size_t aligned_width = ((width + align - 1) & ~(align - 1));
buf->buffer = (int *)aligned_alloc(align, 3 * aligned_width * sizeof(int));
if (!buf->buffer)
{
free(buf);
return NULL;
}
buf->prev = buf->buffer;
buf->curr = buf->prev + aligned_width;
buf->next = buf->curr + aligned_width;
buf->size = aligned_width;
return buf;
}
void rotateLineBuffer(LineBuffer *buf)
{
int *temp = buf->prev;
buf->prev = buf->curr;
buf->curr = buf->next;
buf->next = temp;
}
void freeLineBuffer(LineBuffer *buf)
{
if (buf)
{
free(buf->buffer);
free(buf);
}
}
typedef struct
{
uint8_t **data;
int capacity;
int size;
} Stack;
static Stack *canny_createStack(int capacity);
static void canny_push(Stack *stack, uint8_t *item);
static uint8_t *canny_pop(Stack *stack);
static void freeStack(Stack *stack);
static Stack *canny_createStack(int capacity)
{
Stack *stack = (Stack *)malloc(sizeof(Stack));
stack->data = (uint8_t **)malloc(capacity * sizeof(uint8_t *));
stack->capacity = capacity;
stack->size = 0;
return stack;
}
static void canny_push(Stack *stack, uint8_t *item)
{
if (stack->size < stack->capacity)
{
stack->data[stack->size++] = item;
}
}
static uint8_t *canny_pop(Stack *stack)
{
if (stack->size > 0)
{
return stack->data[--stack->size];
}
return NULL;
}
static void freeStack(Stack *stack)
{
free(stack->data);
free(stack);
}
int sobel(const uint8_t *src_data, size_t src_step, uint8_t *dst_data, size_t dst_step, int width, int height, int src_depth, int dst_depth, int cn, int margin_left, int margin_top, int margin_right, int margin_bottom, int dx, int dy, int ksize, double scale, double delta, int border_type);
int canny(const uint8_t *src_data, size_t src_step,
uint8_t *dst_data, size_t dst_step,
int width, int height, int cn,
double low_thresh, double high_thresh,
int ksize, bool L2gradient)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (cn != 1 || (ksize != 3 && ksize != 5))
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
if (L2gradient)
{
low_thresh = 32767.0 < low_thresh ? 32767.0 : low_thresh;
high_thresh = 32767.0 < high_thresh ? 32767.0 : high_thresh;
if (low_thresh > 0)
low_thresh *= low_thresh;
if (high_thresh > 0)
high_thresh *= high_thresh;
}
int low = (int)low_thresh;
low_thresh = low - (low > low_thresh);
int high = (int)high_thresh;
high_thresh = high - (high > high_thresh);
int16_t *dx_data = (int16_t *)malloc(height * width * sizeof(int16_t));
int16_t *dy_data = (int16_t *)malloc(height * width * sizeof(int16_t));
if (!dx_data || !dy_data)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
const size_t grad_step = width * sizeof(int16_t);
int ret = sobel(src_data, src_step, (uint8_t *)dx_data, grad_step,
width, height, CV_8U, CV_16S, 1,
0, 0, 0, 0, 1, 0, ksize, 1.0, 0.0, BORDER_REPLICATE);
if (ret != CV_HAL_ERROR_OK)
{
free(dx_data);
free(dy_data);
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
ret = sobel(src_data, src_step, (uint8_t *)dy_data, grad_step,
width, height, CV_8U, CV_16S, 1,
0, 0, 0, 0, 0, 1, ksize, 1.0, 0.0, BORDER_REPLICATE);
if (ret != CV_HAL_ERROR_OK)
{
free(dx_data);
free(dy_data);
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
const int mapstep = width + 2;
const size_t mapsize = (height + 2) * mapstep;
uint8_t *edge_map = (uint8_t *)calloc(mapsize, sizeof(uint8_t));
if (!edge_map)
{
free(dx_data);
free(dy_data);
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
Stack *stack = canny_createStack(width * height);
Stack *borderPeaksLocal = canny_createStack(width * height);
if (!stack || !borderPeaksLocal)
{
free(dx_data);
free(dy_data);
free(edge_map);
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
memset(edge_map, 1, mapstep);
memset(edge_map + (height + 1) * mapstep, 1, mapstep);
for (int i = 1; i <= height; i++)
{
edge_map[i * mapstep] = 1;
edge_map[i * mapstep + width + 1] = 1;
}
uint8_t *map = edge_map + mapstep + 1;
const int simd_align = 16;
LineBuffer *lineBuf = createLineBuffer(width, simd_align);
if (!lineBuf)
{
free(dx_data);
free(dy_data);
free(edge_map);
freeStack(stack);
freeStack(borderPeaksLocal);
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
const int TG22 = 13573;
for (int i = 0; i <= height; i++)
{
if (i < height)
{
int16_t *dx = (int16_t *)(dx_data + i * width);
int16_t *dy = (int16_t *)(dy_data + i * width);
if (L2gradient)
{
size_t vl = 0;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m8(width - j);
vint32m8_t vdx = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dx + j, vl), vl);
vint32m8_t vdy = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dy + j, vl), vl);
vint32m8_t vres = __riscv_vmul_vv_i32m8(vdx, vdx, vl);
vres = __riscv_vmacc_vv_i32m8(vres, vdy, vdy, vl);
__riscv_vse32_v_i32m8(lineBuf->next + j, vres, vl);
}
}
else
{
size_t vl = 0;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m8(width - j);
vint32m8_t vdx = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dx + j, vl), vl);
vint32m8_t vdy = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dy + j, vl), vl);
vbool4_t mask = __riscv_vmslt_vx_i32m8_b4(vdx, 0, vl);
vdx = __riscv_vmul_vx_i32m8_m(mask, vdx, -1, vl);
mask = __riscv_vmslt_vx_i32m8_b4(vdy, 0, vl);
vdy = __riscv_vmul_vx_i32m8_m(mask, vdy, -1, vl);
vint32m8_t vres = __riscv_vadd_vv_i32m8(vdx, vdy, vl);
__riscv_vse32_v_i32m8(lineBuf->next + j, vres, vl);
}
}
}
else
{
memset(lineBuf->next, 0, width * sizeof(int));
}
uint8_t *pmap = map + i * mapstep;
int16_t *dx = (int16_t *)(dx_data + i * width);
int16_t *dy = (int16_t *)(dy_data + i * width);
size_t vl = 0;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m8(width - j);
vint32m8_t vm = __riscv_vle32_v_i32m8(lineBuf->curr + j, vl);
vint32m8_t vdx = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dx + j, vl), vl);
vint32m8_t vdy = __riscv_vwcvt_x_x_v_i32m8(__riscv_vle16_v_i16m4(dy + j, vl), vl);
vbool4_t mask_dx = __riscv_vmslt_vx_i32m8_b4(vdx, 0, vl);
vbool4_t mask_dy = __riscv_vmslt_vx_i32m8_b4(vdy, 0, vl);
vint32m8_t vdx_abs = __riscv_vmul_vx_i32m8_m(mask_dx, vdx, -1, vl);
vint32m8_t vdy_abs = __riscv_vmul_vx_i32m8_m(mask_dy, vdy, -1, vl);
vdy_abs = __riscv_vsll_vx_i32m8(vdy_abs, 15, vl);
// Calculate threshold values
vint32m8_t vtg22x = __riscv_vmul_vx_i32m8(vdx_abs, TG22, vl);
vint32m8_t vtg67x = __riscv_vadd_vv_i32m8(vtg22x, __riscv_vsll_vx_i32m8(vdx_abs, 16, vl), vl);
// Create masks for different angle ranges
vbool4_t mask1 = __riscv_vmslt_vv_i32m8_b4(vdy_abs, vtg22x, vl);
vbool4_t mask2 = __riscv_vmsgt_vv_i32m8_b4(vdy_abs, vtg67x, vl);
vbool4_t mask3 = __riscv_vmnot_m_b4(__riscv_vmor_mm_b4(mask1, mask2, vl), vl);
// Load neighbor pixels for all conditions
vint32m8_t prev_curr = __riscv_vle32_v_i32m8(lineBuf->curr + (j > 0 ? j - 1 : j), vl);
vint32m8_t next_curr = __riscv_vle32_v_i32m8(lineBuf->curr + j + 1, vl);
vint32m8_t prev_line = __riscv_vle32_v_i32m8(lineBuf->prev + j, vl);
vint32m8_t next_line = __riscv_vle32_v_i32m8(lineBuf->next + j, vl);
// Condition 1: Horizontal/Vertical edges (compare left/right)
vbool4_t cond1_max = __riscv_vmand_mm_b4(
__riscv_vmsgt_vv_i32m8_b4(vm, prev_curr, vl),
__riscv_vmsge_vv_i32m8_b4(vm, next_curr, vl),
vl);
// Condition 2: Diagonal edges (compare top/bottom)
vbool4_t cond2_max = __riscv_vmand_mm_b4(
__riscv_vmsgt_vv_i32m8_b4(vm, prev_line, vl),
__riscv_vmsge_vv_i32m8_b4(vm, next_line, vl),
vl);
// Condition 3: Other diagonals (calculate s)
vint32m8_t vxor = __riscv_vxor_vv_i32m8(vdx, vdy, vl);
vbool4_t s_mask = __riscv_vmslt_vx_i32m8_b4(vxor, 0, vl);
vint32m8_t prev_s1 = __riscv_vle32_v_i32m8(lineBuf->prev + (j > 0 ? j - 1 : j), vl);
vint32m8_t prev_s2 = __riscv_vle32_v_i32m8(lineBuf->prev + j + 1, vl);
vint32m8_t next_s1 = __riscv_vle32_v_i32m8(lineBuf->next + j + 1, vl);
vint32m8_t next_s2 = __riscv_vle32_v_i32m8(lineBuf->next + (j > 0 ? j - 1 : j), vl);
vint32m8_t prev_sel = __riscv_vmerge_vvm_i32m8(prev_s1, prev_s2, s_mask, vl);
vint32m8_t next_sel = __riscv_vmerge_vvm_i32m8(next_s1, next_s2, s_mask, vl);
vbool4_t cond3_max = __riscv_vmand_mm_b4(
__riscv_vmsgt_vv_i32m8_b4(vm, prev_sel, vl),
__riscv_vmsgt_vv_i32m8_b4(vm, next_sel, vl),
vl);
// Combine results from all conditions
vbool4_t vmax = __riscv_vmor_mm_b4(
__riscv_vmand_mm_b4(mask1, cond1_max, vl),
__riscv_vmand_mm_b4(mask2, cond2_max, vl),
vl);
vmax = __riscv_vmor_mm_b4(
vmax,
__riscv_vmand_mm_b4(mask3, cond3_max, vl),
vl);
// Threshold checks
vbool4_t vlow = __riscv_vmsgt_vx_i32m8_b4(vm, low_thresh, vl);
vbool4_t vhigh = __riscv_vmsgt_vx_i32m8_b4(vm, high_thresh, vl);
vbool4_t valid_edges = __riscv_vmand_mm_b4(vmax, vlow, vl);
vbool4_t strong_edges = __riscv_vmand_mm_b4(valid_edges, vhigh, vl);
// Generate result map
vuint8m2_t vres = __riscv_vmv_v_x_u8m2(1, vl);
vres = __riscv_vmerge_vxm_u8m2(vres, 0, valid_edges, vl);
vres = __riscv_vmerge_vxm_u8m2(vres, 2, strong_edges, vl);
__riscv_vse8_v_u8m2(pmap + j, vres, vl);
// canny_Push strong edges to stack
int32_t vidx = __riscv_vfirst_m_b4(strong_edges, vl);
while (vidx >= 0)
{
canny_push(stack, pmap + j + vidx);
strong_edges = __riscv_vmand_mm_b4(strong_edges,
__riscv_vmclr_m_b4(vl), vl);
vidx = __riscv_vfirst_m_b4(strong_edges, vl);
}
}
rotateLineBuffer(lineBuf);
}
uint8_t *pmapLower = edge_map;
uint32_t pmapDiff = (uint32_t)((edge_map + mapsize) - pmapLower);
while (stack->size > 0)
{
uint8_t *m = canny_pop(stack);
if ((uint64_t)m < (uint64_t)pmapLower || (uint64_t)m >= (uint64_t)(pmapLower + pmapDiff))
continue;
const int offsets[8] = {
-mapstep - 1, -mapstep, -mapstep + 1,
-1, +1,
+mapstep - 1, +mapstep, +mapstep + 1};
for (int k = 0; k < 8; k++)
{
uint8_t *neighbor = m + offsets[k];
if ((uint64_t)neighbor < (uint64_t)edge_map ||
(uint64_t)neighbor >= (uint64_t)(edge_map + mapsize))
continue;
if (*neighbor == 0)
{
*neighbor = 2;
canny_push(stack, neighbor);
}
}
}
if (borderPeaksLocal->size > 0)
{
for (int i = 0; i < borderPeaksLocal->size; i++)
{
canny_push(stack, borderPeaksLocal->data[i]);
}
}
for (int i = 0; i < height; i++)
{
uint8_t *pdst = dst_data + i * dst_step;
uint8_t *pmap = map + i * mapstep + 1;
size_t vl = 0;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m8(width - j);
vuint8m8_t vres = __riscv_vle8_v_u8m8(pmap + j, vl);
vres = __riscv_vsrl_vx_u8m8(vres, 1, vl);
vres = __riscv_vsub_vv_u8m8(__riscv_vmv_v_x_u8m8(0, vl), vres, vl);
__riscv_vse8_v_u8m8(pdst + j, vres, vl);
}
}
freeLineBuffer(lineBuf);
freeStack(borderPeaksLocal);
freeStack(stack);
free(dx_data);
free(dy_data);
free(edge_map);
return CV_HAL_ERROR_OK;
}
}
}
#endif // CV_HAL_RVV_1P0_ENABLED
} // namespace cv::rvv_hal::imgproc
File diff suppressed because it is too large Load Diff
+76
View File
@@ -0,0 +1,76 @@
// 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.
//
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Third party copyrights are property of their respective owners.
#ifndef OPENCV_HAL_RVV_IMGPROC_COMMON_HPP_INCLUDED
#define OPENCV_HAL_RVV_IMGPROC_COMMON_HPP_INCLUDED
#include "opencv2/core/hal/interface.h"
#include "opencv2/imgproc/hal/interface.h"
namespace cv { namespace rvv_hal { namespace imgproc { namespace common {
inline int borderInterpolate( int p, int len, int borderType )
{
if ((unsigned)p < (unsigned)len)
;
else if (borderType == CV_HAL_BORDER_REPLICATE)
p = p < 0 ? 0 : len - 1;
else if (borderType == CV_HAL_BORDER_REFLECT || borderType == CV_HAL_BORDER_REFLECT_101)
{
int delta = borderType == CV_HAL_BORDER_REFLECT_101;
if (len == 1)
return 0;
do
{
if (p < 0)
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
}
while( (unsigned)p >= (unsigned)len );
}
else if (borderType == CV_HAL_BORDER_WRAP)
{
if (p < 0)
p -= ((p-len+1)/len)*len;
if (p >= len)
p %= len;
}
else if (borderType == CV_HAL_BORDER_CONSTANT)
p = -1;
return p;
}
class FilterInvoker : public ParallelLoopBody
{
public:
template<typename... Args>
FilterInvoker(std::function<int(int, int, Args...)> _func, Args&&... args)
{
func = std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::forward<Args>(args)...);
}
virtual void operator()(const Range& range) const override
{
func(range.start, range.end);
}
private:
std::function<int(int, int)> func;
};
template<typename... Args>
inline int invoke(int height, std::function<int(int, int, Args...)> func, Args&&... args)
{
cv::parallel_for_(Range(1, height), FilterInvoker(func, std::forward<Args>(args)...), cv::getNumThreads());
return func(0, 1, std::forward<Args>(args)...);
}
}}}} // cv::rvv_hal::imgproc::common
#endif // OPENCV_HAL_RVV_IMGPROC_COMMON_HPP_INCLUDED
+264
View File
@@ -0,0 +1,264 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
struct Filter2D
{
const uchar* kernel_data;
size_t kernel_step;
int kernel_type;
int kernel_width;
int kernel_height;
int src_type;
int dst_type;
int borderType;
double delta;
int anchor_x;
int anchor_y;
};
static void process3(int anchor, int left, int right, float delta, const float* kernel, const uchar* row0, const uchar* row1, const uchar* row2, uchar* dst)
{
int vl;
for (int i = left; i < right; i += vl)
{
vl = __riscv_vsetvl_e8m1(right - i);
auto s0 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s1 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s2 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s3 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto addshift = [&](vfloat32m4_t a, vfloat32m4_t b, float k0, float k1, float k2, float r1, float r2) {
a = __riscv_vfmacc(a, k0, b, vl);
b = __riscv_vfslide1down(b, r1, vl);
a = __riscv_vfmacc(a, k1, b, vl);
b = __riscv_vfslide1down(b, r2, vl);
return __riscv_vfmacc(a, k2, b, vl);
};
auto loadsrc = [&](const uchar* row, float k0, float k1, float k2) {
if (!row) return;
const uchar* extra = row + (i - anchor) * 4;
auto src = __riscv_vlseg4e8_v_u8m1x4(extra, vl);
auto v0 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 0), vl), vl);
auto v1 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 1), vl), vl);
auto v2 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 2), vl), vl);
auto v3 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 3), vl), vl);
extra += vl * 4;
s0 = addshift(s0, v0, k0, k1, k2, extra[0], extra[4]);
s1 = addshift(s1, v1, k0, k1, k2, extra[1], extra[5]);
s2 = addshift(s2, v2, k0, k1, k2, extra[2], extra[6]);
s3 = addshift(s3, v3, k0, k1, k2, extra[3], extra[7]);
};
loadsrc(row0, kernel[0], kernel[1], kernel[2]);
loadsrc(row1, kernel[3], kernel[4], kernel[5]);
loadsrc(row2, kernel[6], kernel[7], kernel[8]);
vuint8m1x4_t val{};
val = __riscv_vset_v_u8m1_u8m1x4(val, 0, __riscv_vnclipu(__riscv_vfncvt_xu(s0, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 1, __riscv_vnclipu(__riscv_vfncvt_xu(s1, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 2, __riscv_vnclipu(__riscv_vfncvt_xu(s2, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 3, __riscv_vnclipu(__riscv_vfncvt_xu(s3, vl), 0, __RISCV_VXRM_RNU, vl));
__riscv_vsseg4e8(dst + i * 4, val, vl);
}
}
static void process5(int anchor, int left, int right, float delta, const float* kernel, const uchar* row0, const uchar* row1, const uchar* row2, const uchar* row3, const uchar* row4, uchar* dst)
{
int vl;
for (int i = left; i < right; i += vl)
{
vl = __riscv_vsetvl_e8m1(right - i);
auto s0 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s1 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s2 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto s3 = __riscv_vfmv_v_f_f32m4(delta, vl);
auto addshift = [&](vfloat32m4_t a, vfloat32m4_t b, float k0, float k1, float k2, float k3, float k4, float r1, float r2, float r3, float r4) {
a = __riscv_vfmacc(a, k0, b, vl);
b = __riscv_vfslide1down(b, r1, vl);
a = __riscv_vfmacc(a, k1, b, vl);
b = __riscv_vfslide1down(b, r2, vl);
a = __riscv_vfmacc(a, k2, b, vl);
b = __riscv_vfslide1down(b, r3, vl);
a = __riscv_vfmacc(a, k3, b, vl);
b = __riscv_vfslide1down(b, r4, vl);
return __riscv_vfmacc(a, k4, b, vl);
};
auto loadsrc = [&](const uchar* row, float k0, float k1, float k2, float k3, float k4) {
if (!row) return;
const uchar* extra = row + (i - anchor) * 4;
auto src = __riscv_vlseg4e8_v_u8m1x4(extra, vl);
auto v0 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 0), vl), vl);
auto v1 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 1), vl), vl);
auto v2 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 2), vl), vl);
auto v3 = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vget_v_u8m1x4_u8m1(src, 3), vl), vl);
extra += vl * 4;
s0 = addshift(s0, v0, k0, k1, k2, k3, k4, extra[0], extra[4], extra[ 8], extra[12]);
s1 = addshift(s1, v1, k0, k1, k2, k3, k4, extra[1], extra[5], extra[ 9], extra[13]);
s2 = addshift(s2, v2, k0, k1, k2, k3, k4, extra[2], extra[6], extra[10], extra[14]);
s3 = addshift(s3, v3, k0, k1, k2, k3, k4, extra[3], extra[7], extra[11], extra[15]);
};
loadsrc(row0, kernel[ 0], kernel[ 1], kernel[ 2], kernel[ 3], kernel[ 4]);
loadsrc(row1, kernel[ 5], kernel[ 6], kernel[ 7], kernel[ 8], kernel[ 9]);
loadsrc(row2, kernel[10], kernel[11], kernel[12], kernel[13], kernel[14]);
loadsrc(row3, kernel[15], kernel[16], kernel[17], kernel[18], kernel[19]);
loadsrc(row4, kernel[20], kernel[21], kernel[22], kernel[23], kernel[24]);
vuint8m1x4_t val{};
val = __riscv_vset_v_u8m1_u8m1x4(val, 0, __riscv_vnclipu(__riscv_vfncvt_xu(s0, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 1, __riscv_vnclipu(__riscv_vfncvt_xu(s1, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 2, __riscv_vnclipu(__riscv_vfncvt_xu(s2, vl), 0, __RISCV_VXRM_RNU, vl));
val = __riscv_vset_v_u8m1_u8m1x4(val, 3, __riscv_vnclipu(__riscv_vfncvt_xu(s3, vl), 0, __RISCV_VXRM_RNU, vl));
__riscv_vsseg4e8(dst + i * 4, val, vl);
}
}
// the algorithm is copied from 3rdparty/carotene/src/convolution.cpp,
// in the function void CAROTENE_NS::convolution
template<int ksize>
static inline int filter(int start, int end, Filter2D* data, const uchar* src_data, size_t src_step, uchar* dst_data, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
{
float kernel[ksize * ksize];
for (int i = 0; i < ksize * ksize; i++)
{
kernel[i] = reinterpret_cast<const float*>(data->kernel_data + (i / ksize) * data->kernel_step)[i % ksize];
}
constexpr int noval = std::numeric_limits<int>::max();
auto access = [&](int x, int y) {
int pi, pj;
if (data->borderType & BORDER_ISOLATED)
{
pi = common::borderInterpolate(x - data->anchor_y, height, data->borderType & ~BORDER_ISOLATED);
pj = common::borderInterpolate(y - data->anchor_x, width , data->borderType & ~BORDER_ISOLATED);
pi = pi < 0 ? noval : pi;
pj = pj < 0 ? noval : pj;
}
else
{
pi = common::borderInterpolate(offset_y + x - data->anchor_y, full_height, data->borderType);
pj = common::borderInterpolate(offset_x + y - data->anchor_x, full_width , data->borderType);
pi = pi < 0 ? noval : pi - offset_y;
pj = pj < 0 ? noval : pj - offset_x;
}
return std::make_pair(pi, pj);
};
auto process = [&](int x, int y) {
float sum0, sum1, sum2, sum3;
sum0 = sum1 = sum2 = sum3 = data->delta;
for (int i = 0; i < ksize * ksize; i++)
{
auto p = access(x + i / ksize, y + i % ksize);
if (p.first != noval && p.second != noval)
{
sum0 += kernel[i] * src_data[p.first * src_step + p.second * 4 ];
sum1 += kernel[i] * src_data[p.first * src_step + p.second * 4 + 1];
sum2 += kernel[i] * src_data[p.first * src_step + p.second * 4 + 2];
sum3 += kernel[i] * src_data[p.first * src_step + p.second * 4 + 3];
}
}
dst_data[(x * width + y) * 4 ] = std::max(0, std::min((int)std::round(sum0), (int)std::numeric_limits<uchar>::max()));
dst_data[(x * width + y) * 4 + 1] = std::max(0, std::min((int)std::round(sum1), (int)std::numeric_limits<uchar>::max()));
dst_data[(x * width + y) * 4 + 2] = std::max(0, std::min((int)std::round(sum2), (int)std::numeric_limits<uchar>::max()));
dst_data[(x * width + y) * 4 + 3] = std::max(0, std::min((int)std::round(sum3), (int)std::numeric_limits<uchar>::max()));
};
const int left = data->anchor_x, right = width - (ksize - 1 - data->anchor_x);
for (int i = start; i < end; i++)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
const uchar* row0 = access(i , 0).first == noval ? nullptr : src_data + access(i , 0).first * src_step;
const uchar* row1 = access(i + 1, 0).first == noval ? nullptr : src_data + access(i + 1, 0).first * src_step;
const uchar* row2 = access(i + 2, 0).first == noval ? nullptr : src_data + access(i + 2, 0).first * src_step;
if (ksize == 3)
{
process3(data->anchor_x, left, right, data->delta, kernel, row0, row1, row2, dst_data + i * width * 4);
}
else
{
const uchar* row3 = access(i + 3, 0).first == noval ? nullptr : src_data + access(i + 3, 0).first * src_step;
const uchar* row4 = access(i + 4, 0).first == noval ? nullptr : src_data + access(i + 4, 0).first * src_step;
process5(data->anchor_x, left, right, data->delta, kernel, row0, row1, row2, row3, row4, dst_data + i * width * 4);
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int filterInit(cvhalFilter2D** context, uchar* kernel_data, size_t kernel_step, int kernel_type, int kernel_width, int kernel_height, int /*max_width*/, int /*max_height*/, int src_type, int dst_type, int borderType, double delta, int anchor_x, int anchor_y, bool /*allowSubmatrix*/, bool /*allowInplace*/)
{
if (kernel_type != CV_32FC1 || src_type != CV_8UC4 || dst_type != CV_8UC4)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (kernel_width != kernel_height)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (kernel_width != 3 && kernel_width != 5)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((borderType & ~BORDER_ISOLATED) == BORDER_WRAP)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
anchor_x = anchor_x < 0 ? kernel_width / 2 : anchor_x;
anchor_y = anchor_y < 0 ? kernel_height / 2 : anchor_y;
*context = reinterpret_cast<cvhalFilter2D*>(new Filter2D{kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, src_type, dst_type, borderType, delta, anchor_x, anchor_y});
return CV_HAL_ERROR_OK;
}
int filter(cvhalFilter2D* context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
{
Filter2D* data = reinterpret_cast<Filter2D*>(context);
std::vector<uchar> dst(width * height * 4);
int res = CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (data->kernel_width)
{
case 3:
res = common::invoke(height, {filter<3>}, data, src_data, src_step, dst.data(), width, height, full_width, full_height, offset_x, offset_y);
break;
case 5:
res = common::invoke(height, {filter<5>}, data, src_data, src_step, dst.data(), width, height, full_width, full_height, offset_x, offset_y);
break;
}
for (int i = 0; i < height; i++)
memcpy(dst_data + i * dst_step, dst.data() + i * width * 4, width * 4);
return res;
}
int filterFree(cvhalFilter2D* context)
{
delete reinterpret_cast<Filter2D*>(context);
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+389
View File
@@ -0,0 +1,389 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is same as cv_hal_sepFilter
template<int ksize, typename helperT, typename helperWT>
static inline int gaussianBlurC1(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int full_width, int full_height, int offset_x, int offset_y, int border_type)
{
using T = typename helperT::ElemType;
using WT = typename helperWT::ElemType;
constexpr int noval = std::numeric_limits<int>::max();
auto accessX = [&](int x) {
int pi = common::borderInterpolate(offset_y + x - ksize / 2, full_height, border_type); // [TODO] fix dependencies
return pi < 0 ? noval : pi - offset_y;
};
auto accessY = [&](int y) {
int pj = common::borderInterpolate(offset_x + y - ksize / 2, full_width, border_type);
return pj < 0 ? noval : pj - offset_x;
};
auto p2idx = [&](int x, int y){ return (x + ksize) % ksize * width + y; };
constexpr uint kernel[2][5] = {{1, 2, 1}, {1, 4, 6, 4, 1}};
std::vector<WT> res(width * ksize);
auto process = [&](int x, int y) {
WT sum = 0;
for (int i = 0; i < ksize; i++)
{
int p = accessY(y + i);
if (p != noval)
{
sum += kernel[ksize == 5][i] * static_cast<WT>(reinterpret_cast<const T*>(src_data + x * src_step)[p]);
}
}
res[p2idx(x, y)] = sum;
};
const int left = ksize / 2, right = width - ksize / 2;
for (int i = start - ksize / 2; i < end + ksize / 2; i++)
{
if (i + offset_y >= 0 && i + offset_y < full_height)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = helperT::setvl(right - j);
const T* extra = reinterpret_cast<const T*>(src_data + i * src_step) + j - ksize / 2;
auto src = __riscv_vzext_vf2(helperT::vload(extra, vl), vl);
extra += vl;
auto sum = src;
if (ksize == 3)
{
src = __riscv_vslide1down(src, extra[0], vl);
sum = __riscv_vadd(sum, __riscv_vsll(src, 1, vl), vl);
src = __riscv_vslide1down(src, extra[1], vl);
sum = __riscv_vadd(sum, src, vl);
}
else
{
src = __riscv_vslide1down(src, extra[0], vl);
sum = __riscv_vadd(sum, __riscv_vsll(src, 2, vl), vl);
src = __riscv_vslide1down(src, extra[1], vl);
sum = __riscv_vadd(sum, __riscv_vadd(__riscv_vsll(src, 1, vl), __riscv_vsll(src, 2, vl), vl), vl);
src = __riscv_vslide1down(src, extra[2], vl);
sum = __riscv_vadd(sum, __riscv_vsll(src, 2, vl), vl);
src = __riscv_vslide1down(src, extra[3], vl);
sum = __riscv_vadd(sum, src, vl);
}
helperWT::vstore(res.data() + p2idx(i, j), sum, vl);
}
}
}
int cur = i - ksize / 2;
if (cur >= start)
{
const WT* row0 = accessX(cur ) == noval ? nullptr : res.data() + p2idx(accessX(cur ), 0);
const WT* row1 = accessX(cur + 1) == noval ? nullptr : res.data() + p2idx(accessX(cur + 1), 0);
const WT* row2 = accessX(cur + 2) == noval ? nullptr : res.data() + p2idx(accessX(cur + 2), 0);
const WT* row3 = nullptr, *row4 = nullptr;
if (ksize == 5)
{
row3 = accessX(cur + 3) == noval ? nullptr : res.data() + p2idx(accessX(cur + 3), 0);
row4 = accessX(cur + 4) == noval ? nullptr : res.data() + p2idx(accessX(cur + 4), 0);
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = helperWT::setvl(width - j);
auto v0 = row0 ? helperWT::vload(row0 + j, vl) : helperWT::vmv(0, vl);
auto v1 = row1 ? helperWT::vload(row1 + j, vl) : helperWT::vmv(0, vl);
auto v2 = row2 ? helperWT::vload(row2 + j, vl) : helperWT::vmv(0, vl);
typename helperWT::VecType sum;
if (ksize == 3)
{
sum = __riscv_vadd(__riscv_vadd(v0, v2, vl), __riscv_vsll(v1, 1, vl), vl);
}
else
{
sum = __riscv_vadd(v0, __riscv_vadd(__riscv_vsll(v2, 1, vl), __riscv_vsll(v2, 2, vl), vl), vl);
auto v3 = row3 ? helperWT::vload(row3 + j, vl) : helperWT::vmv(0, vl);
sum = __riscv_vadd(sum, __riscv_vsll(__riscv_vadd(v1, v3, vl), 2, vl), vl);
auto v4 = row4 ? helperWT::vload(row4 + j, vl) : helperWT::vmv(0, vl);
sum = __riscv_vadd(sum, v4, vl);
}
helperT::vstore(reinterpret_cast<T*>(dst_data + cur * dst_step) + j, __riscv_vnclipu(sum, ksize == 5 ? 8 : 4, __RISCV_VXRM_RNU, vl), vl);
}
}
}
return CV_HAL_ERROR_OK;
}
template<int ksize>
static inline int gaussianBlurC4(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int full_width, int full_height, int offset_x, int offset_y, int border_type)
{
constexpr int noval = std::numeric_limits<int>::max();
auto accessX = [&](int x) {
int pi = common::borderInterpolate(offset_y + x - ksize / 2, full_height, border_type);
return pi < 0 ? noval : pi - offset_y;
};
auto accessY = [&](int y) {
int pj = common::borderInterpolate(offset_x + y - ksize / 2, full_width, border_type);
return pj < 0 ? noval : pj - offset_x;
};
auto p2idx = [&](int x, int y){ return ((x + ksize) % ksize * width + y) * 4; };
constexpr uint kernel[2][5] = {{1, 2, 1}, {1, 4, 6, 4, 1}};
std::vector<ushort> res(width * ksize * 4);
auto process = [&](int x, int y) {
ushort sum0, sum1, sum2, sum3;
sum0 = sum1 = sum2 = sum3 = 0;
for (int i = 0; i < ksize; i++)
{
int p = accessY(y + i);
if (p != noval)
{
sum0 += kernel[ksize == 5][i] * static_cast<ushort>((src_data + x * src_step)[p * 4 ]);
sum1 += kernel[ksize == 5][i] * static_cast<ushort>((src_data + x * src_step)[p * 4 + 1]);
sum2 += kernel[ksize == 5][i] * static_cast<ushort>((src_data + x * src_step)[p * 4 + 2]);
sum3 += kernel[ksize == 5][i] * static_cast<ushort>((src_data + x * src_step)[p * 4 + 3]);
}
}
res[p2idx(x, y) ] = sum0;
res[p2idx(x, y) + 1] = sum1;
res[p2idx(x, y) + 2] = sum2;
res[p2idx(x, y) + 3] = sum3;
};
const int left = ksize / 2, right = width - ksize / 2;
for (int i = start - ksize / 2; i < end + ksize / 2; i++)
{
if (i + offset_y >= 0 && i + offset_y < full_height)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m1(right - j);
const uchar* extra = src_data + i * src_step + (j - ksize / 2) * 4;
auto src = __riscv_vlseg4e8_v_u8m1x4(extra, vl);
auto src0 = __riscv_vzext_vf2(__riscv_vget_v_u8m1x4_u8m1(src, 0), vl);
auto src1 = __riscv_vzext_vf2(__riscv_vget_v_u8m1x4_u8m1(src, 1), vl);
auto src2 = __riscv_vzext_vf2(__riscv_vget_v_u8m1x4_u8m1(src, 2), vl);
auto src3 = __riscv_vzext_vf2(__riscv_vget_v_u8m1x4_u8m1(src, 3), vl);
extra += vl * 4;
auto sum0 = src0, sum1 = src1, sum2 = src2, sum3 = src3;
if (ksize == 3)
{
src0 = __riscv_vslide1down(src0, extra[0], vl);
src1 = __riscv_vslide1down(src1, extra[1], vl);
src2 = __riscv_vslide1down(src2, extra[2], vl);
src3 = __riscv_vslide1down(src3, extra[3], vl);
sum0 = __riscv_vadd(sum0, __riscv_vsll(src0, 1, vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vsll(src1, 1, vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vsll(src2, 1, vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vsll(src3, 1, vl), vl);
src0 = __riscv_vslide1down(src0, extra[4], vl);
src1 = __riscv_vslide1down(src1, extra[5], vl);
src2 = __riscv_vslide1down(src2, extra[6], vl);
src3 = __riscv_vslide1down(src3, extra[7], vl);
sum0 = __riscv_vadd(sum0, src0, vl);
sum1 = __riscv_vadd(sum1, src1, vl);
sum2 = __riscv_vadd(sum2, src2, vl);
sum3 = __riscv_vadd(sum3, src3, vl);
}
else
{
src0 = __riscv_vslide1down(src0, extra[0], vl);
src1 = __riscv_vslide1down(src1, extra[1], vl);
src2 = __riscv_vslide1down(src2, extra[2], vl);
src3 = __riscv_vslide1down(src3, extra[3], vl);
sum0 = __riscv_vadd(sum0, __riscv_vsll(src0, 2, vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vsll(src1, 2, vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vsll(src2, 2, vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vsll(src3, 2, vl), vl);
src0 = __riscv_vslide1down(src0, extra[4], vl);
src1 = __riscv_vslide1down(src1, extra[5], vl);
src2 = __riscv_vslide1down(src2, extra[6], vl);
src3 = __riscv_vslide1down(src3, extra[7], vl);
sum0 = __riscv_vadd(sum0, __riscv_vadd(__riscv_vsll(src0, 1, vl), __riscv_vsll(src0, 2, vl), vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vadd(__riscv_vsll(src1, 1, vl), __riscv_vsll(src1, 2, vl), vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vadd(__riscv_vsll(src2, 1, vl), __riscv_vsll(src2, 2, vl), vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vadd(__riscv_vsll(src3, 1, vl), __riscv_vsll(src3, 2, vl), vl), vl);
src0 = __riscv_vslide1down(src0, extra[ 8], vl);
src1 = __riscv_vslide1down(src1, extra[ 9], vl);
src2 = __riscv_vslide1down(src2, extra[10], vl);
src3 = __riscv_vslide1down(src3, extra[11], vl);
sum0 = __riscv_vadd(sum0, __riscv_vsll(src0, 2, vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vsll(src1, 2, vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vsll(src2, 2, vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vsll(src3, 2, vl), vl);
src0 = __riscv_vslide1down(src0, extra[12], vl);
src1 = __riscv_vslide1down(src1, extra[13], vl);
src2 = __riscv_vslide1down(src2, extra[14], vl);
src3 = __riscv_vslide1down(src3, extra[15], vl);
sum0 = __riscv_vadd(sum0, src0, vl);
sum1 = __riscv_vadd(sum1, src1, vl);
sum2 = __riscv_vadd(sum2, src2, vl);
sum3 = __riscv_vadd(sum3, src3, vl);
}
vuint16m2x4_t dst{};
dst = __riscv_vset_v_u16m2_u16m2x4(dst, 0, sum0);
dst = __riscv_vset_v_u16m2_u16m2x4(dst, 1, sum1);
dst = __riscv_vset_v_u16m2_u16m2x4(dst, 2, sum2);
dst = __riscv_vset_v_u16m2_u16m2x4(dst, 3, sum3);
__riscv_vsseg4e16(res.data() + p2idx(i, j), dst, vl);
}
}
}
int cur = i - ksize / 2;
if (cur >= start)
{
const ushort* row0 = accessX(cur ) == noval ? nullptr : res.data() + p2idx(accessX(cur ), 0);
const ushort* row1 = accessX(cur + 1) == noval ? nullptr : res.data() + p2idx(accessX(cur + 1), 0);
const ushort* row2 = accessX(cur + 2) == noval ? nullptr : res.data() + p2idx(accessX(cur + 2), 0);
const ushort* row3 = nullptr, *row4 = nullptr;
if (ksize == 5)
{
row3 = accessX(cur + 3) == noval ? nullptr : res.data() + p2idx(accessX(cur + 3), 0);
row4 = accessX(cur + 4) == noval ? nullptr : res.data() + p2idx(accessX(cur + 4), 0);
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e16m2(width - j);
vuint16m2_t sum0, sum1, sum2, sum3, src0{}, src1{}, src2{}, src3{};
sum0 = sum1 = sum2 = sum3 = __riscv_vmv_v_x_u16m2(0, vl);
auto loadres = [&](const ushort* row) {
auto src = __riscv_vlseg4e16_v_u16m2x4(row + j * 4, vl);
src0 = __riscv_vget_v_u16m2x4_u16m2(src, 0);
src1 = __riscv_vget_v_u16m2x4_u16m2(src, 1);
src2 = __riscv_vget_v_u16m2x4_u16m2(src, 2);
src3 = __riscv_vget_v_u16m2x4_u16m2(src, 3);
};
if (row0)
{
loadres(row0);
sum0 = src0;
sum1 = src1;
sum2 = src2;
sum3 = src3;
}
if (row1)
{
loadres(row1);
sum0 = __riscv_vadd(sum0, __riscv_vsll(src0, ksize == 5 ? 2 : 1, vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vsll(src1, ksize == 5 ? 2 : 1, vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vsll(src2, ksize == 5 ? 2 : 1, vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vsll(src3, ksize == 5 ? 2 : 1, vl), vl);
}
if (row2)
{
loadres(row2);
if (ksize == 5)
{
src0 = __riscv_vadd(__riscv_vsll(src0, 1, vl), __riscv_vsll(src0, 2, vl), vl);
src1 = __riscv_vadd(__riscv_vsll(src1, 1, vl), __riscv_vsll(src1, 2, vl), vl);
src2 = __riscv_vadd(__riscv_vsll(src2, 1, vl), __riscv_vsll(src2, 2, vl), vl);
src3 = __riscv_vadd(__riscv_vsll(src3, 1, vl), __riscv_vsll(src3, 2, vl), vl);
}
sum0 = __riscv_vadd(sum0, src0, vl);
sum1 = __riscv_vadd(sum1, src1, vl);
sum2 = __riscv_vadd(sum2, src2, vl);
sum3 = __riscv_vadd(sum3, src3, vl);
}
if (row3)
{
loadres(row3);
sum0 = __riscv_vadd(sum0, __riscv_vsll(src0, 2, vl), vl);
sum1 = __riscv_vadd(sum1, __riscv_vsll(src1, 2, vl), vl);
sum2 = __riscv_vadd(sum2, __riscv_vsll(src2, 2, vl), vl);
sum3 = __riscv_vadd(sum3, __riscv_vsll(src3, 2, vl), vl);
}
if (row4)
{
loadres(row4);
sum0 = __riscv_vadd(sum0, src0, vl);
sum1 = __riscv_vadd(sum1, src1, vl);
sum2 = __riscv_vadd(sum2, src2, vl);
sum3 = __riscv_vadd(sum3, src3, vl);
}
vuint8m1x4_t dst{};
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 0, __riscv_vnclipu(sum0, ksize == 5 ? 8 : 4, __RISCV_VXRM_RNU, vl));
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 1, __riscv_vnclipu(sum1, ksize == 5 ? 8 : 4, __RISCV_VXRM_RNU, vl));
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 2, __riscv_vnclipu(sum2, ksize == 5 ? 8 : 4, __RISCV_VXRM_RNU, vl));
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 3, __riscv_vnclipu(sum3, ksize == 5 ? 8 : 4, __RISCV_VXRM_RNU, vl));
__riscv_vsseg4e8(dst_data + cur * dst_step + j * 4, dst, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int gaussianBlurBinomial(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, size_t margin_left, size_t margin_top, size_t margin_right, size_t margin_bottom, size_t ksize, int border_type)
{
const int type = CV_MAKETYPE(depth, cn);
if ((type != CV_8UC1 && type != CV_8UC4 && type != CV_16UC1) || src_data == dst_data)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((ksize != 3 && ksize != 5) || border_type & BORDER_ISOLATED || border_type == BORDER_WRAP)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (ksize*100 + type)
{
case 300 + CV_8UC1:
return common::invoke(height, {gaussianBlurC1<3, RVV_U8M4, RVV_U16M8>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
case 500 + CV_8UC1:
return common::invoke(height, {gaussianBlurC1<5, RVV_U8M4, RVV_U16M8>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
case 300 + CV_16UC1:
return common::invoke(height, {gaussianBlurC1<3, RVV_U16M4, RVV_U32M8>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
case 500 + CV_16UC1:
return common::invoke(height, {gaussianBlurC1<5, RVV_U16M4, RVV_U32M8>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
case 300 + CV_8UC4:
return common::invoke(height, {gaussianBlurC4<3>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
case 500 + CV_8UC4:
return common::invoke(height, {gaussianBlurC4<5>}, src_data, src_step, dst_data, dst_step, width, margin_left + width + margin_right, margin_top + height + margin_bottom, margin_left, margin_top, border_type);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+282
View File
@@ -0,0 +1,282 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
#include "rvv_hal.hpp"
#include <cstring>
#include <vector>
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
class HistogramInvoker : public ParallelLoopBody
{
public:
template<typename... Args>
HistogramInvoker(std::function<void(int, int, Args...)> _func, Args&&... args)
{
func = std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::forward<Args>(args)...);
}
virtual void operator()(const Range& range) const override
{
func(range.start, range.end);
}
private:
std::function<void(int, int)> func;
};
constexpr int HIST_SZ = std::numeric_limits<uchar>::max() + 1;
static inline void hist_invoke(int start, int end, const uchar* src_data, size_t src_step, int width, int* hist, std::mutex* m)
{
int h[HIST_SZ] = {0};
for (int i = start; i < end; i++)
{
const uchar* src = src_data + i * src_step;
int j;
for (j = 0; j + 3 < width; j += 4)
{
int t0 = src[j], t1 = src[j+1];
h[t0]++; h[t1]++;
t0 = src[j+2]; t1 = src[j+3];
h[t0]++; h[t1]++;
}
for (; j < width; j++)
{
h[src[j]]++;
}
}
std::lock_guard<std::mutex> lk(*m);
for (int i = 0; i < HIST_SZ; i++)
{
hist[i] += h[i];
}
}
static inline void lut_invoke(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, const uchar* lut)
{
for (int i = start; i < end; i++)
{
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e8m8(width - j);
auto src = __riscv_vle8_v_u8m8(src_data + i * src_step + j, vl);
auto dst = __riscv_vloxei8_v_u8m8(lut, src, vl);
__riscv_vse8(dst_data + i * dst_step + j, dst, vl);
}
}
}
} // equalize_hist
// the algorithm is copied from imgproc/src/histogram.cpp,
// in the function void cv::equalizeHist
int equalize_hist(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height)
{
int hist[HIST_SZ] = {0};
uchar lut[HIST_SZ];
std::mutex m;
cv::parallel_for_(Range(0, height), HistogramInvoker({hist_invoke}, src_data, src_step, width, reinterpret_cast<int *>(hist), &m), static_cast<double>(width * height) / (1 << 15));
int i = 0;
while (!hist[i]) ++i;
float scale = (HIST_SZ - 1.f)/(width * height - hist[i]);
int sum = 0;
for (lut[i++] = 0; i < HIST_SZ; i++)
{
sum += hist[i];
lut[i] = std::min(std::max(static_cast<int>(std::round(sum * scale)), 0), HIST_SZ - 1);
}
cv::parallel_for_(Range(0, height), HistogramInvoker({lut_invoke}, src_data, src_step, dst_data, dst_step, width, reinterpret_cast<const uchar*>(lut)), static_cast<double>(width * height) / (1 << 15));
return CV_HAL_ERROR_OK;
}
// ############ calc_hist ############
namespace {
constexpr int MAX_VLEN = 1024;
constexpr int MAX_E8M1 = MAX_VLEN / 8;
inline void cvt_32s32f(const int* ihist, float* fhist, int hist_size) {
int vl;
for (int i = 0; i < hist_size; i += vl) {
vl = __riscv_vsetvl_e32m8(hist_size - i);
auto iv = __riscv_vle32_v_i32m8(ihist + i, vl);
__riscv_vse32(fhist + i, __riscv_vfcvt_f(iv, vl), vl);
}
}
inline void cvt32s32f_add32f(const int* ihist, float* fhist, int hist_size) {
int vl;
for (int i = 0; i < hist_size; i += vl) {
vl = __riscv_vsetvl_e32m8(hist_size - i);
auto iv = __riscv_vle32_v_i32m8(ihist + i, vl);
auto fv = __riscv_vle32_v_f32m8(fhist + i, vl);
auto s = __riscv_vfadd(__riscv_vfcvt_f(iv, vl), fv, vl);
__riscv_vse32(fhist + i, s, vl);
}
}
}
int calc_hist(const uchar* src_data, size_t src_step, int src_type, int src_width, int src_height,
float* hist_data, int hist_size, const float** ranges, bool uniform, bool accumulate) {
int depth = CV_MAT_DEPTH(src_type), cn = CV_MAT_CN(src_type);
// [TODO] support non-uniform
// In case of CV_8U, it is already fast enough with lut
if ((depth != CV_16U && depth != CV_32F) || !uniform) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
std::vector<int> buf_ihist(hist_size+1, 0);
int* ihist = buf_ihist.data();
double low = ranges[0][0], high = ranges[0][1];
double t = hist_size / (high - low);
double a = t, b = -t * low;
double v0_lo = low, v0_hi = high;
int sz = hist_size, d0 = cn, step0 = (int)(src_step / CV_ELEM_SIZE1(src_type));
int buf_idx[MAX_E8M1];
if (depth == CV_16U) {
const ushort* p0 = (const ushort*)src_data;
if (d0 == 1) {
while (src_height--) {
int vl;
for (int x = 0; x < src_width; x += vl) {
vl = __riscv_vsetvl_e16m2(src_width - x);
auto v = __riscv_vfcvt_f(__riscv_vwcvtu_x(__riscv_vwcvtu_x(__riscv_vle16_v_u16m2(p0 + x, vl), vl), vl), vl);
auto m0 = __riscv_vmflt(v, v0_lo, vl);
auto m1 = __riscv_vmfge(v, v0_hi, vl);
auto m = __riscv_vmor(m0, m1, vl);
auto fidx = __riscv_vfadd(__riscv_vfmul(v, a, vl), b, vl);
auto idx = __riscv_vfncvt_x(__riscv_vfsub(fidx, 0.5f - 1e-6, vl), vl);
idx = __riscv_vmerge(idx, 0, __riscv_vmslt(idx, 0, vl), vl);
idx = __riscv_vmerge(idx, sz-1, __riscv_vmsgt(idx, sz-1, vl), vl);
idx = __riscv_vmerge(idx, -1, m, vl);
__riscv_vse32(buf_idx, idx, vl);
for (int i = 0; i < vl; i++) {
int _idx = buf_idx[i] + 1;
ihist[_idx]++;
}
}
p0 += step0;
}
} else {
while (src_height--) {
int vl;
for (int x = 0; x < src_width; x += vl) {
vl = __riscv_vsetvl_e16m2(src_width - x);
auto v = __riscv_vfcvt_f(__riscv_vwcvtu_x(__riscv_vwcvtu_x(__riscv_vlse16_v_u16m2(p0 + x*d0, sizeof(ushort)*d0, vl), vl), vl), vl);
auto m0 = __riscv_vmflt(v, v0_lo, vl);
auto m1 = __riscv_vmfge(v, v0_hi, vl);
auto m = __riscv_vmor(m0, m1, vl);
auto fidx = __riscv_vfadd(__riscv_vfmul(v, a, vl), b, vl);
auto idx = __riscv_vfncvt_x(__riscv_vfsub(fidx, 0.5f - 1e-6, vl), vl);
idx = __riscv_vmerge(idx, 0, __riscv_vmslt(idx, 0, vl), vl);
idx = __riscv_vmerge(idx, sz-1, __riscv_vmsgt(idx, sz-1, vl), vl);
idx = __riscv_vmerge(idx, -1, m, vl);
__riscv_vse32(buf_idx, idx, vl);
for (int i = 0; i < vl; i++) {
int _idx = buf_idx[i] + 1;
ihist[_idx]++;
}
}
p0 += step0;
}
}
} else if (depth == CV_32F) {
const float* p0 = (const float*)src_data;
if (d0 == 1) {
while (src_height--) {
int vl;
for (int x = 0; x < src_width; x += vl) {
vl = __riscv_vsetvl_e32m4(src_width - x);
auto v = __riscv_vfwcvt_f(__riscv_vle32_v_f32m4(p0 + x, vl), vl);
auto m0 = __riscv_vmflt(v, v0_lo, vl);
auto m1 = __riscv_vmfge(v, v0_hi, vl);
auto m = __riscv_vmor(m0, m1, vl);
auto fidx = __riscv_vfadd(__riscv_vfmul(v, a, vl), b, vl);
auto idx = __riscv_vfncvt_x(__riscv_vfsub(fidx, 0.5f - 1e-6, vl), vl);
idx = __riscv_vmerge(idx, 0, __riscv_vmslt(idx, 0, vl), vl);
idx = __riscv_vmerge(idx, sz-1, __riscv_vmsgt(idx, sz-1, vl), vl);
idx = __riscv_vmerge(idx, -1, m, vl);
__riscv_vse32(buf_idx, idx, vl);
for (int i = 0; i < vl; i++) {
int _idx = buf_idx[i] + 1;
ihist[_idx]++;
}
}
p0 += step0;
}
} else {
while (src_height--) {
int vl;
for (int x = 0; x < src_width; x += vl) {
vl = __riscv_vsetvl_e32m4(src_width - x);
auto v = __riscv_vfwcvt_f(__riscv_vlse32_v_f32m4(p0 + x*d0, sizeof(float)*d0, vl), vl);
auto m0 = __riscv_vmflt(v, v0_lo, vl);
auto m1 = __riscv_vmfge(v, v0_hi, vl);
auto m = __riscv_vmor(m0, m1, vl);
auto fidx = __riscv_vfadd(__riscv_vfmul(v, a, vl), b, vl);
auto idx = __riscv_vfncvt_x(__riscv_vfsub(fidx, 0.5f - 1e-6, vl), vl);
idx = __riscv_vmerge(idx, 0, __riscv_vmslt(idx, 0, vl), vl);
idx = __riscv_vmerge(idx, sz-1, __riscv_vmsgt(idx, sz-1, vl), vl);
idx = __riscv_vmerge(idx, -1, m, vl);
__riscv_vse32(buf_idx, idx, vl);
for (int i = 0; i < vl; i++) {
int _idx = buf_idx[i] + 1;
ihist[_idx]++;
}
}
p0 += step0;
}
}
}
if (accumulate) {
cvt32s32f_add32f(ihist+1, hist_data, hist_size);
} else {
std::memset(hist_data, 0, sizeof(float)*hist_size);
cvt_32s32f(ihist+1, hist_data, hist_size);
}
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+177
View File
@@ -0,0 +1,177 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template <typename vec_t>
inline typename vec_t::VecType repeat_last_n(typename vec_t::VecType vs, int n, size_t vl) {
auto v_last = vec_t::vslidedown(vs, vl - n, vl);
if (n == 1) return vec_t::vmv(vec_t::vmv_x(v_last), vl);
for (size_t offset = n; offset < vl; offset <<= 1) {
v_last = vec_t::vslideup(v_last, v_last, offset, vl);
}
return v_last;
}
template <typename data_vec_t, typename acc_vec_t, bool sqsum = false>
inline int integral_inner(const uchar* src_data, size_t src_step,
uchar* sum_data, size_t sum_step,
int width, int height, int cn) {
using data_t = typename data_vec_t::ElemType;
using acc_t = typename acc_vec_t::ElemType;
for (int y = 0; y < height; y++) {
const data_t* src = reinterpret_cast<const data_t*>(src_data + src_step * y);
acc_t* prev = reinterpret_cast<acc_t*>(sum_data + sum_step * y);
acc_t* curr = reinterpret_cast<acc_t*>(sum_data + sum_step * (y + 1));
memset(curr, 0, cn * sizeof(acc_t));
size_t vl = acc_vec_t::setvlmax();
auto sum = acc_vec_t::vmv(0, vl);
for (size_t x = 0; x < static_cast<size_t>(width); x += vl) {
vl = acc_vec_t::setvl(width - x);
__builtin_prefetch(&src[x + vl], 0);
__builtin_prefetch(&prev[x + cn], 0);
auto v_src = data_vec_t::vload(&src[x], vl);
auto acc = acc_vec_t::cast(v_src, vl);
if (sqsum) { // Squared Sum
acc = acc_vec_t::vmul(acc, acc, vl);
}
auto v_zero = acc_vec_t::vmv(0, vl);
for (size_t offset = cn; offset < vl; offset <<= 1) {
auto v_shift = acc_vec_t::vslideup(v_zero, acc, offset, vl);
acc = acc_vec_t::vadd(acc, v_shift, vl);
}
auto last_n = repeat_last_n<acc_vec_t>(acc, cn, vl);
auto v_prev = acc_vec_t::vload(&prev[x + cn], vl);
acc = acc_vec_t::vadd(acc, v_prev, vl);
acc = acc_vec_t::vadd(acc, sum, vl);
sum = acc_vec_t::vadd(sum, last_n, vl);
acc_vec_t::vstore(&curr[x + cn], acc, vl);
}
}
return CV_HAL_ERROR_OK;
}
template <typename data_vec_t, typename acc_vec_t, typename sq_acc_vec_t>
inline int integral(const uchar* src_data, size_t src_step, uchar* sum_data, size_t sum_step, uchar* sqsum_data, size_t sqsum_step, int width, int height, int cn) {
memset(sum_data, 0, (sum_step) * sizeof(uchar));
int result = CV_HAL_ERROR_NOT_IMPLEMENTED;
if (sqsum_data == nullptr) {
result = integral_inner<data_vec_t, acc_vec_t, false>(src_data, src_step, sum_data, sum_step, width, height, cn);
} else {
result = integral_inner<data_vec_t, acc_vec_t, false>(src_data, src_step, sum_data, sum_step, width, height, cn);
memset(sqsum_data, 0, (sqsum_step) * sizeof(uchar));
if (result != CV_HAL_ERROR_OK) return result;
result = integral_inner<data_vec_t, sq_acc_vec_t, true>(src_data, src_step, sqsum_data, sqsum_step, width, height, cn);
}
return result;
}
} // anonymous
/**
@brief Calculate integral image
@param depth Depth of source image
@param sdepth Depth of sum image
@param sqdepth Depth of square sum image
@param src_data Source image data
@param src_step Source image step
@param sum_data Sum image data
@param sum_step Sum image step
@param sqsum_data Square sum image data
@param sqsum_step Square sum image step
@param tilted_data Tilted sum image data
@param tilted_step Tilted sum image step
@param width Source image width
@param height Source image height
@param cn Number of channels
@note Following combinations of image depths are used:
Source | Sum | Square sum
-------|-----|-----------
CV_8U | CV_32S | CV_64F
CV_8U | CV_32S | CV_32F
CV_8U | CV_32S | CV_32S
CV_8U | CV_32F | CV_64F
CV_8U | CV_32F | CV_32F
CV_8U | CV_64F | CV_64F
CV_16U | CV_64F | CV_64F
CV_16S | CV_64F | CV_64F
CV_32F | CV_32F | CV_64F
CV_32F | CV_32F | CV_32F
CV_32F | CV_64F | CV_64F
CV_64F | CV_64F | CV_64F
*/
int integral(int depth, int sdepth, int sqdepth,
const uchar* src_data, size_t src_step,
uchar* sum_data, size_t sum_step,
uchar* sqsum_data, size_t sqsum_step,
uchar* tilted_data, [[maybe_unused]] size_t tilted_step,
int width, int height, int cn) {
// tilted sum and cn == 3 cases are not supported
if (tilted_data || cn == 3) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
// CV_32F sqsum kept on generic path due to accumulation-order sensitivity, see #27407
if (sqsum_data && (sdepth == CV_32F || sqdepth == CV_32F)) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
// Skip images that are too small
if (!(width >> 8 || height >> 8)) {
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
int result = CV_HAL_ERROR_NOT_IMPLEMENTED;
width *= cn;
if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_64F )
result = integral<RVV<uint8_t, LMUL_1>, RVV<int32_t, LMUL_4>, RVV<double, LMUL_8>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32F )
result = integral<RVV<uint8_t, LMUL_1>, RVV<int32_t, LMUL_4>, RVV<float, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_8U && sdepth == CV_32S && sqdepth == CV_32S )
result = integral<RVV<uint8_t, LMUL_1>, RVV<int32_t, LMUL_4>, RVV<int32_t, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_64F )
result = integral<RVV<uint8_t, LMUL_1>, RVV<float, LMUL_4>, RVV<double, LMUL_8>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_8U && sdepth == CV_32F && sqdepth == CV_32F )
result = integral<RVV<uint8_t, LMUL_1>, RVV<float, LMUL_4>, RVV<float, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_8U && sdepth == CV_64F && sqdepth == CV_64F )
result = integral<RVV<uint8_t, LMUL_1>, RVV<double, LMUL_8>, RVV<double, LMUL_8>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_16U && sdepth == CV_64F && sqdepth == CV_64F )
result = integral<RVV<uint16_t, LMUL_1>, RVV<double, LMUL_4>, RVV<double, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_16S && sdepth == CV_64F && sqdepth == CV_64F )
result = integral<RVV<int16_t, LMUL_1>, RVV<double, LMUL_4>, RVV<double, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_64F )
result = integral<RVV<float, LMUL_2>, RVV<float, LMUL_2>, RVV<double, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_32F && sdepth == CV_32F && sqdepth == CV_32F )
result = integral<RVV<float, LMUL_4>, RVV<float, LMUL_4>, RVV<float, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_32F && sdepth == CV_64F && sqdepth == CV_64F )
result = integral<RVV<float, LMUL_2>, RVV<double, LMUL_4>, RVV<double, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
else if( depth == CV_64F && sdepth == CV_64F && sqdepth == CV_64F ) {
result = integral<RVV<double, LMUL_4>, RVV<double, LMUL_4>, RVV<double, LMUL_4>>(src_data, src_step, sum_data, sum_step, sqsum_data, sqsum_step, width, height, cn);
}
return result;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+503
View File
@@ -0,0 +1,503 @@
// 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.
//
// Copyright (C) 2025.
#include "rvv_hal.hpp"
#include "common.hpp"
#include <vector>
#include <limits>
#include <algorithm>
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
static inline int borderMap(int x, int len, int border_type)
{
return common::borderInterpolate(x, len, border_type);
}
static inline uint8_t sample_u8(const uint8_t* src, size_t step, int width, int height, int y, int x, int border_type, uint8_t border_value)
{
int yy = borderMap(y, height, border_type);
int xx = borderMap(x, width , border_type);
if (yy < 0 || xx < 0)
return border_value;
return src[yy * step + xx];
}
static inline bool isLaplacian3x3Supported(int width, int height, int border_type)
{
return width >= 8 && height >= 1 &&
(border_type == BORDER_CONSTANT ||
border_type == BORDER_REPLICATE);
}
static inline bool isLaplacianOpenCVSupported(int width, int height, int border_type)
{
return width >= 8 && height >= 1 &&
(border_type == BORDER_CONSTANT ||
border_type == BORDER_REPLICATE ||
border_type == BORDER_REFLECT ||
border_type == BORDER_REFLECT_101);
}
static inline vint16m2_t vw_u8_to_i16(vuint8m1_t v, size_t vl)
{
vuint16m2_t u16 = __riscv_vwaddu_vx_u16m2(v, 0, vl);
return __riscv_vreinterpret_v_u16m2_i16m2(u16);
}
static inline vuint8m1_t clamp_to_u8(vint16m2_t v, size_t vl)
{
vint16m2_t zero = __riscv_vmv_v_x_i16m2(0, vl);
vint16m2_t maxv = __riscv_vmv_v_x_i16m2(255, vl);
v = __riscv_vmax_vv_i16m2(v, zero, vl);
v = __riscv_vmin_vv_i16m2(v, maxv, vl);
vuint16m2_t u16 = __riscv_vreinterpret_v_i16m2_u16m2(v);
return __riscv_vnclipu(u16, 0, __RISCV_VXRM_RNU, vl);
}
static int laplacian3x3_u8(int start, int end,
const uint8_t* src_data, size_t src_step,
uint8_t* dst_data, size_t dst_step,
int width, int height,
int border_type, uint8_t border_value)
{
if (!isLaplacian3x3Supported(width, height, border_type))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
for (int y = start; y < end; ++y)
{
int y0 = borderMap(y - 1, height, border_type);
int y1 = borderMap(y , height, border_type);
int y2 = borderMap(y + 1, height, border_type);
const uint8_t* r0 = (y0 < 0) ? nullptr : src_data + y0 * src_step;
const uint8_t* r1 = (y1 < 0) ? nullptr : src_data + y1 * src_step;
const uint8_t* r2 = (y2 < 0) ? nullptr : src_data + y2 * src_step;
uint8_t* drow = dst_data + y * dst_step;
int left = 1;
int right = width - 1;
if (right < left)
{
for (int x = 0; x < width; ++x)
{
int v0l = sample_u8(src_data, src_step, width, height, y - 1, x - 1, border_type, border_value);
int v0r = sample_u8(src_data, src_step, width, height, y - 1, x + 1, border_type, border_value);
int v2l = sample_u8(src_data, src_step, width, height, y + 1, x - 1, border_type, border_value);
int v2r = sample_u8(src_data, src_step, width, height, y + 1, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
int val = (v0l + v0r + v2l + v2r - 4 * v1) * 2;
val = std::max(0, std::min(255, val));
drow[x] = (uint8_t)val;
}
continue;
}
for (int x = 0; x < left; ++x)
{
int v0l = sample_u8(src_data, src_step, width, height, y - 1, x - 1, border_type, border_value);
int v0r = sample_u8(src_data, src_step, width, height, y - 1, x + 1, border_type, border_value);
int v2l = sample_u8(src_data, src_step, width, height, y + 1, x - 1, border_type, border_value);
int v2r = sample_u8(src_data, src_step, width, height, y + 1, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
int val = (v0l + v0r + v2l + v2r - 4 * v1) * 2;
val = std::max(0, std::min(255, val));
drow[x] = (uint8_t)val;
}
int x = left;
for (; x < right; )
{
size_t vl = __riscv_vsetvl_e8m1(right - x);
__builtin_prefetch(r0 ? (r0 + x - 1) : nullptr, 0, 3);
__builtin_prefetch(r1 + x, 0, 3);
__builtin_prefetch(r2 ? (r2 + x - 1) : nullptr, 0, 3);
vuint8m1_t v0l = r0 ? __riscv_vle8_v_u8m1(r0 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v0r = r0 ? __riscv_vle8_v_u8m1(r0 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v2l = r2 ? __riscv_vle8_v_u8m1(r2 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v2r = r2 ? __riscv_vle8_v_u8m1(r2 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v1 = r1 ? __riscv_vle8_v_u8m1(r1 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vint16m2_t s0l = vw_u8_to_i16(v0l, vl);
vint16m2_t s0r = vw_u8_to_i16(v0r, vl);
vint16m2_t s2l = vw_u8_to_i16(v2l, vl);
vint16m2_t s2r = vw_u8_to_i16(v2r, vl);
vint16m2_t s1 = vw_u8_to_i16(v1, vl);
vint16m2_t sum = __riscv_vadd_vv_i16m2(s0l, s0r, vl);
sum = __riscv_vadd_vv_i16m2(sum, s2l, vl);
sum = __riscv_vadd_vv_i16m2(sum, s2r, vl);
sum = __riscv_vsub_vv_i16m2(sum, __riscv_vsll_vx_i16m2(s1, 2, vl), vl);
sum = __riscv_vsll_vx_i16m2(sum, 1, vl);
vuint8m1_t out = clamp_to_u8(sum, vl);
__riscv_vse8_v_u8m1(drow + x, out, vl);
x += vl;
}
for (; x < width; ++x)
{
int v0l = sample_u8(src_data, src_step, width, height, y - 1, x - 1, border_type, border_value);
int v0r = sample_u8(src_data, src_step, width, height, y - 1, x + 1, border_type, border_value);
int v2l = sample_u8(src_data, src_step, width, height, y + 1, x - 1, border_type, border_value);
int v2r = sample_u8(src_data, src_step, width, height, y + 1, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
int val = (v0l + v0r + v2l + v2r - 4 * v1) * 2;
val = std::max(0, std::min(255, val));
drow[x] = (uint8_t)val;
}
}
return CV_HAL_ERROR_OK;
}
static int laplacian1(int start, int end,
const uint8_t* src_data, size_t src_step,
int16_t* dst_data, size_t dst_step,
int width, int height,
int border_type, uint8_t border_value)
{
if (!isLaplacianOpenCVSupported(width, height, border_type))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
for (int y = start; y < end; ++y)
{
int y0 = borderMap(y - 1, height, border_type);
int y1 = borderMap(y , height, border_type);
int y2 = borderMap(y + 1, height, border_type);
const uint8_t* r0 = (y0 < 0) ? nullptr : src_data + y0 * src_step;
const uint8_t* r1 = (y1 < 0) ? nullptr : src_data + y1 * src_step;
const uint8_t* r2 = (y2 < 0) ? nullptr : src_data + y2 * src_step;
int16_t* drow = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(dst_data) + y * dst_step);
int left = 1;
int right = width - 1;
for (int x = 0; x < left; ++x)
{
int v0 = sample_u8(src_data, src_step, width, height, y - 1, x, border_type, border_value);
int v2 = sample_u8(src_data, src_step, width, height, y + 1, x, border_type, border_value);
int v1l = sample_u8(src_data, src_step, width, height, y, x - 1, border_type, border_value);
int v1r = sample_u8(src_data, src_step, width, height, y, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
drow[x] = (int16_t)(v0 + v2 + v1l + v1r - 4 * v1);
}
int x = left;
for (; x < right; )
{
size_t vl = __riscv_vsetvl_e8m1(right - x);
vuint8m1_t v0 = r0 ? __riscv_vle8_v_u8m1(r0 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v2 = r2 ? __riscv_vle8_v_u8m1(r2 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v1 = r1 ? __riscv_vle8_v_u8m1(r1 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v1l = r1 ? __riscv_vle8_v_u8m1(r1 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v1r = r1 ? __riscv_vle8_v_u8m1(r1 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vint16m2_t s0 = vw_u8_to_i16(v0, vl);
vint16m2_t s2 = vw_u8_to_i16(v2, vl);
vint16m2_t s1 = vw_u8_to_i16(v1, vl);
vint16m2_t s1l = vw_u8_to_i16(v1l, vl);
vint16m2_t s1r = vw_u8_to_i16(v1r, vl);
vint16m2_t sum = __riscv_vadd_vv_i16m2(s0, s2, vl);
sum = __riscv_vadd_vv_i16m2(sum, s1l, vl);
sum = __riscv_vadd_vv_i16m2(sum, s1r, vl);
sum = __riscv_vsub_vv_i16m2(sum, __riscv_vsll_vx_i16m2(s1, 2, vl), vl);
__riscv_vse16_v_i16m2(drow + x, sum, vl);
x += vl;
}
for (; x < width; ++x)
{
int v0 = sample_u8(src_data, src_step, width, height, y - 1, x, border_type, border_value);
int v2 = sample_u8(src_data, src_step, width, height, y + 1, x, border_type, border_value);
int v1l = sample_u8(src_data, src_step, width, height, y, x - 1, border_type, border_value);
int v1r = sample_u8(src_data, src_step, width, height, y, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
drow[x] = (int16_t)(v0 + v2 + v1l + v1r - 4 * v1);
}
}
return CV_HAL_ERROR_OK;
}
static int laplacian3(int start, int end,
const uint8_t* src_data, size_t src_step,
int16_t* dst_data, size_t dst_step,
int width, int height,
int border_type, uint8_t border_value)
{
if (!isLaplacianOpenCVSupported(width, height, border_type))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
for (int y = start; y < end; ++y)
{
int y0 = borderMap(y - 1, height, border_type);
int y1 = borderMap(y , height, border_type);
int y2 = borderMap(y + 1, height, border_type);
const uint8_t* r0 = (y0 < 0) ? nullptr : src_data + y0 * src_step;
const uint8_t* r1 = (y1 < 0) ? nullptr : src_data + y1 * src_step;
const uint8_t* r2 = (y2 < 0) ? nullptr : src_data + y2 * src_step;
int16_t* drow = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(dst_data) + y * dst_step);
int left = 1;
int right = width - 1;
for (int x = 0; x < left; ++x)
{
int v0l = sample_u8(src_data, src_step, width, height, y - 1, x - 1, border_type, border_value);
int v0r = sample_u8(src_data, src_step, width, height, y - 1, x + 1, border_type, border_value);
int v2l = sample_u8(src_data, src_step, width, height, y + 1, x - 1, border_type, border_value);
int v2r = sample_u8(src_data, src_step, width, height, y + 1, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
int res = (v0l + v0r + v2l + v2r - 4 * v1) * 2;
drow[x] = (int16_t)res;
}
int x = left;
for (; x < right; )
{
size_t vl = __riscv_vsetvl_e8m1(right - x);
vuint8m1_t v0l = r0 ? __riscv_vle8_v_u8m1(r0 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v0r = r0 ? __riscv_vle8_v_u8m1(r0 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v2l = r2 ? __riscv_vle8_v_u8m1(r2 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v2r = r2 ? __riscv_vle8_v_u8m1(r2 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t v1 = r1 ? __riscv_vle8_v_u8m1(r1 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vint16m2_t s0l = vw_u8_to_i16(v0l, vl);
vint16m2_t s0r = vw_u8_to_i16(v0r, vl);
vint16m2_t s2l = vw_u8_to_i16(v2l, vl);
vint16m2_t s2r = vw_u8_to_i16(v2r, vl);
vint16m2_t s1 = vw_u8_to_i16(v1, vl);
vint16m2_t sum = __riscv_vadd_vv_i16m2(s0l, s0r, vl);
sum = __riscv_vadd_vv_i16m2(sum, s2l, vl);
sum = __riscv_vadd_vv_i16m2(sum, s2r, vl);
sum = __riscv_vsub_vv_i16m2(sum, __riscv_vsll_vx_i16m2(s1, 2, vl), vl);
sum = __riscv_vsll_vx_i16m2(sum, 1, vl);
__riscv_vse16_v_i16m2(drow + x, sum, vl);
x += vl;
}
for (; x < width; ++x)
{
int v0l = sample_u8(src_data, src_step, width, height, y - 1, x - 1, border_type, border_value);
int v0r = sample_u8(src_data, src_step, width, height, y - 1, x + 1, border_type, border_value);
int v2l = sample_u8(src_data, src_step, width, height, y + 1, x - 1, border_type, border_value);
int v2r = sample_u8(src_data, src_step, width, height, y + 1, x + 1, border_type, border_value);
int v1 = sample_u8(src_data, src_step, width, height, y, x, border_type, border_value);
int res = (v0l + v0r + v2l + v2r - 4 * v1) * 2;
drow[x] = (int16_t)res;
}
}
return CV_HAL_ERROR_OK;
}
static int laplacian5(int start, int end,
const uint8_t* src_data, size_t src_step,
int16_t* dst_data, size_t dst_step,
int width, int height,
int border_type, uint8_t border_value)
{
if (!isLaplacianOpenCVSupported(width, height, border_type))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
for (int y = start; y < end; ++y)
{
int y0 = borderMap(y - 2, height, border_type);
int y1 = borderMap(y - 1, height, border_type);
int y2 = borderMap(y , height, border_type);
int y3 = borderMap(y + 1, height, border_type);
int y4 = borderMap(y + 2, height, border_type);
const uint8_t* r0 = (y0 < 0) ? nullptr : src_data + y0 * src_step;
const uint8_t* r1 = (y1 < 0) ? nullptr : src_data + y1 * src_step;
const uint8_t* r2 = (y2 < 0) ? nullptr : src_data + y2 * src_step;
const uint8_t* r3 = (y3 < 0) ? nullptr : src_data + y3 * src_step;
const uint8_t* r4 = (y4 < 0) ? nullptr : src_data + y4 * src_step;
int16_t* drow = reinterpret_cast<int16_t*>(reinterpret_cast<uint8_t*>(dst_data) + y * dst_step);
int left = 2;
int right = width - 2;
for (int x = 0; x < left; ++x)
{
auto v = [&](int yy, int xx){ return sample_u8(src_data, src_step, width, height, yy, xx, border_type, border_value); };
int pprevx = v(y-2,x-2) + 2*v(y-1,x-2) + 2*v(y,x-2) + 2*v(y+1,x-2) + v(y+2,x-2);
int prevx = 2*v(y-2,x-1) - 4*v(y,x-1) + 2*v(y+2,x-1);
int currx = 2*v(y-2,x) - 4*v(y-1,x) - 12*v(y,x) - 4*v(y+1,x) + 2*v(y+2,x);
int nextx = 2*v(y-2,x+1) - 4*v(y,x+1) + 2*v(y+2,x+1);
int nnextx = v(y-2,x+2) + 2*v(y-1,x+2) + 2*v(y,x+2) + 2*v(y+1,x+2) + v(y+2,x+2);
int res = (pprevx + prevx + currx + nextx + nnextx) * 2;
drow[x] = (int16_t)res;
}
int x = left;
for (; x < right; )
{
size_t vl = __riscv_vsetvl_e8m1(right - x);
vuint8m1_t r0m2 = r0 ? __riscv_vle8_v_u8m1(r0 + x - 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r0m1 = r0 ? __riscv_vle8_v_u8m1(r0 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r0p0 = r0 ? __riscv_vle8_v_u8m1(r0 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r0p1 = r0 ? __riscv_vle8_v_u8m1(r0 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r0p2 = r0 ? __riscv_vle8_v_u8m1(r0 + x + 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r1m2 = r1 ? __riscv_vle8_v_u8m1(r1 + x - 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r1p0 = r1 ? __riscv_vle8_v_u8m1(r1 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r1p2 = r1 ? __riscv_vle8_v_u8m1(r1 + x + 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r2m2 = r2 ? __riscv_vle8_v_u8m1(r2 + x - 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r2m1 = r2 ? __riscv_vle8_v_u8m1(r2 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r2p0 = r2 ? __riscv_vle8_v_u8m1(r2 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r2p1 = r2 ? __riscv_vle8_v_u8m1(r2 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r2p2 = r2 ? __riscv_vle8_v_u8m1(r2 + x + 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r3m2 = r3 ? __riscv_vle8_v_u8m1(r3 + x - 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r3p0 = r3 ? __riscv_vle8_v_u8m1(r3 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r3p2 = r3 ? __riscv_vle8_v_u8m1(r3 + x + 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r4m2 = r4 ? __riscv_vle8_v_u8m1(r4 + x - 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r4m1 = r4 ? __riscv_vle8_v_u8m1(r4 + x - 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r4p0 = r4 ? __riscv_vle8_v_u8m1(r4 + x, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r4p1 = r4 ? __riscv_vle8_v_u8m1(r4 + x + 1, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
vuint8m1_t r4p2 = r4 ? __riscv_vle8_v_u8m1(r4 + x + 2, vl) : __riscv_vmv_v_x_u8m1(border_value, vl);
auto I = [&](vuint8m1_t v){ return vw_u8_to_i16(v, vl); };
vint16m2_t pprevx = I(r0m2);
pprevx = __riscv_vadd_vv_i16m2(pprevx, __riscv_vsll_vx_i16m2(I(r1m2),1,vl), vl);
pprevx = __riscv_vadd_vv_i16m2(pprevx, __riscv_vsll_vx_i16m2(I(r2m2),1,vl), vl);
pprevx = __riscv_vadd_vv_i16m2(pprevx, __riscv_vsll_vx_i16m2(I(r3m2),1,vl), vl);
pprevx = __riscv_vadd_vv_i16m2(pprevx, I(r4m2), vl);
vint16m2_t prevx = __riscv_vsll_vx_i16m2(I(r0m1),1,vl);
prevx = __riscv_vsub_vv_i16m2(prevx, __riscv_vsll_vx_i16m2(I(r2m1),2,vl), vl);
prevx = __riscv_vadd_vv_i16m2(prevx, __riscv_vsll_vx_i16m2(I(r4m1),1,vl), vl);
vint16m2_t currx = __riscv_vsll_vx_i16m2(I(r0p0),1,vl);
currx = __riscv_vsub_vv_i16m2(currx, __riscv_vsll_vx_i16m2(I(r1p0),2,vl), vl);
currx = __riscv_vsub_vv_i16m2(currx, __riscv_vsll_vx_i16m2(I(r2p0),3,vl), vl);
currx = __riscv_vsub_vv_i16m2(currx, __riscv_vsll_vx_i16m2(I(r3p0),2,vl), vl);
currx = __riscv_vadd_vv_i16m2(currx, __riscv_vsll_vx_i16m2(I(r4p0),1,vl), vl);
vint16m2_t nextx = __riscv_vsll_vx_i16m2(I(r0p1),1,vl);
nextx = __riscv_vsub_vv_i16m2(nextx, __riscv_vsll_vx_i16m2(I(r2p1),2,vl), vl);
nextx = __riscv_vadd_vv_i16m2(nextx, __riscv_vsll_vx_i16m2(I(r4p1),1,vl), vl);
vint16m2_t nnextx = I(r0p2);
nnextx = __riscv_vadd_vv_i16m2(nnextx, __riscv_vsll_vx_i16m2(I(r1p2),1,vl), vl);
nnextx = __riscv_vadd_vv_i16m2(nnextx, __riscv_vsll_vx_i16m2(I(r2p2),1,vl), vl);
nnextx = __riscv_vadd_vv_i16m2(nnextx, __riscv_vsll_vx_i16m2(I(r3p2),1,vl), vl);
nnextx = __riscv_vadd_vv_i16m2(nnextx, I(r4p2), vl);
vint16m2_t sum = __riscv_vadd_vv_i16m2(pprevx, prevx, vl);
sum = __riscv_vadd_vv_i16m2(sum, currx, vl);
sum = __riscv_vadd_vv_i16m2(sum, nextx, vl);
sum = __riscv_vadd_vv_i16m2(sum, nnextx, vl);
sum = __riscv_vsll_vx_i16m2(sum, 1, vl);
__riscv_vse16_v_i16m2(drow + x, sum, vl);
x += vl;
}
for (; x < width; ++x)
{
auto v = [&](int yy, int xx){ return sample_u8(src_data, src_step, width, height, yy, xx, border_type, border_value); };
int pprevx = v(y-2,x-2) + 2*v(y-1,x-2) + 2*v(y,x-2) + 2*v(y+1,x-2) + v(y+2,x-2);
int prevx = 2*v(y-2,x-1) - 4*v(y,x-1) + 2*v(y+2,x-1);
int currx = 2*v(y-2,x) - 4*v(y-1,x) - 12*v(y,x) - 4*v(y+1,x) + 2*v(y+2,x);
int nextx = 2*v(y-2,x+1) - 4*v(y,x+1) + 2*v(y+2,x+1);
int nnextx = v(y-2,x+2) + 2*v(y-1,x+2) + 2*v(y,x+2) + 2*v(y+1,x+2) + v(y+2,x+2);
int res = (pprevx + prevx + currx + nextx + nnextx) * 2;
drow[x] = (int16_t)res;
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int laplacian(const uint8_t* src_data, size_t src_step,
uint8_t* dst_data, size_t dst_step,
int width, int height,
int src_depth, int dst_depth, int cn,
int ksize, int border_type, uint8_t border_value)
{
if (src_data == dst_data)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_depth != CV_8U || cn != 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (ksize != 1 && ksize != 3 && ksize != 5)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (dst_depth != CV_8U && dst_depth != CV_16S)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (dst_depth == CV_8U)
{
if (ksize != 3) // only 3x3 path for u8
return CV_HAL_ERROR_NOT_IMPLEMENTED;
return common::invoke(height, {laplacian3x3_u8},
src_data, src_step, dst_data, dst_step,
width, height, border_type, border_value);
}
if (ksize == 1)
{
return common::invoke(height, {laplacian1},
src_data, src_step,
reinterpret_cast<int16_t*>(dst_data), dst_step,
width, height, border_type, border_value);
}
if (ksize == 3)
{
return common::invoke(height, {laplacian3},
src_data, src_step,
reinterpret_cast<int16_t*>(dst_data), dst_step,
width, height, border_type, border_value);
}
if (ksize == 5)
{
return common::invoke(height, {laplacian5},
src_data, src_step,
reinterpret_cast<int16_t*>(dst_data), dst_step,
width, height, border_type, border_value);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+575
View File
@@ -0,0 +1,575 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
// the algorithm is copied from imgproc/src/median_blur.simd.cpp
// in the function template static void medianBlur_SortNet
template<int ksize, typename helper>
static inline int medianBlurC1(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height)
{
using T = typename helper::ElemType;
using VT = typename helper::VecType;
for (int i = start; i < end; i++)
{
const T* row0 = reinterpret_cast<const T*>(src_data + std::min(std::max(i - ksize / 2, 0), height - 1) * src_step);
const T* row1 = reinterpret_cast<const T*>(src_data + std::min(std::max(i + 1 - ksize / 2, 0), height - 1) * src_step);
const T* row2 = reinterpret_cast<const T*>(src_data + std::min(std::max(i + 2 - ksize / 2, 0), height - 1) * src_step);
const T* row3 = reinterpret_cast<const T*>(src_data + std::min(std::max(i + 3 - ksize / 2, 0), height - 1) * src_step);
const T* row4 = reinterpret_cast<const T*>(src_data + std::min(std::max(i + 4 - ksize / 2, 0), height - 1) * src_step);
int vl;
auto vop = [&vl](VT& a, VT& b) {
auto t = a;
a = helper::vmin(a, b, vl);
b = helper::vmax(t, b, vl);
};
for (int j = 0; j < width; j += vl)
{
vl = helper::setvl(width - j);
if (ksize == 3)
{
VT p0, p1, p2;
VT p3, p4, p5;
VT p6, p7, p8;
if (j != 0)
{
p0 = helper::vload(row0 + j - 1, vl);
p3 = helper::vload(row1 + j - 1, vl);
p6 = helper::vload(row2 + j - 1, vl);
}
else
{
p0 = helper::vslide1up(helper::vload(row0, vl), row0[0], vl);
p3 = helper::vslide1up(helper::vload(row1, vl), row1[0], vl);
p6 = helper::vslide1up(helper::vload(row2, vl), row2[0], vl);
}
p1 = helper::vslide1down(p0, row0[j + vl - 1], vl);
p4 = helper::vslide1down(p3, row1[j + vl - 1], vl);
p7 = helper::vslide1down(p6, row2[j + vl - 1], vl);
p2 = helper::vslide1down(p1, row0[std::min(width - 1, j + vl)], vl);
p5 = helper::vslide1down(p4, row1[std::min(width - 1, j + vl)], vl);
p8 = helper::vslide1down(p7, row2[std::min(width - 1, j + vl)], vl);
vop(p1, p2); vop(p4, p5); vop(p7, p8); vop(p0, p1);
vop(p3, p4); vop(p6, p7); vop(p1, p2); vop(p4, p5);
vop(p7, p8); vop(p0, p3); vop(p5, p8); vop(p4, p7);
vop(p3, p6); vop(p1, p4); vop(p2, p5); vop(p4, p7);
vop(p4, p2); vop(p6, p4); vop(p4, p2);
helper::vstore(reinterpret_cast<T*>(dst_data + i * dst_step) + j, p4, vl);
}
else
{
VT p0, p1, p2, p3, p4;
VT p5, p6, p7, p8, p9;
VT p10, p11, p12, p13, p14;
VT p15, p16, p17, p18, p19;
VT p20, p21, p22, p23, p24;
if (j >= 2)
{
p0 = helper::vload(row0 + j - 2, vl);
p5 = helper::vload(row1 + j - 2, vl);
p10 = helper::vload(row2 + j - 2, vl);
p15 = helper::vload(row3 + j - 2, vl);
p20 = helper::vload(row4 + j - 2, vl);
}
else
{
p0 = helper::vslide1up(helper::vload(row0, vl), row0[0], vl);
p5 = helper::vslide1up(helper::vload(row1, vl), row1[0], vl);
p10 = helper::vslide1up(helper::vload(row2, vl), row2[0], vl);
p15 = helper::vslide1up(helper::vload(row3, vl), row3[0], vl);
p20 = helper::vslide1up(helper::vload(row4, vl), row4[0], vl);
if (j == 0)
{
p0 = helper::vslide1up(p0, row0[0], vl);
p5 = helper::vslide1up(p5, row1[0], vl);
p10 = helper::vslide1up(p10, row2[0], vl);
p15 = helper::vslide1up(p15, row3[0], vl);
p20 = helper::vslide1up(p20, row4[0], vl);
}
}
p1 = helper::vslide1down(p0, row0[j + vl - 2], vl);
p6 = helper::vslide1down(p5, row1[j + vl - 2], vl);
p11 = helper::vslide1down(p10, row2[j + vl - 2], vl);
p16 = helper::vslide1down(p15, row3[j + vl - 2], vl);
p21 = helper::vslide1down(p20, row4[j + vl - 2], vl);
p2 = helper::vslide1down(p1, row0[j + vl - 1], vl);
p7 = helper::vslide1down(p6, row1[j + vl - 1], vl);
p12 = helper::vslide1down(p11, row2[j + vl - 1], vl);
p17 = helper::vslide1down(p16, row3[j + vl - 1], vl);
p22 = helper::vslide1down(p21, row4[j + vl - 1], vl);
p3 = helper::vslide1down(p2, row0[std::min(width - 1, j + vl)], vl);
p8 = helper::vslide1down(p7, row1[std::min(width - 1, j + vl)], vl);
p13 = helper::vslide1down(p12, row2[std::min(width - 1, j + vl)], vl);
p18 = helper::vslide1down(p17, row3[std::min(width - 1, j + vl)], vl);
p23 = helper::vslide1down(p22, row4[std::min(width - 1, j + vl)], vl);
p4 = helper::vslide1down(p3, row0[std::min(width - 1, j + vl + 1)], vl);
p9 = helper::vslide1down(p8, row1[std::min(width - 1, j + vl + 1)], vl);
p14 = helper::vslide1down(p13, row2[std::min(width - 1, j + vl + 1)], vl);
p19 = helper::vslide1down(p18, row3[std::min(width - 1, j + vl + 1)], vl);
p24 = helper::vslide1down(p23, row4[std::min(width - 1, j + vl + 1)], vl);
vop(p1, p2); vop(p0, p1); vop(p1, p2); vop(p4, p5); vop(p3, p4);
vop(p4, p5); vop(p0, p3); vop(p2, p5); vop(p2, p3); vop(p1, p4);
vop(p1, p2); vop(p3, p4); vop(p7, p8); vop(p6, p7); vop(p7, p8);
vop(p10, p11); vop(p9, p10); vop(p10, p11); vop(p6, p9); vop(p8, p11);
vop(p8, p9); vop(p7, p10); vop(p7, p8); vop(p9, p10); vop(p0, p6);
vop(p4, p10); vop(p4, p6); vop(p2, p8); vop(p2, p4); vop(p6, p8);
vop(p1, p7); vop(p5, p11); vop(p5, p7); vop(p3, p9); vop(p3, p5);
vop(p7, p9); vop(p1, p2); vop(p3, p4); vop(p5, p6); vop(p7, p8);
vop(p9, p10); vop(p13, p14); vop(p12, p13); vop(p13, p14); vop(p16, p17);
vop(p15, p16); vop(p16, p17); vop(p12, p15); vop(p14, p17); vop(p14, p15);
vop(p13, p16); vop(p13, p14); vop(p15, p16); vop(p19, p20); vop(p18, p19);
vop(p19, p20); vop(p21, p22); vop(p23, p24); vop(p21, p23); vop(p22, p24);
vop(p22, p23); vop(p18, p21); vop(p20, p23); vop(p20, p21); vop(p19, p22);
vop(p22, p24); vop(p19, p20); vop(p21, p22); vop(p23, p24); vop(p12, p18);
vop(p16, p22); vop(p16, p18); vop(p14, p20); vop(p20, p24); vop(p14, p16);
vop(p18, p20); vop(p22, p24); vop(p13, p19); vop(p17, p23); vop(p17, p19);
vop(p15, p21); vop(p15, p17); vop(p19, p21); vop(p13, p14); vop(p15, p16);
vop(p17, p18); vop(p19, p20); vop(p21, p22); vop(p23, p24); vop(p0, p12);
vop(p8, p20); vop(p8, p12); vop(p4, p16); vop(p16, p24); vop(p12, p16);
vop(p2, p14); vop(p10, p22); vop(p10, p14); vop(p6, p18); vop(p6, p10);
vop(p10, p12); vop(p1, p13); vop(p9, p21); vop(p9, p13); vop(p5, p17);
vop(p13, p17); vop(p3, p15); vop(p11, p23); vop(p11, p15); vop(p7, p19);
vop(p7, p11); vop(p11, p13); vop(p11, p12);
helper::vstore(reinterpret_cast<T*>(dst_data + i * dst_step) + j, p12, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
template<int ksize>
static inline int medianBlurC4(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height)
{
for (int i = start; i < end; i++)
{
const uchar* row0 = src_data + std::min(std::max(i - ksize / 2, 0), height - 1) * src_step;
const uchar* row1 = src_data + std::min(std::max(i + 1 - ksize / 2, 0), height - 1) * src_step;
const uchar* row2 = src_data + std::min(std::max(i + 2 - ksize / 2, 0), height - 1) * src_step;
const uchar* row3 = src_data + std::min(std::max(i + 3 - ksize / 2, 0), height - 1) * src_step;
const uchar* row4 = src_data + std::min(std::max(i + 4 - ksize / 2, 0), height - 1) * src_step;
int vl;
for (int j = 0; j < width; j += vl)
{
if (ksize == 3)
{
vl = __riscv_vsetvl_e8m1(width - j);
vuint8m1_t p00, p01, p02;
vuint8m1_t p03, p04, p05;
vuint8m1_t p06, p07, p08;
vuint8m1_t p10, p11, p12;
vuint8m1_t p13, p14, p15;
vuint8m1_t p16, p17, p18;
vuint8m1_t p20, p21, p22;
vuint8m1_t p23, p24, p25;
vuint8m1_t p26, p27, p28;
vuint8m1_t p30, p31, p32;
vuint8m1_t p33, p34, p35;
vuint8m1_t p36, p37, p38;
auto loadsrc = [&vl](const uchar* row, vuint8m1_t& p0, vuint8m1_t& p1, vuint8m1_t& p2, vuint8m1_t& p3) {
auto src = __riscv_vlseg4e8_v_u8m1x4(row, vl);
p0 = __riscv_vget_v_u8m1x4_u8m1(src, 0);
p1 = __riscv_vget_v_u8m1x4_u8m1(src, 1);
p2 = __riscv_vget_v_u8m1x4_u8m1(src, 2);
p3 = __riscv_vget_v_u8m1x4_u8m1(src, 3);
};
if (j != 0)
{
loadsrc(row0 + (j - 1) * 4, p00, p10, p20, p30);
loadsrc(row1 + (j - 1) * 4, p03, p13, p23, p33);
loadsrc(row2 + (j - 1) * 4, p06, p16, p26, p36);
}
else
{
loadsrc(row0, p00, p10, p20, p30);
loadsrc(row1, p03, p13, p23, p33);
loadsrc(row2, p06, p16, p26, p36);
p00 = __riscv_vslide1up(p00, row0[0], vl);
p10 = __riscv_vslide1up(p10, row0[1], vl);
p20 = __riscv_vslide1up(p20, row0[2], vl);
p30 = __riscv_vslide1up(p30, row0[3], vl);
p03 = __riscv_vslide1up(p03, row1[0], vl);
p13 = __riscv_vslide1up(p13, row1[1], vl);
p23 = __riscv_vslide1up(p23, row1[2], vl);
p33 = __riscv_vslide1up(p33, row1[3], vl);
p06 = __riscv_vslide1up(p06, row2[0], vl);
p16 = __riscv_vslide1up(p16, row2[1], vl);
p26 = __riscv_vslide1up(p26, row2[2], vl);
p36 = __riscv_vslide1up(p36, row2[3], vl);
}
p01 = __riscv_vslide1down(p00, row0[(j + vl - 1) * 4 ], vl);
p11 = __riscv_vslide1down(p10, row0[(j + vl - 1) * 4 + 1], vl);
p21 = __riscv_vslide1down(p20, row0[(j + vl - 1) * 4 + 2], vl);
p31 = __riscv_vslide1down(p30, row0[(j + vl - 1) * 4 + 3], vl);
p04 = __riscv_vslide1down(p03, row1[(j + vl - 1) * 4 ], vl);
p14 = __riscv_vslide1down(p13, row1[(j + vl - 1) * 4 + 1], vl);
p24 = __riscv_vslide1down(p23, row1[(j + vl - 1) * 4 + 2], vl);
p34 = __riscv_vslide1down(p33, row1[(j + vl - 1) * 4 + 3], vl);
p07 = __riscv_vslide1down(p06, row2[(j + vl - 1) * 4 ], vl);
p17 = __riscv_vslide1down(p16, row2[(j + vl - 1) * 4 + 1], vl);
p27 = __riscv_vslide1down(p26, row2[(j + vl - 1) * 4 + 2], vl);
p37 = __riscv_vslide1down(p36, row2[(j + vl - 1) * 4 + 3], vl);
p02 = __riscv_vslide1down(p01, row0[std::min(width - 1, j + vl) * 4 ], vl);
p12 = __riscv_vslide1down(p11, row0[std::min(width - 1, j + vl) * 4 + 1], vl);
p22 = __riscv_vslide1down(p21, row0[std::min(width - 1, j + vl) * 4 + 2], vl);
p32 = __riscv_vslide1down(p31, row0[std::min(width - 1, j + vl) * 4 + 3], vl);
p05 = __riscv_vslide1down(p04, row1[std::min(width - 1, j + vl) * 4 ], vl);
p15 = __riscv_vslide1down(p14, row1[std::min(width - 1, j + vl) * 4 + 1], vl);
p25 = __riscv_vslide1down(p24, row1[std::min(width - 1, j + vl) * 4 + 2], vl);
p35 = __riscv_vslide1down(p34, row1[std::min(width - 1, j + vl) * 4 + 3], vl);
p08 = __riscv_vslide1down(p07, row2[std::min(width - 1, j + vl) * 4 ], vl);
p18 = __riscv_vslide1down(p17, row2[std::min(width - 1, j + vl) * 4 + 1], vl);
p28 = __riscv_vslide1down(p27, row2[std::min(width - 1, j + vl) * 4 + 2], vl);
p38 = __riscv_vslide1down(p37, row2[std::min(width - 1, j + vl) * 4 + 3], vl);
auto vop = [&vl](vuint8m1_t& a, vuint8m1_t& b) {
auto t = a;
a = __riscv_vminu(a, b, vl);
b = __riscv_vmaxu(t, b, vl);
};
vuint8m1x4_t dst{};
vop(p01, p02); vop(p04, p05); vop(p07, p08); vop(p00, p01);
vop(p03, p04); vop(p06, p07); vop(p01, p02); vop(p04, p05);
vop(p07, p08); vop(p00, p03); vop(p05, p08); vop(p04, p07);
vop(p03, p06); vop(p01, p04); vop(p02, p05); vop(p04, p07);
vop(p04, p02); vop(p06, p04); vop(p04, p02);
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 0, p04);
vop(p11, p12); vop(p14, p15); vop(p17, p18); vop(p10, p11);
vop(p13, p14); vop(p16, p17); vop(p11, p12); vop(p14, p15);
vop(p17, p18); vop(p10, p13); vop(p15, p18); vop(p14, p17);
vop(p13, p16); vop(p11, p14); vop(p12, p15); vop(p14, p17);
vop(p14, p12); vop(p16, p14); vop(p14, p12);
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 1, p14);
vop(p21, p22); vop(p24, p25); vop(p27, p28); vop(p20, p21);
vop(p23, p24); vop(p26, p27); vop(p21, p22); vop(p24, p25);
vop(p27, p28); vop(p20, p23); vop(p25, p28); vop(p24, p27);
vop(p23, p26); vop(p21, p24); vop(p22, p25); vop(p24, p27);
vop(p24, p22); vop(p26, p24); vop(p24, p22);
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 2, p24);
vop(p31, p32); vop(p34, p35); vop(p37, p38); vop(p30, p31);
vop(p33, p34); vop(p36, p37); vop(p31, p32); vop(p34, p35);
vop(p37, p38); vop(p30, p33); vop(p35, p38); vop(p34, p37);
vop(p33, p36); vop(p31, p34); vop(p32, p35); vop(p34, p37);
vop(p34, p32); vop(p36, p34); vop(p34, p32);
dst = __riscv_vset_v_u8m1_u8m1x4(dst, 3, p34);
__riscv_vsseg4e8(dst_data + i * dst_step + j * 4, dst, vl);
}
else
{
vl = __riscv_vsetvl_e8m2(width - j);
vuint8m2_t p00, p01, p02, p03, p04;
vuint8m2_t p05, p06, p07, p08, p09;
vuint8m2_t p010, p011, p012, p013, p014;
vuint8m2_t p015, p016, p017, p018, p019;
vuint8m2_t p020, p021, p022, p023, p024;
vuint8m2_t p10, p11, p12, p13, p14;
vuint8m2_t p15, p16, p17, p18, p19;
vuint8m2_t p110, p111, p112, p113, p114;
vuint8m2_t p115, p116, p117, p118, p119;
vuint8m2_t p120, p121, p122, p123, p124;
vuint8m2_t p20, p21, p22, p23, p24;
vuint8m2_t p25, p26, p27, p28, p29;
vuint8m2_t p210, p211, p212, p213, p214;
vuint8m2_t p215, p216, p217, p218, p219;
vuint8m2_t p220, p221, p222, p223, p224;
vuint8m2_t p30, p31, p32, p33, p34;
vuint8m2_t p35, p36, p37, p38, p39;
vuint8m2_t p310, p311, p312, p313, p314;
vuint8m2_t p315, p316, p317, p318, p319;
vuint8m2_t p320, p321, p322, p323, p324;
auto loadsrc = [&vl](const uchar* row, vuint8m2_t& p0, vuint8m2_t& p1, vuint8m2_t& p2, vuint8m2_t& p3) {
auto src = __riscv_vlseg4e8_v_u8m2x4(row, vl);
p0 = __riscv_vget_v_u8m2x4_u8m2(src, 0);
p1 = __riscv_vget_v_u8m2x4_u8m2(src, 1);
p2 = __riscv_vget_v_u8m2x4_u8m2(src, 2);
p3 = __riscv_vget_v_u8m2x4_u8m2(src, 3);
};
if (j >= 2)
{
loadsrc(row0 + (j - 2) * 4, p00, p10, p20, p30);
loadsrc(row1 + (j - 2) * 4, p05, p15, p25, p35);
loadsrc(row2 + (j - 2) * 4, p010, p110, p210, p310);
loadsrc(row3 + (j - 2) * 4, p015, p115, p215, p315);
loadsrc(row4 + (j - 2) * 4, p020, p120, p220, p320);
}
else
{
loadsrc(row0, p00, p10, p20, p30);
loadsrc(row1, p05, p15, p25, p35);
loadsrc(row2, p010, p110, p210, p310);
loadsrc(row3, p015, p115, p215, p315);
loadsrc(row4, p020, p120, p220, p320);
auto slideup = [&] {
p00 = __riscv_vslide1up(p00, row0[0], vl);
p10 = __riscv_vslide1up(p10, row0[1], vl);
p20 = __riscv_vslide1up(p20, row0[2], vl);
p30 = __riscv_vslide1up(p30, row0[3], vl);
p05 = __riscv_vslide1up(p05, row1[0], vl);
p15 = __riscv_vslide1up(p15, row1[1], vl);
p25 = __riscv_vslide1up(p25, row1[2], vl);
p35 = __riscv_vslide1up(p35, row1[3], vl);
p010 = __riscv_vslide1up(p010, row2[0], vl);
p110 = __riscv_vslide1up(p110, row2[1], vl);
p210 = __riscv_vslide1up(p210, row2[2], vl);
p310 = __riscv_vslide1up(p310, row2[3], vl);
p015 = __riscv_vslide1up(p015, row3[0], vl);
p115 = __riscv_vslide1up(p115, row3[1], vl);
p215 = __riscv_vslide1up(p215, row3[2], vl);
p315 = __riscv_vslide1up(p315, row3[3], vl);
p020 = __riscv_vslide1up(p020, row4[0], vl);
p120 = __riscv_vslide1up(p120, row4[1], vl);
p220 = __riscv_vslide1up(p220, row4[2], vl);
p320 = __riscv_vslide1up(p320, row4[3], vl);
};
slideup();
if (j == 0)
{
slideup();
}
}
p01 = __riscv_vslide1down(p00, row0[(j + vl - 2) * 4 ], vl);
p11 = __riscv_vslide1down(p10, row0[(j + vl - 2) * 4 + 1], vl);
p21 = __riscv_vslide1down(p20, row0[(j + vl - 2) * 4 + 2], vl);
p31 = __riscv_vslide1down(p30, row0[(j + vl - 2) * 4 + 3], vl);
p06 = __riscv_vslide1down(p05, row1[(j + vl - 2) * 4 ], vl);
p16 = __riscv_vslide1down(p15, row1[(j + vl - 2) * 4 + 1], vl);
p26 = __riscv_vslide1down(p25, row1[(j + vl - 2) * 4 + 2], vl);
p36 = __riscv_vslide1down(p35, row1[(j + vl - 2) * 4 + 3], vl);
p011 = __riscv_vslide1down(p010, row2[(j + vl - 2) * 4 ], vl);
p111 = __riscv_vslide1down(p110, row2[(j + vl - 2) * 4 + 1], vl);
p211 = __riscv_vslide1down(p210, row2[(j + vl - 2) * 4 + 2], vl);
p311 = __riscv_vslide1down(p310, row2[(j + vl - 2) * 4 + 3], vl);
p016 = __riscv_vslide1down(p015, row3[(j + vl - 2) * 4 ], vl);
p116 = __riscv_vslide1down(p115, row3[(j + vl - 2) * 4 + 1], vl);
p216 = __riscv_vslide1down(p215, row3[(j + vl - 2) * 4 + 2], vl);
p316 = __riscv_vslide1down(p315, row3[(j + vl - 2) * 4 + 3], vl);
p021 = __riscv_vslide1down(p020, row4[(j + vl - 2) * 4 ], vl);
p121 = __riscv_vslide1down(p120, row4[(j + vl - 2) * 4 + 1], vl);
p221 = __riscv_vslide1down(p220, row4[(j + vl - 2) * 4 + 2], vl);
p321 = __riscv_vslide1down(p320, row4[(j + vl - 2) * 4 + 3], vl);
p02 = __riscv_vslide1down(p01, row0[(j + vl - 1) * 4 ], vl);
p12 = __riscv_vslide1down(p11, row0[(j + vl - 1) * 4 + 1], vl);
p22 = __riscv_vslide1down(p21, row0[(j + vl - 1) * 4 + 2], vl);
p32 = __riscv_vslide1down(p31, row0[(j + vl - 1) * 4 + 3], vl);
p07 = __riscv_vslide1down(p06, row1[(j + vl - 1) * 4 ], vl);
p17 = __riscv_vslide1down(p16, row1[(j + vl - 1) * 4 + 1], vl);
p27 = __riscv_vslide1down(p26, row1[(j + vl - 1) * 4 + 2], vl);
p37 = __riscv_vslide1down(p36, row1[(j + vl - 1) * 4 + 3], vl);
p012 = __riscv_vslide1down(p011, row2[(j + vl - 1) * 4 ], vl);
p112 = __riscv_vslide1down(p111, row2[(j + vl - 1) * 4 + 1], vl);
p212 = __riscv_vslide1down(p211, row2[(j + vl - 1) * 4 + 2], vl);
p312 = __riscv_vslide1down(p311, row2[(j + vl - 1) * 4 + 3], vl);
p017 = __riscv_vslide1down(p016, row3[(j + vl - 1) * 4 ], vl);
p117 = __riscv_vslide1down(p116, row3[(j + vl - 1) * 4 + 1], vl);
p217 = __riscv_vslide1down(p216, row3[(j + vl - 1) * 4 + 2], vl);
p317 = __riscv_vslide1down(p316, row3[(j + vl - 1) * 4 + 3], vl);
p022 = __riscv_vslide1down(p021, row4[(j + vl - 1) * 4 ], vl);
p122 = __riscv_vslide1down(p121, row4[(j + vl - 1) * 4 + 1], vl);
p222 = __riscv_vslide1down(p221, row4[(j + vl - 1) * 4 + 2], vl);
p322 = __riscv_vslide1down(p321, row4[(j + vl - 1) * 4 + 3], vl);
p03 = __riscv_vslide1down(p02, row0[std::min(width - 1, j + vl) * 4 ], vl);
p13 = __riscv_vslide1down(p12, row0[std::min(width - 1, j + vl) * 4 + 1], vl);
p23 = __riscv_vslide1down(p22, row0[std::min(width - 1, j + vl) * 4 + 2], vl);
p33 = __riscv_vslide1down(p32, row0[std::min(width - 1, j + vl) * 4 + 3], vl);
p08 = __riscv_vslide1down(p07, row1[std::min(width - 1, j + vl) * 4 ], vl);
p18 = __riscv_vslide1down(p17, row1[std::min(width - 1, j + vl) * 4 + 1], vl);
p28 = __riscv_vslide1down(p27, row1[std::min(width - 1, j + vl) * 4 + 2], vl);
p38 = __riscv_vslide1down(p37, row1[std::min(width - 1, j + vl) * 4 + 3], vl);
p013 = __riscv_vslide1down(p012, row2[std::min(width - 1, j + vl) * 4 ], vl);
p113 = __riscv_vslide1down(p112, row2[std::min(width - 1, j + vl) * 4 + 1], vl);
p213 = __riscv_vslide1down(p212, row2[std::min(width - 1, j + vl) * 4 + 2], vl);
p313 = __riscv_vslide1down(p312, row2[std::min(width - 1, j + vl) * 4 + 3], vl);
p018 = __riscv_vslide1down(p017, row3[std::min(width - 1, j + vl) * 4 ], vl);
p118 = __riscv_vslide1down(p117, row3[std::min(width - 1, j + vl) * 4 + 1], vl);
p218 = __riscv_vslide1down(p217, row3[std::min(width - 1, j + vl) * 4 + 2], vl);
p318 = __riscv_vslide1down(p317, row3[std::min(width - 1, j + vl) * 4 + 3], vl);
p023 = __riscv_vslide1down(p022, row4[std::min(width - 1, j + vl) * 4 ], vl);
p123 = __riscv_vslide1down(p122, row4[std::min(width - 1, j + vl) * 4 + 1], vl);
p223 = __riscv_vslide1down(p222, row4[std::min(width - 1, j + vl) * 4 + 2], vl);
p323 = __riscv_vslide1down(p322, row4[std::min(width - 1, j + vl) * 4 + 3], vl);
p04 = __riscv_vslide1down(p03, row0[std::min(width - 1, j + vl + 1) * 4 ], vl);
p14 = __riscv_vslide1down(p13, row0[std::min(width - 1, j + vl + 1) * 4 + 1], vl);
p24 = __riscv_vslide1down(p23, row0[std::min(width - 1, j + vl + 1) * 4 + 2], vl);
p34 = __riscv_vslide1down(p33, row0[std::min(width - 1, j + vl + 1) * 4 + 3], vl);
p09 = __riscv_vslide1down(p08, row1[std::min(width - 1, j + vl + 1) * 4 ], vl);
p19 = __riscv_vslide1down(p18, row1[std::min(width - 1, j + vl + 1) * 4 + 1], vl);
p29 = __riscv_vslide1down(p28, row1[std::min(width - 1, j + vl + 1) * 4 + 2], vl);
p39 = __riscv_vslide1down(p38, row1[std::min(width - 1, j + vl + 1) * 4 + 3], vl);
p014 = __riscv_vslide1down(p013, row2[std::min(width - 1, j + vl + 1) * 4 ], vl);
p114 = __riscv_vslide1down(p113, row2[std::min(width - 1, j + vl + 1) * 4 + 1], vl);
p214 = __riscv_vslide1down(p213, row2[std::min(width - 1, j + vl + 1) * 4 + 2], vl);
p314 = __riscv_vslide1down(p313, row2[std::min(width - 1, j + vl + 1) * 4 + 3], vl);
p019 = __riscv_vslide1down(p018, row3[std::min(width - 1, j + vl + 1) * 4 ], vl);
p119 = __riscv_vslide1down(p118, row3[std::min(width - 1, j + vl + 1) * 4 + 1], vl);
p219 = __riscv_vslide1down(p218, row3[std::min(width - 1, j + vl + 1) * 4 + 2], vl);
p319 = __riscv_vslide1down(p318, row3[std::min(width - 1, j + vl + 1) * 4 + 3], vl);
p024 = __riscv_vslide1down(p023, row4[std::min(width - 1, j + vl + 1) * 4 ], vl);
p124 = __riscv_vslide1down(p123, row4[std::min(width - 1, j + vl + 1) * 4 + 1], vl);
p224 = __riscv_vslide1down(p223, row4[std::min(width - 1, j + vl + 1) * 4 + 2], vl);
p324 = __riscv_vslide1down(p323, row4[std::min(width - 1, j + vl + 1) * 4 + 3], vl);
auto vop = [&vl](vuint8m2_t& a, vuint8m2_t& b) {
auto t = a;
a = __riscv_vminu(a, b, vl);
b = __riscv_vmaxu(t, b, vl);
};
vuint8m2x4_t dst{};
vop(p01, p02); vop(p00, p01); vop(p01, p02); vop(p04, p05); vop(p03, p04);
vop(p04, p05); vop(p00, p03); vop(p02, p05); vop(p02, p03); vop(p01, p04);
vop(p01, p02); vop(p03, p04); vop(p07, p08); vop(p06, p07); vop(p07, p08);
vop(p010, p011); vop(p09, p010); vop(p010, p011); vop(p06, p09); vop(p08, p011);
vop(p08, p09); vop(p07, p010); vop(p07, p08); vop(p09, p010); vop(p00, p06);
vop(p04, p010); vop(p04, p06); vop(p02, p08); vop(p02, p04); vop(p06, p08);
vop(p01, p07); vop(p05, p011); vop(p05, p07); vop(p03, p09); vop(p03, p05);
vop(p07, p09); vop(p01, p02); vop(p03, p04); vop(p05, p06); vop(p07, p08);
vop(p09, p010); vop(p013, p014); vop(p012, p013); vop(p013, p014); vop(p016, p017);
vop(p015, p016); vop(p016, p017); vop(p012, p015); vop(p014, p017); vop(p014, p015);
vop(p013, p016); vop(p013, p014); vop(p015, p016); vop(p019, p020); vop(p018, p019);
vop(p019, p020); vop(p021, p022); vop(p023, p024); vop(p021, p023); vop(p022, p024);
vop(p022, p023); vop(p018, p021); vop(p020, p023); vop(p020, p021); vop(p019, p022);
vop(p022, p024); vop(p019, p020); vop(p021, p022); vop(p023, p024); vop(p012, p018);
vop(p016, p022); vop(p016, p018); vop(p014, p020); vop(p020, p024); vop(p014, p016);
vop(p018, p020); vop(p022, p024); vop(p013, p019); vop(p017, p023); vop(p017, p019);
vop(p015, p021); vop(p015, p017); vop(p019, p021); vop(p013, p014); vop(p015, p016);
vop(p017, p018); vop(p019, p020); vop(p021, p022); vop(p023, p024); vop(p00, p012);
vop(p08, p020); vop(p08, p012); vop(p04, p016); vop(p016, p024); vop(p012, p016);
vop(p02, p014); vop(p010, p022); vop(p010, p014); vop(p06, p018); vop(p06, p010);
vop(p010, p012); vop(p01, p013); vop(p09, p021); vop(p09, p013); vop(p05, p017);
vop(p013, p017); vop(p03, p015); vop(p011, p023); vop(p011, p015); vop(p07, p019);
vop(p07, p011); vop(p011, p013); vop(p011, p012);
dst = __riscv_vset_v_u8m2_u8m2x4(dst, 0, p012);
vop(p11, p12); vop(p10, p11); vop(p11, p12); vop(p14, p15); vop(p13, p14);
vop(p14, p15); vop(p10, p13); vop(p12, p15); vop(p12, p13); vop(p11, p14);
vop(p11, p12); vop(p13, p14); vop(p17, p18); vop(p16, p17); vop(p17, p18);
vop(p110, p111); vop(p19, p110); vop(p110, p111); vop(p16, p19); vop(p18, p111);
vop(p18, p19); vop(p17, p110); vop(p17, p18); vop(p19, p110); vop(p10, p16);
vop(p14, p110); vop(p14, p16); vop(p12, p18); vop(p12, p14); vop(p16, p18);
vop(p11, p17); vop(p15, p111); vop(p15, p17); vop(p13, p19); vop(p13, p15);
vop(p17, p19); vop(p11, p12); vop(p13, p14); vop(p15, p16); vop(p17, p18);
vop(p19, p110); vop(p113, p114); vop(p112, p113); vop(p113, p114); vop(p116, p117);
vop(p115, p116); vop(p116, p117); vop(p112, p115); vop(p114, p117); vop(p114, p115);
vop(p113, p116); vop(p113, p114); vop(p115, p116); vop(p119, p120); vop(p118, p119);
vop(p119, p120); vop(p121, p122); vop(p123, p124); vop(p121, p123); vop(p122, p124);
vop(p122, p123); vop(p118, p121); vop(p120, p123); vop(p120, p121); vop(p119, p122);
vop(p122, p124); vop(p119, p120); vop(p121, p122); vop(p123, p124); vop(p112, p118);
vop(p116, p122); vop(p116, p118); vop(p114, p120); vop(p120, p124); vop(p114, p116);
vop(p118, p120); vop(p122, p124); vop(p113, p119); vop(p117, p123); vop(p117, p119);
vop(p115, p121); vop(p115, p117); vop(p119, p121); vop(p113, p114); vop(p115, p116);
vop(p117, p118); vop(p119, p120); vop(p121, p122); vop(p123, p124); vop(p10, p112);
vop(p18, p120); vop(p18, p112); vop(p14, p116); vop(p116, p124); vop(p112, p116);
vop(p12, p114); vop(p110, p122); vop(p110, p114); vop(p16, p118); vop(p16, p110);
vop(p110, p112); vop(p11, p113); vop(p19, p121); vop(p19, p113); vop(p15, p117);
vop(p113, p117); vop(p13, p115); vop(p111, p123); vop(p111, p115); vop(p17, p119);
vop(p17, p111); vop(p111, p113); vop(p111, p112);
dst = __riscv_vset_v_u8m2_u8m2x4(dst, 1, p112);
vop(p21, p22); vop(p20, p21); vop(p21, p22); vop(p24, p25); vop(p23, p24);
vop(p24, p25); vop(p20, p23); vop(p22, p25); vop(p22, p23); vop(p21, p24);
vop(p21, p22); vop(p23, p24); vop(p27, p28); vop(p26, p27); vop(p27, p28);
vop(p210, p211); vop(p29, p210); vop(p210, p211); vop(p26, p29); vop(p28, p211);
vop(p28, p29); vop(p27, p210); vop(p27, p28); vop(p29, p210); vop(p20, p26);
vop(p24, p210); vop(p24, p26); vop(p22, p28); vop(p22, p24); vop(p26, p28);
vop(p21, p27); vop(p25, p211); vop(p25, p27); vop(p23, p29); vop(p23, p25);
vop(p27, p29); vop(p21, p22); vop(p23, p24); vop(p25, p26); vop(p27, p28);
vop(p29, p210); vop(p213, p214); vop(p212, p213); vop(p213, p214); vop(p216, p217);
vop(p215, p216); vop(p216, p217); vop(p212, p215); vop(p214, p217); vop(p214, p215);
vop(p213, p216); vop(p213, p214); vop(p215, p216); vop(p219, p220); vop(p218, p219);
vop(p219, p220); vop(p221, p222); vop(p223, p224); vop(p221, p223); vop(p222, p224);
vop(p222, p223); vop(p218, p221); vop(p220, p223); vop(p220, p221); vop(p219, p222);
vop(p222, p224); vop(p219, p220); vop(p221, p222); vop(p223, p224); vop(p212, p218);
vop(p216, p222); vop(p216, p218); vop(p214, p220); vop(p220, p224); vop(p214, p216);
vop(p218, p220); vop(p222, p224); vop(p213, p219); vop(p217, p223); vop(p217, p219);
vop(p215, p221); vop(p215, p217); vop(p219, p221); vop(p213, p214); vop(p215, p216);
vop(p217, p218); vop(p219, p220); vop(p221, p222); vop(p223, p224); vop(p20, p212);
vop(p28, p220); vop(p28, p212); vop(p24, p216); vop(p216, p224); vop(p212, p216);
vop(p22, p214); vop(p210, p222); vop(p210, p214); vop(p26, p218); vop(p26, p210);
vop(p210, p212); vop(p21, p213); vop(p29, p221); vop(p29, p213); vop(p25, p217);
vop(p213, p217); vop(p23, p215); vop(p211, p223); vop(p211, p215); vop(p27, p219);
vop(p27, p211); vop(p211, p213); vop(p211, p212);
dst = __riscv_vset_v_u8m2_u8m2x4(dst, 2, p212);
vop(p31, p32); vop(p30, p31); vop(p31, p32); vop(p34, p35); vop(p33, p34);
vop(p34, p35); vop(p30, p33); vop(p32, p35); vop(p32, p33); vop(p31, p34);
vop(p31, p32); vop(p33, p34); vop(p37, p38); vop(p36, p37); vop(p37, p38);
vop(p310, p311); vop(p39, p310); vop(p310, p311); vop(p36, p39); vop(p38, p311);
vop(p38, p39); vop(p37, p310); vop(p37, p38); vop(p39, p310); vop(p30, p36);
vop(p34, p310); vop(p34, p36); vop(p32, p38); vop(p32, p34); vop(p36, p38);
vop(p31, p37); vop(p35, p311); vop(p35, p37); vop(p33, p39); vop(p33, p35);
vop(p37, p39); vop(p31, p32); vop(p33, p34); vop(p35, p36); vop(p37, p38);
vop(p39, p310); vop(p313, p314); vop(p312, p313); vop(p313, p314); vop(p316, p317);
vop(p315, p316); vop(p316, p317); vop(p312, p315); vop(p314, p317); vop(p314, p315);
vop(p313, p316); vop(p313, p314); vop(p315, p316); vop(p319, p320); vop(p318, p319);
vop(p319, p320); vop(p321, p322); vop(p323, p324); vop(p321, p323); vop(p322, p324);
vop(p322, p323); vop(p318, p321); vop(p320, p323); vop(p320, p321); vop(p319, p322);
vop(p322, p324); vop(p319, p320); vop(p321, p322); vop(p323, p324); vop(p312, p318);
vop(p316, p322); vop(p316, p318); vop(p314, p320); vop(p320, p324); vop(p314, p316);
vop(p318, p320); vop(p322, p324); vop(p313, p319); vop(p317, p323); vop(p317, p319);
vop(p315, p321); vop(p315, p317); vop(p319, p321); vop(p313, p314); vop(p315, p316);
vop(p317, p318); vop(p319, p320); vop(p321, p322); vop(p323, p324); vop(p30, p312);
vop(p38, p320); vop(p38, p312); vop(p34, p316); vop(p316, p324); vop(p312, p316);
vop(p32, p314); vop(p310, p322); vop(p310, p314); vop(p36, p318); vop(p36, p310);
vop(p310, p312); vop(p31, p313); vop(p39, p321); vop(p39, p313); vop(p35, p317);
vop(p313, p317); vop(p33, p315); vop(p311, p323); vop(p311, p315); vop(p37, p319);
vop(p37, p311); vop(p311, p313); vop(p311, p312);
dst = __riscv_vset_v_u8m2_u8m2x4(dst, 3, p312);
__riscv_vsseg4e8(dst_data + i * dst_step + j * 4, dst, vl);
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int medianBlur(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, int ksize)
{
const int type = CV_MAKETYPE(depth, cn);
if (type != CV_8UC1 && type != CV_8UC4 && type != CV_16UC1 && type != CV_16SC1 && type != CV_32FC1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((ksize != 3 && ksize != 5) || src_data == dst_data)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (ksize*100 + type)
{
case 300 + CV_8UC1:
return common::invoke(height, {medianBlurC1<3, RVV_U8M4>}, src_data, src_step, dst_data, dst_step, width, height);
case 300 + CV_16UC1:
return common::invoke(height, {medianBlurC1<3, RVV_U16M4>}, src_data, src_step, dst_data, dst_step, width, height);
case 300 + CV_16SC1:
return common::invoke(height, {medianBlurC1<3, RVV_I16M4>}, src_data, src_step, dst_data, dst_step, width, height);
case 300 + CV_32FC1:
return common::invoke(height, {medianBlurC1<3, RVV_F32M4>}, src_data, src_step, dst_data, dst_step, width, height);
case 500 + CV_8UC1:
return common::invoke(height, {medianBlurC1<5, RVV_U8M1>}, src_data, src_step, dst_data, dst_step, width, height);
case 500 + CV_16UC1:
return common::invoke(height, {medianBlurC1<5, RVV_U16M1>}, src_data, src_step, dst_data, dst_step, width, height);
case 500 + CV_16SC1:
return common::invoke(height, {medianBlurC1<5, RVV_I16M1>}, src_data, src_step, dst_data, dst_step, width, height);
case 500 + CV_32FC1:
return common::invoke(height, {medianBlurC1<5, RVV_F32M1>}, src_data, src_step, dst_data, dst_step, width, height);
case 300 + CV_8UC4:
return common::invoke(height, {medianBlurC4<3>}, src_data, src_step, dst_data, dst_step, width, height);
case 500 + CV_8UC4:
return common::invoke(height, {medianBlurC4<5>}, src_data, src_step, dst_data, dst_step, width, height);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+189
View File
@@ -0,0 +1,189 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
class MomentsInvoker : public ParallelLoopBody
{
public:
template<typename... Args>
MomentsInvoker(std::function<int(int, int, Args...)> _func, Args&&... args)
{
func = std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::forward<Args>(args)...);
}
virtual void operator()(const Range& range) const override
{
func(range.start, range.end);
}
private:
std::function<int(int, int)> func;
};
template<typename... Args>
static inline int invoke(int width, int height, std::function<int(int, int, Args...)> func, Args&&... args)
{
cv::parallel_for_(Range(1, height), MomentsInvoker(func, std::forward<Args>(args)...), static_cast<double>((width - 1) * height) / (1 << 10));
return func(0, 1, std::forward<Args>(args)...);
}
template<typename helper> struct rvv;
template<> struct rvv<RVV_U32M2>
{
static inline vuint8mf2_t vid(size_t a) { return __riscv_vid_v_u8mf2(a); }
static inline RVV_U32M2::VecType vcvt(vuint8mf2_t a, size_t b) { return __riscv_vzext_vf4(a, b); }
};
template<> struct rvv<RVV_U32M4>
{
static inline vuint8m1_t vid(size_t a) { return __riscv_vid_v_u8m1(a); }
static inline RVV_U32M4::VecType vcvt(vuint8m1_t a, size_t b) { return __riscv_vzext_vf4(a, b); }
};
template<> struct rvv<RVV_I32M2>
{
static inline vuint8mf2_t vid(size_t a) { return __riscv_vid_v_u8mf2(a); }
static inline RVV_I32M2::VecType vcvt(vuint8mf2_t a, size_t b) { return RVV_I32M2::reinterpret(__riscv_vzext_vf4(a, b)); }
};
template<> struct rvv<RVV_F64M4>
{
static inline vuint8mf2_t vid(size_t a) { return __riscv_vid_v_u8mf2(a); }
static inline RVV_F64M4::VecType vcvt(vuint8mf2_t a, size_t b) { return __riscv_vfcvt_f(__riscv_vzext_vf8(a, b), b); }
};
constexpr int TILE_SIZE = 32;
template<bool binary, typename T, typename helperT, typename helperWT, typename helperMT>
static inline int imageMoments(int start, int end, const uchar* src_data, size_t src_step, int full_width, int full_height, double* m, std::mutex* mt)
{
double mm[10] = {0};
for (int yy = start; yy < end; yy++)
{
const int y = yy * TILE_SIZE;
const int height = std::min(TILE_SIZE, full_height - y);
for (int x = 0; x < full_width; x += TILE_SIZE)
{
const int width = std::min(TILE_SIZE, full_width - x);
double mom[10] = {0};
for (int i = 0; i < height; i++)
{
auto id = rvv<helperWT>::vid(helperT::setvlmax());
auto v0 = helperWT::vmv(0, helperWT::setvlmax());
auto v1 = helperWT::vmv(0, helperWT::setvlmax());
auto v2 = helperWT::vmv(0, helperWT::setvlmax());
auto v3 = helperMT::vmv(0, helperMT::setvlmax());
int vl;
for (int j = 0; j < width; j += vl)
{
vl = helperT::setvl(width - j);
typename helperWT::VecType p;
if (binary)
{
auto src = RVV_SameLen<T, helperT>::vload(reinterpret_cast<const T*>(src_data + (i + y) * src_step) + j + x, vl);
p = __riscv_vmerge(helperWT::vmv(0, vl), helperWT::vmv(255, vl), RVV_SameLen<T, helperT>::vmne(src, 0, vl), vl);
}
else
{
p = helperWT::cast(helperT::vload(reinterpret_cast<const typename helperT::ElemType*>(src_data + (i + y) * src_step) + j + x, vl), vl);
}
auto xx = rvv<helperWT>::vcvt(id, vl);
auto xp = helperWT::vmul(xx, p, vl);
v0 = helperWT::vadd_tu(v0, v0, p, vl);
v1 = helperWT::vadd_tu(v1, v1, xp, vl);
auto xxp = helperWT::vmul(xx, xp, vl);
v2 = helperWT::vadd_tu(v2, v2, xxp, vl);
v3 = helperMT::vadd_tu(v3, v3, helperMT::vmul(helperMT::cast(xx, vl), helperMT::cast(xxp, vl), vl), vl);
id = __riscv_vadd(id, vl, vl);
}
auto x0 = RVV_BaseType<helperWT>::vmv_x(helperWT::vredsum(v0, RVV_BaseType<helperWT>::vmv_s(0, RVV_BaseType<helperWT>::setvlmax()), helperWT::setvlmax()));
auto x1 = RVV_BaseType<helperWT>::vmv_x(helperWT::vredsum(v1, RVV_BaseType<helperWT>::vmv_s(0, RVV_BaseType<helperWT>::setvlmax()), helperWT::setvlmax()));
auto x2 = RVV_BaseType<helperWT>::vmv_x(helperWT::vredsum(v2, RVV_BaseType<helperWT>::vmv_s(0, RVV_BaseType<helperWT>::setvlmax()), helperWT::setvlmax()));
auto x3 = RVV_BaseType<helperMT>::vmv_x(helperMT::vredsum(v3, RVV_BaseType<helperMT>::vmv_s(0, RVV_BaseType<helperMT>::setvlmax()), helperMT::setvlmax()));
typename helperWT::ElemType py = i * x0, sy = i*i;
mom[9] += static_cast<typename helperMT::ElemType>(py) * sy;
mom[8] += static_cast<typename helperMT::ElemType>(x1) * sy;
mom[7] += static_cast<typename helperMT::ElemType>(x2) * i;
mom[6] += x3;
mom[5] += x0 * sy;
mom[4] += x1 * i;
mom[3] += x2;
mom[2] += py;
mom[1] += x1;
mom[0] += x0;
}
if (binary)
{
mom[0] /= 255, mom[1] /= 255, mom[2] /= 255, mom[3] /= 255, mom[4] /= 255;
mom[5] /= 255, mom[6] /= 255, mom[7] /= 255, mom[8] /= 255, mom[9] /= 255;
}
double xm = x * mom[0], ym = y * mom[0];
mm[0] += mom[0];
mm[1] += mom[1] + xm;
mm[2] += mom[2] + ym;
mm[3] += mom[3] + x * (mom[1] * 2 + xm);
mm[4] += mom[4] + x * (mom[2] + ym) + y * mom[1];
mm[5] += mom[5] + y * (mom[2] * 2 + ym);
mm[6] += mom[6] + x * (3. * mom[3] + x * (3. * mom[1] + xm));
mm[7] += mom[7] + x * (2 * (mom[4] + y * mom[1]) + x * (mom[2] + ym)) + y * mom[3];
mm[8] += mom[8] + y * (2 * (mom[4] + x * mom[2]) + y * (mom[1] + xm)) + x * mom[5];
mm[9] += mom[9] + y * (3. * mom[5] + y * (3. * mom[2] + ym));
}
}
std::lock_guard<std::mutex> lk(*mt);
for (int i = 0; i < 10; i++)
m[i] += mm[i];
return CV_HAL_ERROR_OK;
}
} // anonymous
// the algorithm is copied from imgproc/src/moments.cpp,
// in the function cv::Moments cv::moments
int imageMoments(const uchar* src_data, size_t src_step, int src_type, int width, int height, bool binary, double m[10])
{
if (src_type != CV_16UC1 && src_type != CV_16SC1 && src_type != CV_32FC1 && src_type != CV_64FC1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
std::fill(m, m + 10, 0);
const int cnt = (height + TILE_SIZE - 1) / TILE_SIZE;
std::mutex mt;
switch (static_cast<int>(binary)*100 + src_type)
{
case CV_16UC1:
return invoke(width, cnt, {imageMoments<false, ushort, RVV_U16M1, RVV_U32M2, RVV_U64M4>}, src_data, src_step, width, height, m, &mt);
case CV_16SC1:
return invoke(width, cnt, {imageMoments<false, short, RVV_I16M1, RVV_I32M2, RVV_I64M4>}, src_data, src_step, width, height, m, &mt);
case CV_32FC1:
return invoke(width, cnt, {imageMoments<false, float, RVV_F32M2, RVV_F64M4, RVV_F64M4>}, src_data, src_step, width, height, m, &mt);
case CV_64FC1:
return invoke(width, cnt, {imageMoments<false, double, RVV_F64M4, RVV_F64M4, RVV_F64M4>}, src_data, src_step, width, height, m, &mt);
case 100 + CV_16UC1:
return invoke(width, cnt, {imageMoments<true, ushort, RVV_U8M1, RVV_U32M4, RVV_U32M4>}, src_data, src_step, width, height, m, &mt);
case 100 + CV_16SC1:
return invoke(width, cnt, {imageMoments<true, short, RVV_U8M1, RVV_U32M4, RVV_U32M4>}, src_data, src_step, width, height, m, &mt);
case 100 + CV_32FC1:
return invoke(width, cnt, {imageMoments<true, float, RVV_U8M1, RVV_U32M4, RVV_U32M4>}, src_data, src_step, width, height, m, &mt);
case 100 + CV_64FC1:
return invoke(width, cnt, {imageMoments<true, double, RVV_U8M1, RVV_U32M4, RVV_U32M4>}, src_data, src_step, width, height, m, &mt);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+331
View File
@@ -0,0 +1,331 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
struct Morph2D
{
int operation;
int src_type;
int dst_type;
int kernel_type;
uchar* kernel_data;
size_t kernel_step;
int kernel_width;
int kernel_height;
int anchor_x;
int anchor_y;
int borderType;
const uchar* borderValue;
};
template<int op> struct rvv;
template<> struct rvv<CV_HAL_MORPH_ERODE>
{
static inline uchar init() { return std::numeric_limits<uchar>::max(); }
static inline uchar mop(uchar a, uchar b) { return a < b ? a : b; }
static inline vuint8m4_t vop(vuint8m4_t a, vuint8m4_t b, size_t c) { return __riscv_vminu(a, b, c); }
static inline vuint8m4_t vop(vuint8m4_t a, uchar b, size_t c) { return __riscv_vminu(a, b, c); }
};
template<> struct rvv<CV_HAL_MORPH_DILATE>
{
static inline uchar init() { return std::numeric_limits<uchar>::min(); }
static inline uchar mop(uchar a, uchar b) { return a > b ? a : b; }
static inline vuint8m4_t vop(vuint8m4_t a, vuint8m4_t b, size_t c) { return __riscv_vmaxu(a, b, c); }
static inline vuint8m4_t vop(vuint8m4_t a, uchar b, size_t c) { return __riscv_vmaxu(a, b, c); }
};
// the algorithm is copied from 3rdparty/carotene/src/morph.cpp,
// in the function template void morph3x3
template<int op>
static inline int morph(int start, int end, Morph2D* data, const uchar* src_data, size_t src_step, uchar* dst_data, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
{
bool kernel[9];
for (int i = 0; i < 9; i++)
{
kernel[i] = data->kernel_data[(i / 3) * data->kernel_step + i % 3] != 0;
}
constexpr int noval = std::numeric_limits<int>::max();
auto access = [&](int x, int y) {
int pi, pj;
if (data->borderType & BORDER_ISOLATED)
{
pi = common::borderInterpolate(x - data->anchor_y, height, data->borderType & ~BORDER_ISOLATED);
pj = common::borderInterpolate(y - data->anchor_x, width , data->borderType & ~BORDER_ISOLATED);
pi = pi < 0 ? noval : pi;
pj = pj < 0 ? noval : pj;
}
else
{
pi = common::borderInterpolate(offset_y + x - data->anchor_y, full_height, data->borderType);
pj = common::borderInterpolate(offset_x + y - data->anchor_x, full_width , data->borderType);
pi = pi < 0 ? noval : pi - offset_y;
pj = pj < 0 ? noval : pj - offset_x;
}
return std::make_pair(pi, pj);
};
auto process = [&](int x, int y) {
if (data->src_type == CV_8UC1)
{
uchar val = rvv<op>::init();
for (int i = 0; i < 9; i++)
{
if (kernel[i])
{
auto p = access(x + i / 3, y + i % 3);
if (p.first != noval && p.second != noval)
{
val = rvv<op>::mop(val, src_data[p.first * src_step + p.second]);
}
else
{
val = rvv<op>::mop(val, data->borderValue[0]);
}
}
}
dst_data[x * width + y] = val;
}
else
{
uchar val0, val1, val2, val3;
val0 = val1 = val2 = val3 = rvv<op>::init();
for (int i = 0; i < 9; i++)
{
if (kernel[i])
{
auto p = access(x + i / 3, y + i % 3);
if (p.first != noval && p.second != noval)
{
val0 = rvv<op>::mop(val0, src_data[p.first * src_step + p.second * 4 ]);
val1 = rvv<op>::mop(val1, src_data[p.first * src_step + p.second * 4 + 1]);
val2 = rvv<op>::mop(val2, src_data[p.first * src_step + p.second * 4 + 2]);
val3 = rvv<op>::mop(val3, src_data[p.first * src_step + p.second * 4 + 3]);
}
else
{
val0 = rvv<op>::mop(val0, data->borderValue[0]);
val1 = rvv<op>::mop(val1, data->borderValue[1]);
val2 = rvv<op>::mop(val2, data->borderValue[2]);
val3 = rvv<op>::mop(val3, data->borderValue[3]);
}
}
}
dst_data[(x * width + y) * 4 ] = val0;
dst_data[(x * width + y) * 4 + 1] = val1;
dst_data[(x * width + y) * 4 + 2] = val2;
dst_data[(x * width + y) * 4 + 3] = val3;
}
};
const int left = data->anchor_x, right = width - (2 - data->anchor_x);
for (int i = start; i < end; i++)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
const uchar* row0 = access(i , 0).first == noval ? nullptr : src_data + access(i , 0).first * src_step;
const uchar* row1 = access(i + 1, 0).first == noval ? nullptr : src_data + access(i + 1, 0).first * src_step;
const uchar* row2 = access(i + 2, 0).first == noval ? nullptr : src_data + access(i + 2, 0).first * src_step;
if (data->src_type == CV_8UC1)
{
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m4(right - j);
auto m0 = __riscv_vmv_v_x_u8m4(rvv<op>::init(), vl);
auto loadsrc = [&](const uchar* row, bool k0, bool k1, bool k2) {
if (!row)
{
m0 = rvv<op>::vop(m0, data->borderValue[0], vl);
return;
}
const uchar* extra = row + j - data->anchor_x;
auto v0 = __riscv_vle8_v_u8m4(extra, vl);
if (k0) m0 = rvv<op>::vop(m0, v0, vl);
v0 = __riscv_vslide1down(v0, extra[vl], vl);
if (k1) m0 = rvv<op>::vop(m0, v0, vl);
if (!k2) return;
v0 = __riscv_vslide1down(v0, extra[vl + 1], vl);
m0 = rvv<op>::vop(m0, v0, vl);
};
loadsrc(row0, kernel[0], kernel[1], kernel[2]);
loadsrc(row1, kernel[3], kernel[4], kernel[5]);
loadsrc(row2, kernel[6], kernel[7], kernel[8]);
__riscv_vse8(dst_data + i * width + j, m0, vl);
}
}
else
{
int vl, vl0, vl1;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m4(right - j);
vl0 = std::min(vl, (int)__riscv_vlenb() * 2);
vl1 = vl - vl0;
auto m0 = __riscv_vmv_v_x_u8m4(rvv<op>::init(), vl);
auto m1 = __riscv_vmv_v_x_u8m4(rvv<op>::init(), vl);
auto m2 = __riscv_vmv_v_x_u8m4(rvv<op>::init(), vl);
auto m3 = __riscv_vmv_v_x_u8m4(rvv<op>::init(), vl);
auto opshift = [&](vuint8m4_t a, vuint8m4_t b, bool k0, bool k1, bool k2, uchar r1, uchar r2) {
if (k0) a = rvv<op>::vop(a, b, vl);
b = __riscv_vslide1down(b, r1, vl);
if (k1) a = rvv<op>::vop(a, b, vl);
if (!k2) return a;
b = __riscv_vslide1down(b, r2, vl);
return rvv<op>::vop(a, b, vl);
};
auto loadsrc = [&](const uchar* row, bool k0, bool k1, bool k2) {
if (!row)
{
m0 = rvv<op>::vop(m0, data->borderValue[0], vl);
m1 = rvv<op>::vop(m1, data->borderValue[1], vl);
m2 = rvv<op>::vop(m2, data->borderValue[2], vl);
m3 = rvv<op>::vop(m3, data->borderValue[3], vl);
return;
}
vuint8m4_t v0{}, v1{}, v2{}, v3{};
const uchar* extra = row + (j - data->anchor_x) * 4;
auto src = __riscv_vlseg4e8_v_u8m2x4(extra, vl0);
v0 = __riscv_vset_v_u8m2_u8m4(v0, 0, __riscv_vget_v_u8m2x4_u8m2(src, 0));
v1 = __riscv_vset_v_u8m2_u8m4(v1, 0, __riscv_vget_v_u8m2x4_u8m2(src, 1));
v2 = __riscv_vset_v_u8m2_u8m4(v2, 0, __riscv_vget_v_u8m2x4_u8m2(src, 2));
v3 = __riscv_vset_v_u8m2_u8m4(v3, 0, __riscv_vget_v_u8m2x4_u8m2(src, 3));
src = __riscv_vlseg4e8_v_u8m2x4(extra + vl0 * 4, vl1);
v0 = __riscv_vset_v_u8m2_u8m4(v0, 1, __riscv_vget_v_u8m2x4_u8m2(src, 0));
v1 = __riscv_vset_v_u8m2_u8m4(v1, 1, __riscv_vget_v_u8m2x4_u8m2(src, 1));
v2 = __riscv_vset_v_u8m2_u8m4(v2, 1, __riscv_vget_v_u8m2x4_u8m2(src, 2));
v3 = __riscv_vset_v_u8m2_u8m4(v3, 1, __riscv_vget_v_u8m2x4_u8m2(src, 3));
extra += vl * 4;
m0 = opshift(m0, v0, k0, k1, k2, extra[0], extra[4]);
m1 = opshift(m1, v1, k0, k1, k2, extra[1], extra[5]);
m2 = opshift(m2, v2, k0, k1, k2, extra[2], extra[6]);
m3 = opshift(m3, v3, k0, k1, k2, extra[3], extra[7]);
};
loadsrc(row0, kernel[0], kernel[1], kernel[2]);
loadsrc(row1, kernel[3], kernel[4], kernel[5]);
loadsrc(row2, kernel[6], kernel[7], kernel[8]);
vuint8m2x4_t val{};
val = __riscv_vset_v_u8m2_u8m2x4(val, 0, __riscv_vget_v_u8m4_u8m2(m0, 0));
val = __riscv_vset_v_u8m2_u8m2x4(val, 1, __riscv_vget_v_u8m4_u8m2(m1, 0));
val = __riscv_vset_v_u8m2_u8m2x4(val, 2, __riscv_vget_v_u8m4_u8m2(m2, 0));
val = __riscv_vset_v_u8m2_u8m2x4(val, 3, __riscv_vget_v_u8m4_u8m2(m3, 0));
__riscv_vsseg4e8(dst_data + (i * width + j) * 4, val, vl0);
val = __riscv_vset_v_u8m2_u8m2x4(val, 0, __riscv_vget_v_u8m4_u8m2(m0, 1));
val = __riscv_vset_v_u8m2_u8m2x4(val, 1, __riscv_vget_v_u8m4_u8m2(m1, 1));
val = __riscv_vset_v_u8m2_u8m2x4(val, 2, __riscv_vget_v_u8m4_u8m2(m2, 1));
val = __riscv_vset_v_u8m2_u8m2x4(val, 3, __riscv_vget_v_u8m4_u8m2(m3, 1));
__riscv_vsseg4e8(dst_data + (i * width + j + vl0) * 4, val, vl1);
}
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int morphInit(cvhalFilter2D** context, int operation, int src_type, int dst_type, int /*max_width*/, int /*max_height*/, int kernel_type, uchar* kernel_data, size_t kernel_step, int kernel_width, int kernel_height, int anchor_x, int anchor_y, int borderType, const double borderValue[4], int iterations, bool /*allowSubmatrix*/, bool /*allowInplace*/)
{
if (kernel_type != CV_8UC1 || src_type != dst_type)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_type != CV_8UC1 && src_type != CV_8UC4)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (kernel_width != kernel_height || kernel_width != 3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (iterations != 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (operation != CV_HAL_MORPH_ERODE && operation != CV_HAL_MORPH_DILATE)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((borderType & ~BORDER_ISOLATED) == BORDER_WRAP)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
uchar* borderV;
if (src_type == CV_8UC1)
{
borderV = new uchar{static_cast<uchar>(borderValue[0])};
if (operation == CV_HAL_MORPH_DILATE && borderValue[0] == DBL_MAX)
borderV[0] = 0;
}
else
{
borderV = new uchar[4]{static_cast<uchar>(borderValue[0]), static_cast<uchar>(borderValue[1]), static_cast<uchar>(borderValue[2]), static_cast<uchar>(borderValue[3])};
if (operation == CV_HAL_MORPH_DILATE)
{
if (borderValue[0] == DBL_MAX)
borderV[0] = 0;
if (borderValue[1] == DBL_MAX)
borderV[1] = 0;
if (borderValue[2] == DBL_MAX)
borderV[2] = 0;
if (borderValue[3] == DBL_MAX)
borderV[3] = 0;
}
}
anchor_x = anchor_x < 0 ? kernel_width / 2 : anchor_x;
anchor_y = anchor_y < 0 ? kernel_height / 2 : anchor_y;
*context = reinterpret_cast<cvhalFilter2D*>(new Morph2D{operation, src_type, dst_type, kernel_type, kernel_data, kernel_step, kernel_width, kernel_height, anchor_x, anchor_y, borderType, borderV});
return CV_HAL_ERROR_OK;
}
int morph(cvhalFilter2D* context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int src_full_width, int src_full_height, int src_roi_x, int src_roi_y, int /*dst_full_width*/, int /*dst_full_height*/, int /*dst_roi_x*/, int /*dst_roi_y*/)
{
Morph2D* data = reinterpret_cast<Morph2D*>(context);
int cn = data->src_type == CV_8UC1 ? 1 : 4;
std::vector<uchar> dst(width * height * cn);
int res = CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (data->operation)
{
case CV_HAL_MORPH_ERODE:
res = common::invoke(height, {morph<CV_HAL_MORPH_ERODE>}, data, src_data, src_step, dst.data(), width, height, src_full_width, src_full_height, src_roi_x, src_roi_y);
break;
case CV_HAL_MORPH_DILATE:
res = common::invoke(height, {morph<CV_HAL_MORPH_DILATE>}, data, src_data, src_step, dst.data(), width, height, src_full_width, src_full_height, src_roi_x, src_roi_y);
break;
}
for (int i = 0; i < height; i++)
memcpy(dst_data + i * dst_step, dst.data() + i * width * cn, width * cn);
return res;
}
int morphFree(cvhalFilter2D* context)
{
delete reinterpret_cast<Morph2D*>(context)->borderValue;
delete reinterpret_cast<Morph2D*>(context);
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+600
View File
@@ -0,0 +1,600 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
template<typename T> struct rvv;
template<> struct rvv<uchar>
{
using T = RVV_U8M1;
using WT = RVV_SameLen<int, T>;
using MT = RVV_SameLen<uint, T>;
static inline WT::VecType vcvt_T_WT(T::VecType a, size_t b) { return WT::reinterpret(MT::cast(a, b)); }
static inline T::VecType vcvt_WT_T(WT::VecType a, int b, size_t c) { return T::cast(MT::reinterpret(__riscv_vsra(__riscv_vadd(a, 1 << (b - 1), c), b, c)), c); }
static inline WT::VecType down0(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return __riscv_vadd(__riscv_vadd(__riscv_vadd(vec_src0, vec_src4, vl), __riscv_vadd(vec_src2, vec_src2, vl), vl),
__riscv_vsll(__riscv_vadd(__riscv_vadd(vec_src1, vec_src2, vl), vec_src3, vl), 2, vl), vl);
}
static inline WT::VecType down1(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl);
}
static inline WT::VecType up00(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vadd(__riscv_vadd(vec_src0, vec_src2, vl), __riscv_vadd(__riscv_vsll(vec_src1, 2, vl), __riscv_vsll(vec_src1, 1, vl), vl), vl);
}
static inline WT::VecType up01(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vsll(__riscv_vadd(vec_src1, vec_src2, vl), 2, vl);
}
static inline WT::VecType up10(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return up00(vec_src0, vec_src1, vec_src2, vl);
}
static inline WT::VecType up11(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return up01(vec_src1, vec_src2, vl);
}
};
template<> struct rvv<short>
{
using T = RVV_I16M2;
using WT = RVV_SameLen<int, T>;
using MT = RVV_SameLen<uint, T>;
static inline WT::VecType vcvt_T_WT(T::VecType a, size_t b) { return WT::cast(a, b); }
static inline T::VecType vcvt_WT_T(WT::VecType a, int b, size_t c) { return T::cast(__riscv_vsra(__riscv_vadd(a, 1 << (b - 1), c), b, c), c); }
static inline WT::VecType down0(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return __riscv_vadd(__riscv_vadd(__riscv_vadd(vec_src0, vec_src4, vl), __riscv_vadd(vec_src2, vec_src2, vl), vl),
__riscv_vsll(__riscv_vadd(__riscv_vadd(vec_src1, vec_src2, vl), vec_src3, vl), 2, vl), vl);
}
static inline WT::VecType down1(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl);
}
static inline WT::VecType up00(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vadd(__riscv_vadd(vec_src0, vec_src2, vl), __riscv_vadd(__riscv_vsll(vec_src1, 2, vl), __riscv_vsll(vec_src1, 1, vl), vl), vl);
}
static inline WT::VecType up01(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vsll(__riscv_vadd(vec_src1, vec_src2, vl), 2, vl);
}
static inline WT::VecType up10(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return up00(vec_src0, vec_src1, vec_src2, vl);
}
static inline WT::VecType up11(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return up01(vec_src1, vec_src2, vl);
}
};
template<> struct rvv<float>
{
using T = RVV_F32M4;
using WT = RVV_SameLen<float, T>;
using MT = RVV_SameLen<uint, T>;
static inline WT::VecType vcvt_T_WT(T::VecType a, size_t b) { return WT::cast(a, b); }
static inline T::VecType vcvt_WT_T(WT::VecType a, [[maybe_unused]] int b, size_t c) { return T::cast(a, c); }
static inline WT::VecType down0(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return __riscv_vfmadd(vec_src2, 6, __riscv_vfmadd(__riscv_vfadd(vec_src1, vec_src3, vl), 4, __riscv_vfadd(vec_src0, vec_src4, vl), vl), vl);
}
static inline WT::VecType down1(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, WT::VecType vec_src3, WT::VecType vec_src4, size_t vl) {
return __riscv_vfmul(down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), 1.f / 256.f, vl);
}
static inline WT::VecType up00(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vfadd(__riscv_vfmadd(vec_src1, 6, vec_src0, vl), vec_src2, vl);
}
static inline WT::VecType up01(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vfmul(__riscv_vfadd(vec_src1, vec_src2, vl), 4, vl);
}
static inline WT::VecType up10(WT::VecType vec_src0, WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vfmul(__riscv_vfadd(__riscv_vfmadd(vec_src1, 6, vec_src0, vl), vec_src2, vl), 1.f / 64.f, vl);
}
static inline WT::VecType up11(WT::VecType vec_src1, WT::VecType vec_src2, size_t vl) {
return __riscv_vfmul(__riscv_vfadd(vec_src1, vec_src2, vl), 1.f / 16.f, vl);
}
};
template <typename RVV>
struct pyrDownVec0
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
void operator()(const T* src, WT* row, const uint* tabM, int start, int end)
{
int vl;
switch (start)
{
case 1:
for( int x = start; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + x * 2 - 2, 2 * sizeof(T), vl), vl);
auto vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + x * 2 - 1, 2 * sizeof(T), vl), vl);
auto vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + x * 2, 2 * sizeof(T), vl), vl);
auto vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + x * 2 + 1, 2 * sizeof(T), vl), vl);
auto vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + x * 2 + 2, 2 * sizeof(T), vl), vl);
__riscv_vse32(row + x, RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
}
break;
case 2:
for( int x = start / 2; x < end / 2; x += vl )
{
vl = RVV::WT::setvl(end / 2 - x);
auto vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 2, 4 * sizeof(T), vl), vl);
auto vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 2, 4 * sizeof(T), vl), vl);
auto vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 2, 4 * sizeof(T), vl), vl);
auto vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 2, 4 * sizeof(T), vl), vl);
auto vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 2, 4 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 2, 2 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 2 + 1, 4 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 2 + 1, 4 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 2 + 1, 4 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 2 + 1, 4 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 2 + 1, 4 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 2 + 1, 2 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
}
break;
case 3:
for( int x = start / 3; x < end / 3; x += vl )
{
vl = RVV::WT::setvl(end / 3 - x);
auto vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 3, 6 * sizeof(T), vl), vl);
auto vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 3, 6 * sizeof(T), vl), vl);
auto vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 3, 6 * sizeof(T), vl), vl);
auto vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 3, 6 * sizeof(T), vl), vl);
auto vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 3, 6 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 3, 3 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 3 + 1, 6 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 3 + 1, 6 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 3 + 1, 6 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 3 + 1, 6 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 3 + 1, 6 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 3 + 1, 3 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 3 + 2, 6 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 3 + 2, 6 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 3 + 2, 6 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 3 + 2, 6 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 3 + 2, 6 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 3 + 2, 3 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
}
break;
case 4:
for( int x = start / 4; x < end / 4; x += vl )
{
vl = RVV::WT::setvl(end / 4 - x);
auto vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 4, 8 * sizeof(T), vl), vl);
auto vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 4, 8 * sizeof(T), vl), vl);
auto vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 4, 8 * sizeof(T), vl), vl);
auto vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 4, 8 * sizeof(T), vl), vl);
auto vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 4, 8 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 4, 4 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 4 + 1, 8 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 4 + 1, 8 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 4 + 1, 8 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 4 + 1, 8 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 4 + 1, 8 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 4 + 1, 4 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 4 + 2, 8 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 4 + 2, 8 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 4 + 2, 8 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 4 + 2, 8 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 4 + 2, 8 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 4 + 2, 4 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
vec_src0 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 2) * 4 + 3, 8 * sizeof(T), vl), vl);
vec_src1 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 - 1) * 4 + 3, 8 * sizeof(T), vl), vl);
vec_src2 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2) * 4 + 3, 8 * sizeof(T), vl), vl);
vec_src3 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 1) * 4 + 3, 8 * sizeof(T), vl), vl);
vec_src4 = RVV::vcvt_T_WT(RVV::T::vload_stride(src + (x * 2 + 2) * 4 + 3, 8 * sizeof(T), vl), vl);
__riscv_vsse32(row + x * 4 + 3, 4 * sizeof(WT), RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
}
break;
default:
for( int x = start; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_tabM = RVV::MT::vload(tabM + x, vl);
vec_tabM = __riscv_vmul(__riscv_vsub(vec_tabM, start * 2, vl), sizeof(T), vl);
auto vec_src0 = RVV::vcvt_T_WT(__riscv_vloxei32(src, vec_tabM, vl), vl);
vec_tabM = __riscv_vadd(vec_tabM, start * sizeof(T), vl);
auto vec_src1 = RVV::vcvt_T_WT(__riscv_vloxei32(src, vec_tabM, vl), vl);
vec_tabM = __riscv_vadd(vec_tabM, start * sizeof(T), vl);
auto vec_src2 = RVV::vcvt_T_WT(__riscv_vloxei32(src, vec_tabM, vl), vl);
vec_tabM = __riscv_vadd(vec_tabM, start * sizeof(T), vl);
auto vec_src3 = RVV::vcvt_T_WT(__riscv_vloxei32(src, vec_tabM, vl), vl);
vec_tabM = __riscv_vadd(vec_tabM, start * sizeof(T), vl);
auto vec_src4 = RVV::vcvt_T_WT(__riscv_vloxei32(src, vec_tabM, vl), vl);
__riscv_vse32(row + x, RVV::down0(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), vl);
}
}
}
};
template <typename RVV>
struct pyrDownVec1
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
void operator()(WT* row0, WT* row1, WT* row2, WT* row3, WT* row4, T* dst, int end)
{
int vl;
for( int x = 0 ; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_src0 = RVV::WT::vload(row0 + x, vl);
auto vec_src1 = RVV::WT::vload(row1 + x, vl);
auto vec_src2 = RVV::WT::vload(row2 + x, vl);
auto vec_src3 = RVV::WT::vload(row3 + x, vl);
auto vec_src4 = RVV::WT::vload(row4 + x, vl);
RVV::T::vstore(dst + x, RVV::vcvt_WT_T(RVV::down1(vec_src0, vec_src1, vec_src2, vec_src3, vec_src4, vl), 8, vl), vl);
}
}
};
template <typename RVV>
struct pyrUpVec0
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
void operator()(const T* src, WT* row, const uint* dtab, int start, int end)
{
int vl;
for( int x = start; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_src0 = RVV::vcvt_T_WT(RVV::T::vload(src + x - start, vl), vl);
auto vec_src1 = RVV::vcvt_T_WT(RVV::T::vload(src + x, vl), vl);
auto vec_src2 = RVV::vcvt_T_WT(RVV::T::vload(src + x + start, vl), vl);
auto vec_dtab = RVV::MT::vload(dtab + x, vl);
vec_dtab = __riscv_vmul(vec_dtab, sizeof(WT), vl);
__riscv_vsoxei32(row, vec_dtab, RVV::up00(vec_src0, vec_src1, vec_src2, vl), vl);
__riscv_vsoxei32(row, __riscv_vadd(vec_dtab, start * sizeof(WT), vl), RVV::up01(vec_src1, vec_src2, vl), vl);
}
}
};
template <typename RVV>
struct pyrUpVec1
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
void operator()(WT* row0, WT* row1, WT* row2, T* dst0, T* dst1, int end)
{
int vl;
if (dst0 != dst1)
{
for( int x = 0 ; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_src0 = RVV::WT::vload(row0 + x, vl);
auto vec_src1 = RVV::WT::vload(row1 + x, vl);
auto vec_src2 = RVV::WT::vload(row2 + x, vl);
RVV::T::vstore(dst0 + x, RVV::vcvt_WT_T(RVV::up10(vec_src0, vec_src1, vec_src2, vl), 6, vl), vl);
RVV::T::vstore(dst1 + x, RVV::vcvt_WT_T(RVV::up11(vec_src1, vec_src2, vl), 6, vl), vl);
}
}
else
{
for( int x = 0 ; x < end; x += vl )
{
vl = RVV::WT::setvl(end - x);
auto vec_src0 = RVV::WT::vload(row0 + x, vl);
auto vec_src1 = RVV::WT::vload(row1 + x, vl);
auto vec_src2 = RVV::WT::vload(row2 + x, vl);
RVV::T::vstore(dst0 + x, RVV::vcvt_WT_T(RVV::up10(vec_src0, vec_src1, vec_src2, vl), 6, vl), vl);
}
}
}
};
template<typename RVV>
struct PyrDownInvoker : ParallelLoopBody
{
PyrDownInvoker(const uchar* _src_data, size_t _src_step, int _src_width, int _src_height, uchar* _dst_data, size_t _dst_step, int _dst_width, int _dst_height, int _cn, int _borderType, int* _tabR, int* _tabM, int* _tabL)
{
src_data = _src_data;
src_step = _src_step;
src_width = _src_width;
src_height = _src_height;
dst_data = _dst_data;
dst_step = _dst_step;
dst_width = _dst_width;
dst_height = _dst_height;
cn = _cn;
borderType = _borderType;
tabR = _tabR;
tabM = _tabM;
tabL = _tabL;
}
void operator()(const Range& range) const CV_OVERRIDE;
const uchar* src_data;
size_t src_step;
int src_width;
int src_height;
uchar* dst_data;
size_t dst_step;
int dst_width;
int dst_height;
int cn;
int borderType;
int* tabR;
int* tabM;
int* tabL;
};
static inline int borderInterpolate( int p, int len, int borderType )
{
if( (unsigned)p < (unsigned)len )
;
else if( borderType == BORDER_REPLICATE )
p = p < 0 ? 0 : len - 1;
else if( borderType == BORDER_REFLECT || borderType == BORDER_REFLECT_101 )
{
int delta = borderType == BORDER_REFLECT_101;
if( len == 1 )
return 0;
do
{
if( p < 0 )
p = -p - 1 + delta;
else
p = len - 1 - (p - len) - delta;
}
while( (unsigned)p >= (unsigned)len );
}
else if( borderType == BORDER_WRAP )
{
if( p < 0 )
p -= ((p-len+1)/len)*len;
if( p >= len )
p %= len;
}
else if( borderType == BORDER_CONSTANT )
p = -1;
return p;
}
// the algorithm is copied from imgproc/src/pyramids.cpp,
// in the function template void cv::pyrDown_
template <typename RVV>
inline int pyrDown(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int cn, int borderType)
{
const int PD_SZ = 5;
std::vector<int> _tabM(dst_width * cn), _tabL(cn * (PD_SZ + 2)), _tabR(cn * (PD_SZ + 2));
int *tabM = _tabM.data(), *tabL = _tabL.data(), *tabR = _tabR.data();
if( src_width <= 0 || src_height <= 0 ||
std::abs(dst_width*2 - src_width) > 2 ||
std::abs(dst_height*2 - src_height) > 2 )
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
int width0 = std::min((src_width-PD_SZ/2-1)/2 + 1, dst_width);
for (int x = 0; x <= PD_SZ+1; x++)
{
int sx0 = borderInterpolate(x - PD_SZ/2, src_width, borderType)*cn;
int sx1 = borderInterpolate(x + width0*2 - PD_SZ/2, src_width, borderType)*cn;
for (int k = 0; k < cn; k++)
{
tabL[x*cn + k] = sx0 + k;
tabR[x*cn + k] = sx1 + k;
}
}
for (int x = 0; x < dst_width*cn; x++)
tabM[x] = (x/cn)*2*cn + x % cn;
cv::parallel_for_(Range(0,dst_height), PyrDownInvoker<RVV>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn, borderType, tabR, tabM, tabL), cv::getNumThreads());
return CV_HAL_ERROR_OK;
}
template <typename RVV>
void PyrDownInvoker<RVV>::operator()(const Range& range) const
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
const int PD_SZ = 5;
int bufstep = (dst_width*cn + 15) & -16;
std::vector<WT> _buf(bufstep*PD_SZ + 16);
WT* buf = (WT*)(((size_t)_buf.data() + 15) & -16);
WT* rows[PD_SZ];
int sy0 = -PD_SZ/2, sy = range.start * 2 + sy0, width0 = std::min((src_width-PD_SZ/2-1)/2 + 1, dst_width);
int _dst_width = dst_width * cn;
width0 *= cn;
for (int y = range.start; y < range.end; y++)
{
T* dst = reinterpret_cast<T*>(dst_data + dst_step * y);
WT *row0, *row1, *row2, *row3, *row4;
// fill the ring buffer (horizontal convolution and decimation)
int sy_limit = y*2 + 2;
for( ; sy <= sy_limit; sy++ )
{
WT* row = buf + ((sy - sy0) % PD_SZ)*bufstep;
int _sy = borderInterpolate(sy, src_height, borderType);
const T* src = reinterpret_cast<const T*>(src_data + src_step * _sy);
do {
int x = 0;
for( ; x < cn; x++ )
{
row[x] = src[tabL[x+cn*2]]*6 + (src[tabL[x+cn]] + src[tabL[x+cn*3]])*4 +
src[tabL[x]] + src[tabL[x+cn*4]];
}
if( x == _dst_width )
break;
pyrDownVec0<RVV>()(src, row, reinterpret_cast<const uint*>(tabM), cn, width0);
x = width0;
// tabR
for (int x_ = 0; x < _dst_width; x++, x_++)
{
row[x] = src[tabR[x_+cn*2]]*6 + (src[tabR[x_+cn]] + src[tabR[x_+cn*3]])*4 +
src[tabR[x_]] + src[tabR[x_+cn*4]];
}
} while (0);
}
// do vertical convolution and decimation and write the result to the destination image
for (int k = 0; k < PD_SZ; k++)
rows[k] = buf + ((y*2 - PD_SZ/2 + k - sy0) % PD_SZ)*bufstep;
row0 = rows[0]; row1 = rows[1]; row2 = rows[2]; row3 = rows[3]; row4 = rows[4];
pyrDownVec1<RVV>()(row0, row1, row2, row3, row4, dst, _dst_width);
}
}
// the algorithm is copied from imgproc/src/pyramids.cpp,
// in the function template void cv::pyrUp_
template <typename RVV>
inline int pyrUp(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int cn)
{
using T = typename RVV::T::ElemType;
using WT = typename RVV::WT::ElemType;
const int PU_SZ = 3;
int bufstep = ((dst_width+1)*cn + 15) & -16;
std::vector<WT> _buf(bufstep*PU_SZ + 16);
WT* buf = (WT*)(((size_t)_buf.data() + 15) & -16);
std::vector<int> _dtab(src_width*cn);
int* dtab = _dtab.data();
WT* rows[PU_SZ];
if( std::abs(dst_width - src_width*2) != dst_width % 2 ||
std::abs(dst_height - src_height*2) != dst_height % 2)
{
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
int k, x, sy0 = -PU_SZ/2, sy = sy0;
src_width *= cn;
dst_width *= cn;
for( x = 0; x < src_width; x++ )
dtab[x] = (x/cn)*2*cn + x % cn;
for( int y = 0; y < src_height; y++ )
{
T* dst0 = reinterpret_cast<T*>(dst_data + dst_step * (y*2));
T* dst1 = reinterpret_cast<T*>(dst_data + dst_step * (std::min(y*2+1, dst_height-1)));
WT *row0, *row1, *row2;
// fill the ring buffer (horizontal convolution and decimation)
for( ; sy <= y + 1; sy++ )
{
WT* row = buf + ((sy - sy0) % PU_SZ)*bufstep;
int _sy = borderInterpolate(sy*2, src_height*2, (int)BORDER_REFLECT_101)/2;
const T* src = reinterpret_cast<const T*>(src_data + src_step * _sy);
if( src_width == cn )
{
for( x = 0; x < cn; x++ )
row[x] = row[x + cn] = src[x]*8;
continue;
}
for( x = 0; x < cn; x++ )
{
int dx = dtab[x];
WT t0 = src[x]*6 + src[x + cn]*2;
WT t1 = (src[x] + src[x + cn])*4;
row[dx] = t0; row[dx + cn] = t1;
dx = dtab[src_width - cn + x];
int sx = src_width - cn + x;
t0 = src[sx - cn] + src[sx]*7;
t1 = src[sx]*8;
row[dx] = t0; row[dx + cn] = t1;
if (dst_width > src_width*2)
{
row[(dst_width-1) * cn + x] = row[dx + cn];
}
}
pyrUpVec0<RVV>()(src, row, reinterpret_cast<const uint*>(dtab), cn, src_width - cn);
}
// do vertical convolution and decimation and write the result to the destination image
for( k = 0; k < PU_SZ; k++ )
rows[k] = buf + ((y - PU_SZ/2 + k - sy0) % PU_SZ)*bufstep;
row0 = rows[0]; row1 = rows[1]; row2 = rows[2];
pyrUpVec1<RVV>()(row0, row1, row2, dst0, dst1, dst_width);
}
if (dst_height > src_height*2)
{
T* dst0 = reinterpret_cast<T*>(dst_data + dst_step * (src_height*2-2));
T* dst2 = reinterpret_cast<T*>(dst_data + dst_step * (src_height*2));
for(x = 0; x < dst_width ; x++ )
{
dst2[x] = dst0[x];
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int pyrDown(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int depth, int cn, int border_type)
{
if (border_type == BORDER_CONSTANT || (depth == CV_32F && cn == 1))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (depth)
{
case CV_8U:
return pyrDown<rvv<uchar>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn, border_type);
case CV_16S:
return pyrDown<rvv<short>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn, border_type);
case CV_32F:
return pyrDown<rvv<float>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn, border_type);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
int pyrUp(const uchar* src_data, size_t src_step, int src_width, int src_height, uchar* dst_data, size_t dst_step, int dst_width, int dst_height, int depth, int cn, int border_type)
{
if (border_type != BORDER_DEFAULT)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (depth)
{
case CV_8U:
return pyrUp<rvv<uchar>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn);
case CV_16S:
return pyrUp<rvv<short>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn);
case CV_32F:
return pyrUp<rvv<float>>(src_data, src_step, src_width, src_height, dst_data, dst_step, dst_width, dst_height, cn);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
File diff suppressed because it is too large Load Diff
+883
View File
@@ -0,0 +1,883 @@
// 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 .
// Copyright (C) 2025, SpaceMIT Inc., all rights reserved.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv
{
namespace rvv_hal
{
namespace imgproc
{
#if CV_HAL_RVV_1P0_ENABLED
#define borderValue 0
static inline int scharr_dx0(int start, int end, const uint8_t *src_data, size_t src_step,
uint8_t *dst_data, size_t dst_step,
int width, int height,
int src_depth __attribute__((unused)), int dst_depth, int cn __attribute__((unused)),
int margin_left __attribute__((unused)), int margin_top __attribute__((unused)),
int margin_right __attribute__((unused)), int margin_bottom __attribute__((unused)),
double scale __attribute__((unused)), double delta __attribute__((unused)),
int border_type)
{
int dx0, dx1, dx2, dy0, dy1, dy2;
dy0 = -1;
dx0 = 3;
dy1 = 0;
dx1 = 10;
dy2 = 1;
dx2 = 3;
int16_t trow[width];
static thread_local std::vector<uint8_t> zero_row;
if (zero_row.size() < static_cast<size_t>(width))
{
zero_row.clear();
zero_row.resize(width, 0);
}
if (dst_depth == CV_8U)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
trow[0] = (dy0 * srow0[0] + dy1 * srow1[0] + dy2 * srow2[0]);
// Last pixel
trow[width - 1] = dy0 * srow0[width - 1] + dy1 * srow1[width - 1] + dy2 * srow2[width - 1];
size_t vl = 0;
// Vector processing
for (int x = 1; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x - 1);
vint16m8_t vsrow0 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow0 + x, vl), vl));
vint16m8_t vsrow2 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow2 + x, vl), vl));
vint16m8_t vrowx = __riscv_vsub_vv_i16m8(vsrow2, vsrow0, vl);
__riscv_vse16_v_i16m8(trow + x, vrowx, vl);
}
int x = 0;
uint8_t *drow = (uint8_t *)(dst_data + y * dst_step);
int16_t temp = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
temp += trow[0] * dx0;
}
drow[x] = (uint8_t)(temp > 0 ? (temp < 255 ? temp : 255) : 0);
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m8(width - x - 1);
vint16m8_t vleft = __riscv_vle16_v_i16m8(trow + x - 1, vl);
vint16m8_t vcenter = __riscv_vle16_v_i16m8(trow + x, vl);
vint16m8_t vright = __riscv_vle16_v_i16m8(trow + x + 1, vl);
vint16m8_t vres = __riscv_vmul_vx_i16m8(vcenter, dx1, vl);
vcenter = __riscv_vadd_vv_i16m8(vleft, vright, vl);
vres = __riscv_vmacc_vx_i16m8(vres, dx0, vcenter, vl);
vres = __riscv_vmax_vx_i16m8(vres, 0, vl);
vres = __riscv_vmin_vx_i16m8(vres, 255, vl);
__riscv_vse8_v_u8m4(drow + x, __riscv_vncvt_x_x_w_u8m4(__riscv_vreinterpret_v_i16m8_u16m8(vres), vl), vl);
}
x = width - 1;
temp = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
temp += trow[width - 1] * dx2;
}
drow[x] = (uint8_t)(temp > 0 ? (temp < 255 ? temp : 255) : 0);
}
}
else if (dst_depth == CV_16S)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
if (y == 0)
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
else if (y == height - 1)
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
size_t vl = 0;
// Vector processing
for (int x = 0; x < width; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x);
vint16m8_t vsrow0 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow0 + x, vl), vl));
vint16m8_t vsrow2 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow2 + x, vl), vl));
vint16m8_t vrowx = __riscv_vsub_vv_i16m8(vsrow2, vsrow0, vl);
__riscv_vse16_v_i16m8(trow + x, vrowx, vl);
}
int x = 0;
int16_t *drow = (int16_t *)(dst_data + y * dst_step);
drow[0] = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[0] * dx0;
}
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m8(width - x - 1);
vint16m8_t vleft = __riscv_vle16_v_i16m8(trow + x - 1, vl);
vint16m8_t vcenter = __riscv_vle16_v_i16m8(trow + x, vl);
vint16m8_t vright = __riscv_vle16_v_i16m8(trow + x + 1, vl);
vint16m8_t vres = __riscv_vmul_vx_i16m8(vcenter, dx1, vl);
vcenter = __riscv_vadd_vv_i16m8(vleft, vright, vl);
vres = __riscv_vmacc_vx_i16m8(vres, dx0, vcenter, vl);
__riscv_vse16_v_i16m8(drow + x, vres, vl);
}
x = width - 1;
drow[x] = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[width - 1] * dx2;
}
}
}
else if (dst_depth == CV_32F)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
if (y == 0)
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
else if (y == height - 1)
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
size_t vl = 0;
// Vector processing
for (int x = 0; x < width; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x);
vint16m8_t vsrow0 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow0 + x, vl), vl));
vint16m8_t vsrow2 = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vwcvtu_x_x_v_u16m8(__riscv_vle8_v_u8m4(srow2 + x, vl), vl));
vint16m8_t vrowx = __riscv_vsub_vv_i16m8(vsrow2, vsrow0, vl);
__riscv_vse16_v_i16m8(trow + x, vrowx, vl);
}
int x = 0;
float *drow = (float *)(dst_data + y * dst_step);
drow[x] = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[0] * dx0;
}
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m4(width - x - 1);
vint16m4_t vleft = __riscv_vle16_v_i16m4(trow + x - 1, vl);
vint16m4_t vcenter = __riscv_vle16_v_i16m4(trow + x, vl);
vint16m4_t vright = __riscv_vle16_v_i16m4(trow + x + 1, vl);
vint16m4_t vres = __riscv_vmul_vx_i16m4(vcenter, dx1, vl);
vcenter = __riscv_vadd_vv_i16m4(vleft, vright, vl);
vres = __riscv_vmacc_vx_i16m4(vres, dx0, vcenter, vl);
__riscv_vse32_v_f32m8(drow + x, __riscv_vfwcvt_f_x_v_f32m8(vres, vl), vl);
}
x = width - 1;
drow[x] = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[width - 1] * dx2;
}
}
}
return CV_HAL_ERROR_OK;
}
static inline int scharr_dx1(int start, int end, const uint8_t *src_data, size_t src_step,
uint8_t *dst_data, size_t dst_step,
int width, int height,
int src_depth __attribute__((unused)), int dst_depth, int cn __attribute__((unused)),
int margin_left __attribute__((unused)), int margin_top __attribute__((unused)),
int margin_right __attribute__((unused)), int margin_bottom __attribute__((unused)),
double scale __attribute__((unused)), double delta __attribute__((unused)),
int border_type)
{
int dx0, dx1, dx2, dy0, dy1, dy2;
dx0 = -1;
dy0 = 3;
dx1 = 0;
dy1 = 10;
dx2 = 1;
dy2 = 3;
int16_t trow[width];
static thread_local std::vector<uint8_t> zero_row;
if (zero_row.size() < static_cast<size_t>(width))
{
zero_row.clear();
zero_row.resize(width, 0);
}
if (dst_depth == CV_8U)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
if (y == 0)
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
else if (y == height - 1)
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
trow[0] = (dy0 * srow0[0] + dy1 * srow1[0] + dy2 * srow2[0]);
// Last pixel
trow[width - 1] = dy0 * srow0[width - 1] + dy1 * srow1[width - 1] + dy2 * srow2[width - 1];
size_t vl = 0;
// Vector processing
for (int x = 1; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x - 1);
vuint8m4_t vsrow0 = __riscv_vle8_v_u8m4(srow0 + x, vl);
vuint8m4_t vsrow1 = __riscv_vle8_v_u8m4(srow1 + x, vl);
vuint8m4_t vsrow2 = __riscv_vle8_v_u8m4(srow2 + x, vl);
vuint16m8_t vrowx = __riscv_vwmulu_vx_u16m8(vsrow1, dy1, vl);
vuint16m8_t vtemp = __riscv_vwaddu_vv_u16m8(vsrow0, vsrow2, vl);
vrowx = __riscv_vmacc_vx_u16m8(vrowx, dy0, vtemp, vl);
__riscv_vse16_v_i16m8(trow + x, __riscv_vreinterpret_v_u16m8_i16m8(vrowx), vl);
}
int x = 0;
uint8_t *drow = (uint8_t *)(dst_data + y * dst_step);
int16_t temp = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
temp += trow[0] * dx0;
}
drow[x] = (uint8_t)(temp > 0 ? (temp < 255 ? temp : 255) : 0);
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m8(width - x - 1);
vint16m8_t vleft = __riscv_vle16_v_i16m8(trow + x - 1, vl);
vint16m8_t vright = __riscv_vle16_v_i16m8(trow + x + 1, vl);
vint16m8_t vres = __riscv_vsub_vv_i16m8(vright, vleft, vl);
vres = __riscv_vmax_vx_i16m8(vres, 0, vl);
vres = __riscv_vmin_vx_i16m8(vres, 255, vl);
__riscv_vse8_v_u8m4(drow + x, __riscv_vncvt_x_x_w_u8m4(__riscv_vreinterpret_v_i16m8_u16m8(vres), vl), vl);
}
x = width - 1;
temp = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
temp += trow[width - 1] * dx2;
}
drow[x] = (uint8_t)(temp > 0 ? (temp < 255 ? temp : 255) : 0);
}
}
else if (dst_depth == CV_16S)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
if (y == 0)
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
else if (y == height - 1)
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
size_t vl = 0;
// Vector processing
for (int x = 0; x < width; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x);
vuint8m4_t vsrow0 = __riscv_vle8_v_u8m4(srow0 + x, vl);
vuint8m4_t vsrow1 = __riscv_vle8_v_u8m4(srow1 + x, vl);
vuint8m4_t vsrow2 = __riscv_vle8_v_u8m4(srow2 + x, vl);
vuint16m8_t vrowx = __riscv_vwmulu_vx_u16m8(vsrow1, dy1, vl);
vuint16m8_t vtemp = __riscv_vwaddu_vv_u16m8(vsrow0, vsrow2, vl);
vrowx = __riscv_vmacc_vx_u16m8(vrowx, dy0, vtemp, vl);
__riscv_vse16_v_i16m8(trow + x, __riscv_vreinterpret_v_u16m8_i16m8(vrowx), vl);
}
int x = 0;
int16_t *drow = (int16_t *)(dst_data + y * dst_step);
drow[x] = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[0] * dx0;
}
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m8(width - x - 1);
vint16m8_t vleft = __riscv_vle16_v_i16m8(trow + x - 1, vl);
vint16m8_t vright = __riscv_vle16_v_i16m8(trow + x + 1, vl);
vint16m8_t vres = __riscv_vsub_vv_i16m8(vright, vleft, vl);
__riscv_vse16_v_i16m8(drow + x, vres, vl);
}
x = width - 1;
drow[x] = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[width - 1] * dx2;
}
}
}
else if (dst_depth == CV_32F)
{
for (int y = start; y < end; ++y)
{
const uint8_t *srow1 = src_data + y * src_step;
const uint8_t *srow0;
const uint8_t *srow2;
if (y != 0)
{
srow0 = src_data + (y - 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
if (y != height - 1)
{
srow2 = src_data + (y + 1) * src_step;
}
else
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
if (y == 0)
{
if (border_type == BORDER_REPLICATE)
{
srow0 = srow1;
}
else
{
srow0 = zero_row.data();
}
}
else if (y == height - 1)
{
if (border_type == BORDER_REPLICATE)
{
srow2 = srow1;
}
else
{
srow2 = zero_row.data();
}
}
size_t vl = 0;
// Vector processing
for (int x = 0; x < width; x += vl)
{
vl = __riscv_vsetvl_e8m4(width - x);
vuint8m4_t vsrow0 = __riscv_vle8_v_u8m4(srow0 + x, vl);
vuint8m4_t vsrow1 = __riscv_vle8_v_u8m4(srow1 + x, vl);
vuint8m4_t vsrow2 = __riscv_vle8_v_u8m4(srow2 + x, vl);
vuint16m8_t vrowx = __riscv_vwmulu_vx_u16m8(vsrow1, dy1, vl);
vuint16m8_t vtemp = __riscv_vwaddu_vv_u16m8(vsrow0, vsrow2, vl);
vrowx = __riscv_vmacc_vx_u16m8(vrowx, dy0, vtemp, vl);
__riscv_vse16_v_i16m8(trow + x, __riscv_vreinterpret_v_u16m8_i16m8(vrowx), vl);
}
int x = 0;
float *drow = (float *)(dst_data + y * dst_step);
drow[x] = trow[0] * dx1 + trow[1] * dx2;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[0] * dx0;
}
x = 1;
for (; x < width - 1; x += vl)
{
vl = __riscv_vsetvl_e16m4(width - x - 1);
vint16m4_t vleft = __riscv_vle16_v_i16m4(trow + x - 1, vl);
vint16m4_t vright = __riscv_vle16_v_i16m4(trow + x + 1, vl);
vint16m4_t vres = __riscv_vsub_vv_i16m4(vright, vleft, vl);
__riscv_vse32_v_f32m8(drow + x, __riscv_vfwcvt_f_x_v_f32m8(vres, vl), vl);
}
x = width - 1;
drow[x] = trow[width - 2] * dx0 + trow[width - 1] * dx1;
if (border_type == BORDER_REPLICATE)
{
drow[x] += trow[width - 1] * dx2;
}
}
}
return CV_HAL_ERROR_OK;
}
class ScharrInvoker : public ParallelLoopBody
{
public:
explicit ScharrInvoker(std::function<int(int, int)> _func)
: func(std::move(_func)) {}
void operator()(const Range &range) const override
{
func(range.start, range.end);
}
private:
std::function<int(int, int)> func;
};
template <typename... Args>
inline int invoke(int height,
int (*f)(int, int, Args...),
Args... args)
{
using namespace std::placeholders;
auto bound = std::bind(f, _1, _2, std::forward<Args>(args)...);
cv::parallel_for_(Range(1, height), ScharrInvoker(bound), cv::getNumThreads());
return f(0, 1, std::forward<Args>(args)...);
}
int scharr(const uint8_t *src_data, size_t src_step,
uint8_t *dst_data, size_t dst_step,
int width, int height,
int src_depth, int dst_depth, int cn,
int margin_left, int margin_top,
int margin_right, int margin_bottom,
int dx, int dy __attribute__((unused)),
double scale, double delta,
int border_type)
{
if (src_depth != CV_8U ||
(dst_depth != CV_8U && dst_depth != CV_16S && dst_depth != CV_32F) ||
cn != 1 || width < 3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (scale != 1 || delta != 0)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (border_type != BORDER_REPLICATE && border_type != BORDER_CONSTANT)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (margin_left != 0 || margin_top != 0 || margin_right != 0 || margin_bottom != 0)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
// This is copied from opencv/modules/imgproc/src/deriv.cpp
// if (!(dx >= 0 && dy >= 0 && dx + dy == 1))
// {
// return CV_HAL_ERROR_NOT_IMPLEMENTED;
// }
int size = 1;
if (dst_depth == CV_16S)
{
size = 2;
}
else if (dst_depth == CV_32F)
{
size = 4;
}
std::vector<uint8_t> temp_buffer;
uint8_t *actual_dst_data = dst_data;
if (src_data == dst_data)
{
temp_buffer.resize(height * dst_step);
actual_dst_data = temp_buffer.data();
}
int res = invoke(height,
dx == 1 ? &scharr_dx1 : &scharr_dx0,
src_data, src_step,
actual_dst_data, dst_step,
width, height,
src_depth, dst_depth, cn,
margin_left, margin_top,
margin_right, margin_bottom,
scale, delta,
border_type);
if (src_data == dst_data && res == CV_HAL_ERROR_OK)
{
for (int y = 0; y < height; ++y)
{
memcpy(dst_data + y * dst_step,
actual_dst_data + y * dst_step,
width * size);
}
}
return res;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}
}
} // cv::rvv_hal::imgproc
+259
View File
@@ -0,0 +1,259 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
struct sepFilter2D
{
int src_type;
int dst_type;
int kernel_type;
const uchar* kernelx_data;
int kernelx_length;
const uchar* kernely_data;
int kernely_length;
int anchor_x;
int anchor_y;
double delta;
int borderType;
};
// the algorithm is copied from 3rdparty/carotene/src/separable_filter.hpp,
// in the functor RowFilter3x3S16Generic and ColFilter3x3S16Generic
template<int ksize, typename T>
static inline int sepFilter(int start, int end, sepFilter2D* data, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
{
constexpr int noval = std::numeric_limits<int>::max();
auto accessX = [&](int x) {
int pi;
if (data->borderType & BORDER_ISOLATED)
{
pi = common::borderInterpolate(x - data->anchor_y, height, data->borderType & ~BORDER_ISOLATED);
pi = pi < 0 ? noval : pi;
}
else
{
pi = common::borderInterpolate(offset_y + x - data->anchor_y, full_height, data->borderType);
pi = pi < 0 ? noval : pi - offset_y;
}
return pi;
};
auto accessY = [&](int y) {
int pj;
if (data->borderType & BORDER_ISOLATED)
{
pj = common::borderInterpolate(y - data->anchor_x, width, data->borderType & ~BORDER_ISOLATED);
pj = pj < 0 ? noval : pj;
}
else
{
pj = common::borderInterpolate(offset_x + y - data->anchor_x, full_width, data->borderType);
pj = pj < 0 ? noval : pj - offset_x;
}
return pj;
};
auto p2idx = [&](int x, int y){ return (x + ksize) % ksize * width + y; };
const float* kx = reinterpret_cast<const float*>(data->kernelx_data);
const float* ky = reinterpret_cast<const float*>(data->kernely_data);
std::vector<float> res(width * ksize);
auto process = [&](int x, int y) {
float sum = 0;
for (int i = 0; i < ksize; i++)
{
int p = accessY(y + i);
if (p != noval)
{
sum += kx[i] * reinterpret_cast<const T*>(src_data + x * src_step)[p];
}
}
res[p2idx(x, y)] = sum;
};
const int left = data->anchor_x, right = width - (ksize - 1 - data->anchor_x);
for (int i = start - data->anchor_y; i < end + (ksize - 1 - data->anchor_y); i++)
{
if (i + offset_y >= 0 && i + offset_y < full_height)
{
if (left >= right)
{
for (int j = 0; j < width; j++)
process(i, j);
}
else
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m2(right - j);
const T* extra = reinterpret_cast<const T*>(src_data + i * src_step) + j - data->anchor_x;
vfloat32m8_t src;
if (std::is_same<T, uchar>::value)
{
src = __riscv_vfwcvt_f(__riscv_vwcvtu_x(__riscv_vle8_v_u8m2(reinterpret_cast<const uchar*>(extra), vl), vl), vl);
}
else if (std::is_same<T, short>::value)
{
src = __riscv_vfwcvt_f(__riscv_vle16_v_i16m4(reinterpret_cast<const short*>(extra), vl), vl);
}
else
{
src = __riscv_vle32_v_f32m8(reinterpret_cast<const float*>(extra), vl);
}
extra += vl;
auto sum = __riscv_vfmul(src, kx[0], vl);
src = __riscv_vfslide1down(src, extra[0], vl);
sum = __riscv_vfmacc(sum, kx[1], src, vl);
src = __riscv_vfslide1down(src, extra[1], vl);
sum = __riscv_vfmacc(sum, kx[2], src, vl);
if (ksize == 5)
{
src = __riscv_vfslide1down(src, extra[2], vl);
sum = __riscv_vfmacc(sum, kx[3], src, vl);
src = __riscv_vfslide1down(src, extra[3], vl);
sum = __riscv_vfmacc(sum, kx[4], src, vl);
}
__riscv_vse32(res.data() + p2idx(i, j), sum, vl);
}
}
}
int cur = i - (ksize - 1 - data->anchor_y);
if (cur >= start)
{
const float* row0 = accessX(cur ) == noval ? nullptr : res.data() + p2idx(accessX(cur ), 0);
const float* row1 = accessX(cur + 1) == noval ? nullptr : res.data() + p2idx(accessX(cur + 1), 0);
const float* row2 = accessX(cur + 2) == noval ? nullptr : res.data() + p2idx(accessX(cur + 2), 0);
const float* row3 = nullptr, *row4 = nullptr;
if (ksize == 5)
{
row3 = accessX(cur + 3) == noval ? nullptr : res.data() + p2idx(accessX(cur + 3), 0);
row4 = accessX(cur + 4) == noval ? nullptr : res.data() + p2idx(accessX(cur + 4), 0);
}
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m4(width - j);
auto v0 = row0 ? __riscv_vle32_v_f32m4(row0 + j, vl) : __riscv_vfmv_v_f_f32m4(0, vl);
auto v1 = row1 ? __riscv_vle32_v_f32m4(row1 + j, vl) : __riscv_vfmv_v_f_f32m4(0, vl);
auto v2 = row2 ? __riscv_vle32_v_f32m4(row2 + j, vl) : __riscv_vfmv_v_f_f32m4(0, vl);
auto sum = __riscv_vfmacc(__riscv_vfmacc(__riscv_vfmacc(__riscv_vfmv_v_f_f32m4(data->delta, vl), ky[0], v0, vl), ky[1], v1, vl), ky[2], v2, vl);
if (ksize == 5)
{
auto v3 = row3 ? __riscv_vle32_v_f32m4(row3 + j, vl) : __riscv_vfmv_v_f_f32m4(0, vl);
auto v4 = row4 ? __riscv_vle32_v_f32m4(row4 + j, vl) : __riscv_vfmv_v_f_f32m4(0, vl);
sum = __riscv_vfmacc(__riscv_vfmacc(sum, ky[3], v3, vl), ky[4], v4, vl);
}
if (data->dst_type == CV_16SC1)
{
__riscv_vse16(reinterpret_cast<short*>(dst_data + cur * dst_step) + j, __riscv_vfncvt_x(sum, vl), vl);
}
else
{
__riscv_vse32(reinterpret_cast<float*>(dst_data + cur * dst_step) + j, sum, vl);
}
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int sepFilterInit(cvhalFilter2D **context, int src_type, int dst_type, int kernel_type, uchar* kernelx_data, int kernelx_length, uchar* kernely_data, int kernely_length, int anchor_x, int anchor_y, double delta, int borderType)
{
if (kernel_type != CV_32FC1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_type != CV_8UC1 && src_type != CV_16SC1 && src_type != CV_32FC1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (dst_type != CV_16SC1 && dst_type != CV_32FC1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((kernelx_length != 3 && kernelx_length != 5) || kernelx_length != kernely_length)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((borderType & ~BORDER_ISOLATED) == BORDER_WRAP)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
anchor_x = anchor_x < 0 ? kernelx_length / 2 : anchor_x;
anchor_y = anchor_y < 0 ? kernely_length / 2 : anchor_y;
*context = reinterpret_cast<cvhalFilter2D*>(new sepFilter2D{src_type, dst_type, kernel_type, kernelx_data, kernelx_length, kernely_data, kernely_length, anchor_x, anchor_y, delta, borderType & ~BORDER_ISOLATED});
return CV_HAL_ERROR_OK;
}
int sepFilter(cvhalFilter2D *context, uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int full_width, int full_height, int offset_x, int offset_y)
{
sepFilter2D* data = reinterpret_cast<sepFilter2D*>(context);
uchar* _dst_data = dst_data;
size_t _dst_step = dst_step;
const size_t size = CV_ELEM_SIZE(data->dst_type);
std::vector<uchar> dst;
if (src_data == _dst_data)
{
dst = std::vector<uchar>(width * height * size);
dst_data = dst.data();
dst_step = width * size;
}
int res = CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (data->kernelx_length*100 + data->src_type)
{
case 300 + CV_8UC1:
res = common::invoke(height, {sepFilter<3, uchar>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
case 500 + CV_8UC1:
res = common::invoke(height, {sepFilter<5, uchar>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
case 300 + CV_16SC1:
res = common::invoke(height, {sepFilter<3, short>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
case 500 + CV_16SC1:
res = common::invoke(height, {sepFilter<5, short>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
case 300 + CV_32FC1:
res = common::invoke(height, {sepFilter<3, float>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
case 500 + CV_32FC1:
res = common::invoke(height, {sepFilter<5, float>}, data, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
break;
}
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (src_data == _dst_data)
{
for (int i = 0; i < height; i++)
memcpy(_dst_data + i * _dst_step, dst.data() + i * dst_step, dst_step);
}
return res;
}
int sepFilterFree(cvhalFilter2D* context)
{
delete reinterpret_cast<sepFilter2D*>(context);
return CV_HAL_ERROR_OK;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,254 @@
// 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.
#include "rvv_hal.hpp"
#include "common.hpp"
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
static inline vint16m2_t widen_u8_to_i16(vuint8m1_t v, size_t vl)
{
vuint16m2_t widened = __riscv_vzext_vf2(v, vl);
return __riscv_vreinterpret_v_u16m2_i16m2(widened);
}
static inline void spatialGradientKernel(int16_t& dx, int16_t& dy,
int16_t v00, int16_t v01, int16_t v02,
int16_t v10, int16_t v12,
int16_t v20, int16_t v21, int16_t v22)
{
int16_t tmp_add = v22 - v00;
int16_t tmp_sub = v02 - v20;
int16_t tmp_x = v12 - v10;
int16_t tmp_y = v21 - v01;
dx = tmp_add + tmp_sub + tmp_x + tmp_x;
dy = tmp_add - tmp_sub + tmp_y + tmp_y;
}
static inline void loadRow3(const uint8_t* row, int x, size_t vl,
vint16m2_t& m, vint16m2_t& n, vint16m2_t& p)
{
m = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x - 1, vl), vl);
n = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x, vl), vl);
p = widen_u8_to_i16(__riscv_vle8_v_u8m1(row + x + 1, vl), vl);
}
static inline void spatialGradientKernelVec(vint16m2_t& vdx, vint16m2_t& vdy,
const vint16m2_t& v_s1m,
const vint16m2_t& v_s1n,
const vint16m2_t& v_s1p,
const vint16m2_t& v_s2m,
const vint16m2_t& v_s2p,
const vint16m2_t& v_s3m,
const vint16m2_t& v_s3n,
const vint16m2_t& v_s3p,
size_t vl)
{
// vdx = (v_s3p - v_s1m) + (v_s1p - v_s3m) + 2 * (v_s2p - v_s2m)
// vdy = (v_s3p - v_s1m) - (v_s1p - v_s3m) + 2 * (v_s3n - v_s1n)
vint16m2_t tmp_add = __riscv_vsub_vv_i16m2(v_s3p, v_s1m, vl);
vint16m2_t tmp_sub = __riscv_vsub_vv_i16m2(v_s1p, v_s3m, vl);
vint16m2_t tmp_x = __riscv_vsub_vv_i16m2(v_s2p, v_s2m, vl);
vint16m2_t tmp_y = __riscv_vsub_vv_i16m2(v_s3n, v_s1n, vl);
vdx = __riscv_vadd_vv_i16m2(tmp_add, tmp_sub, vl);
vdx = __riscv_vadd_vv_i16m2(vdx, tmp_x, vl);
vdx = __riscv_vadd_vv_i16m2(vdx, tmp_x, vl);
vdy = __riscv_vsub_vv_i16m2(tmp_add, tmp_sub, vl);
vdy = __riscv_vadd_vv_i16m2(vdy, tmp_y, vl);
vdy = __riscv_vadd_vv_i16m2(vdy, tmp_y, vl);
}
static inline void processBorderPixels(const uint8_t* p_src,
const uint8_t* c_src,
const uint8_t* n_src,
int16_t* c_dx,
int16_t* c_dy,
int width,
int j_offl,
int j_offr)
{
int j = 0;
int j_p = j + j_offl;
int j_n = 1;
if (j_n >= width)
j_n = j + j_offr;
int16_t v00 = p_src[j_p], v01 = p_src[j], v02 = p_src[j_n];
int16_t v10 = c_src[j_p], v12 = c_src[j_n];
int16_t v20 = n_src[j_p], v21 = n_src[j], v22 = n_src[j_n];
spatialGradientKernel(c_dx[j], c_dy[j], v00, v01, v02, v10, v12, v20, v21, v22);
if (width > 1)
{
j = width - 1;
j_p = j - 1;
j_n = j + j_offr;
v00 = p_src[j_p]; v01 = p_src[j]; v02 = p_src[j_n];
v10 = c_src[j_p]; v12 = c_src[j_n];
v20 = n_src[j_p]; v21 = n_src[j]; v22 = n_src[j_n];
spatialGradientKernel(c_dx[j], c_dy[j], v00, v01, v02, v10, v12, v20, v21, v22);
}
}
// Characters in variable names have the following meanings:
// m: offset -1
// n: offset 0
// p: offset 1
static int spatialGradient_row(int start, int end,
const uint8_t* src_data, size_t src_step,
int16_t* dx_data, size_t dx_step,
int16_t* dy_data, size_t dy_step,
int width, int height,
int border_type)
{
int i_top = 0;
int i_bottom = height - 1;
int j_offl = 0;
int j_offr = 0;
if (border_type == BORDER_DEFAULT)
{
if (height > 1)
{
i_top = 1;
i_bottom = height - 2;
}
if (width > 1)
{
j_offl = 1;
j_offr = -1;
}
}
int y = start;
for (; y + 1 < end; y += 2)
{
const uint8_t* p_src = src_data + (y == 0 ? i_top : y - 1) * src_step;
const uint8_t* c_src = src_data + y * src_step;
const uint8_t* n_src = src_data + (y + 1) * src_step;
const uint8_t* m_src = src_data + (y == height - 2 ? i_bottom : y + 2) * src_step;
int16_t* c_dx = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dx_data) + y * dx_step);
int16_t* c_dy = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dy_data) + y * dy_step);
int16_t* n_dx = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dx_data) + (y + 1) * dx_step);
int16_t* n_dy = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dy_data) + (y + 1) * dy_step);
processBorderPixels(p_src, c_src, n_src, c_dx, c_dy, width, j_offl, j_offr);
processBorderPixels(c_src, n_src, m_src, n_dx, n_dy, width, j_offl, j_offr);
// Process rest of columns
int x = 1;
const int last = width - 1;
while (x < last)
{
size_t vl = __riscv_vsetvl_e8m1((size_t)(last - x));
vint16m2_t v_s1m, v_s1n, v_s1p;
vint16m2_t v_s2m, v_s2n, v_s2p;
vint16m2_t v_s3m, v_s3n, v_s3p;
loadRow3(p_src, x, vl, v_s1m, v_s1n, v_s1p);
loadRow3(c_src, x, vl, v_s2m, v_s2n, v_s2p);
loadRow3(n_src, x, vl, v_s3m, v_s3n, v_s3p);
vint16m2_t vdx, vdy;
spatialGradientKernelVec(vdx, vdy,
v_s1m, v_s1n, v_s1p,
v_s2m, v_s2p,
v_s3m, v_s3n, v_s3p, vl);
__riscv_vse16_v_i16m2(c_dx + x, vdx, vl);
__riscv_vse16_v_i16m2(c_dy + x, vdy, vl);
vint16m2_t v_s4m, v_s4n, v_s4p;
loadRow3(m_src, x, vl, v_s4m, v_s4n, v_s4p);
spatialGradientKernelVec(vdx, vdy,
v_s2m, v_s2n, v_s2p,
v_s3m, v_s3p,
v_s4m, v_s4n, v_s4p, vl);
__riscv_vse16_v_i16m2(n_dx + x, vdx, vl);
__riscv_vse16_v_i16m2(n_dy + x, vdy, vl);
x += (int)vl;
}
}
for (; y < end; ++y)
{
const uint8_t* p_src = src_data + (y == 0 ? i_top : y - 1) * src_step;
const uint8_t* c_src = src_data + y * src_step;
const uint8_t* n_src = src_data + (y == height - 1 ? i_bottom : y + 1) * src_step;
int16_t* c_dx = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dx_data) + y * dx_step);
int16_t* c_dy = reinterpret_cast<int16_t*>(
reinterpret_cast<uint8_t*>(dy_data) + y * dy_step);
processBorderPixels(p_src, c_src, n_src, c_dx, c_dy, width, j_offl, j_offr);
int x = 1;
const int last = width - 1;
while (x < last)
{
size_t vl = __riscv_vsetvl_e8m1((size_t)(last - x));
vint16m2_t v_s1m, v_s1n, v_s1p;
vint16m2_t v_s2m, v_s2p;
vint16m2_t v_s3m, v_s3n, v_s3p;
loadRow3(p_src, x, vl, v_s1m, v_s1n, v_s1p);
v_s2m = widen_u8_to_i16(__riscv_vle8_v_u8m1(c_src + x - 1, vl), vl);
v_s2p = widen_u8_to_i16(__riscv_vle8_v_u8m1(c_src + x + 1, vl), vl);
loadRow3(n_src, x, vl, v_s3m, v_s3n, v_s3p);
vint16m2_t vdx, vdy;
spatialGradientKernelVec(vdx, vdy,
v_s1m, v_s1n, v_s1p,
v_s2m, v_s2p,
v_s3m, v_s3n, v_s3p, vl);
__riscv_vse16_v_i16m2(c_dx + x, vdx, vl);
__riscv_vse16_v_i16m2(c_dy + x, vdy, vl);
x += (int)vl;
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous namespace
int spatialGradient(const uint8_t* src_data, size_t src_step,
int16_t* dx_data, size_t dx_step,
int16_t* dy_data, size_t dy_step,
int width, int height,
int ksize, int border_type)
{
if (ksize != 3)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (border_type != BORDER_REPLICATE && border_type != BORDER_DEFAULT)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (width < 1 || height < 1)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
return common::invoke(height, {spatialGradient_row},
src_data, src_step,
dx_data, dx_step,
dy_data, dy_step,
width, height, border_type);
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} // cv::rvv_hal::imgproc
+470
View File
@@ -0,0 +1,470 @@
// 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.
// Copyright (C) 2025, Institute of Software, Chinese Academy of Sciences.
#include "rvv_hal.hpp"
#include "common.hpp"
#include <atomic>
namespace cv { namespace rvv_hal { namespace imgproc {
#if CV_HAL_RVV_1P0_ENABLED
namespace {
class ThresholdInvoker : public ParallelLoopBody
{
public:
template<typename... Args>
ThresholdInvoker(std::function<int(int, int, Args...)> _func, Args&&... args)
{
func = std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::forward<Args>(args)...);
}
virtual void operator()(const Range& range) const override
{
func(range.start, range.end);
}
private:
std::function<int(int, int)> func;
};
template<typename... Args>
static inline int invoke(int width, int height, std::function<int(int, int, Args...)> func, Args&&... args)
{
cv::parallel_for_(Range(1, height), ThresholdInvoker(func, std::forward<Args>(args)...), static_cast<double>((width - 1) * height) / (1 << 15));
return func(0, 1, std::forward<Args>(args)...);
}
template<typename T> struct rvv;
template<> struct rvv<uchar>
{
static inline vuint8m4_t vmerge(vuint8m4_t a, uchar b, vbool2_t c, size_t d) { return __riscv_vmerge(a, b, c, d); }
};
template<> struct rvv<short>
{
static inline vint16m4_t vmerge(vint16m4_t a, short b, vbool4_t c, size_t d) { return __riscv_vmerge(a, b, c, d); }
};
template<> struct rvv<float>
{
static inline vfloat32m4_t vmerge(vfloat32m4_t a, float b, vbool8_t c, size_t d) { return __riscv_vfmerge(a, b, c, d); }
};
template<> struct rvv<double>
{
static inline vfloat64m4_t vmerge(vfloat64m4_t a, double b, vbool16_t c, size_t d) { return __riscv_vfmerge(a, b, c, d); }
};
// the algorithm is copied from imgproc/src/thresh.cpp,
// in the functor ThresholdRunner
template<typename helper, int type, typename T = typename helper::ElemType>
static inline int threshold(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, T tval, T mval)
{
auto zero = helper::vmv(0, helper::setvlmax());
for (int i = start; i < end; i++)
{
const T* src = reinterpret_cast<const T*>(src_data + i * src_step);
T* dst = reinterpret_cast<T*>(dst_data + i * dst_step);
int vl0, vl1;
for (int j = 0; j < width; j += vl0 + vl1)
{
vl0 = helper::setvl(width - j);
vl1 = helper::setvl(width - j - vl0);
auto src0 = helper::vload(src + j, vl0);
auto src1 = helper::vload(src + j + vl0, vl1);
typename helper::VecType dst0, dst1;
switch (type)
{
case CV_HAL_THRESH_BINARY:
dst0 = rvv<T>::vmerge(zero, mval, helper::vmgt(src0, tval, vl0), vl0);
dst1 = rvv<T>::vmerge(zero, mval, helper::vmgt(src1, tval, vl1), vl1);
break;
case CV_HAL_THRESH_BINARY_INV:
dst0 = rvv<T>::vmerge(zero, mval, helper::vmle(src0, tval, vl0), vl0);
dst1 = rvv<T>::vmerge(zero, mval, helper::vmle(src1, tval, vl1), vl1);
break;
case CV_HAL_THRESH_TRUNC:
dst0 = rvv<T>::vmerge(src0, tval, helper::vmgt(src0, tval, vl0), vl0);
dst1 = rvv<T>::vmerge(src1, tval, helper::vmgt(src1, tval, vl1), vl1);
break;
case CV_HAL_THRESH_TOZERO:
dst0 = rvv<T>::vmerge(src0, 0, helper::vmle(src0, tval, vl0), vl0);
dst1 = rvv<T>::vmerge(src1, 0, helper::vmle(src1, tval, vl1), vl1);
break;
case CV_HAL_THRESH_TOZERO_INV:
dst0 = rvv<T>::vmerge(src0, 0, helper::vmgt(src0, tval, vl0), vl0);
dst1 = rvv<T>::vmerge(src1, 0, helper::vmgt(src1, tval, vl1), vl1);
break;
}
helper::vstore(dst + j, dst0, vl0);
helper::vstore(dst + j + vl0, dst1, vl1);
}
}
return CV_HAL_ERROR_OK;
}
static inline int threshold_range(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int depth, int cn, double thresh, double maxValue, int thresholdType)
{
auto saturate_8u = [](double x){ return static_cast<uchar>(std::min(std::max(x, static_cast<double>(std::numeric_limits<uchar>::lowest())), static_cast<double>(std::numeric_limits<uchar>::max()))); };
auto saturate_16s = [](double x){ return static_cast<short>(std::min(std::max(x, static_cast<double>(std::numeric_limits<short>::lowest())), static_cast<double>(std::numeric_limits<short>::max()))); };
width *= cn;
switch (depth)
{
case CV_8U:
switch (thresholdType)
{
case CV_HAL_THRESH_BINARY:
return threshold<RVV_U8M4, CV_HAL_THRESH_BINARY>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_8u(std::floor(thresh)), saturate_8u(std::round(maxValue)));
case CV_HAL_THRESH_BINARY_INV:
return threshold<RVV_U8M4, CV_HAL_THRESH_BINARY_INV>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_8u(std::floor(thresh)), saturate_8u(std::round(maxValue)));
case CV_HAL_THRESH_TRUNC:
return threshold<RVV_U8M4, CV_HAL_THRESH_TRUNC>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_8u(std::floor(thresh)), saturate_8u(std::round(maxValue)));
case CV_HAL_THRESH_TOZERO:
return threshold<RVV_U8M4, CV_HAL_THRESH_TOZERO>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_8u(std::floor(thresh)), saturate_8u(std::round(maxValue)));
case CV_HAL_THRESH_TOZERO_INV:
return threshold<RVV_U8M4, CV_HAL_THRESH_TOZERO_INV>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_8u(std::floor(thresh)), saturate_8u(std::round(maxValue)));
}
break;
case CV_16S:
switch (thresholdType)
{
case CV_HAL_THRESH_BINARY:
return threshold<RVV_I16M4, CV_HAL_THRESH_BINARY>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_16s(std::floor(thresh)), saturate_16s(std::round(maxValue)));
case CV_HAL_THRESH_BINARY_INV:
return threshold<RVV_I16M4, CV_HAL_THRESH_BINARY_INV>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_16s(std::floor(thresh)), saturate_16s(std::round(maxValue)));
case CV_HAL_THRESH_TRUNC:
return threshold<RVV_I16M4, CV_HAL_THRESH_TRUNC>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_16s(std::floor(thresh)), saturate_16s(std::round(maxValue)));
case CV_HAL_THRESH_TOZERO:
return threshold<RVV_I16M4, CV_HAL_THRESH_TOZERO>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_16s(std::floor(thresh)), saturate_16s(std::round(maxValue)));
case CV_HAL_THRESH_TOZERO_INV:
return threshold<RVV_I16M4, CV_HAL_THRESH_TOZERO_INV>(start, end, src_data, src_step, dst_data, dst_step, width, saturate_16s(std::floor(thresh)), saturate_16s(std::round(maxValue)));
}
break;
case CV_32F:
switch (thresholdType)
{
case CV_HAL_THRESH_BINARY:
return threshold<RVV_F32M4, CV_HAL_THRESH_BINARY>(start, end, src_data, src_step, dst_data, dst_step, width, static_cast<float>(thresh), static_cast<float>(maxValue));
case CV_HAL_THRESH_BINARY_INV:
return threshold<RVV_F32M4, CV_HAL_THRESH_BINARY_INV>(start, end, src_data, src_step, dst_data, dst_step, width, static_cast<float>(thresh), static_cast<float>(maxValue));
case CV_HAL_THRESH_TRUNC:
return threshold<RVV_F32M4, CV_HAL_THRESH_TRUNC>(start, end, src_data, src_step, dst_data, dst_step, width, static_cast<float>(thresh), static_cast<float>(maxValue));
case CV_HAL_THRESH_TOZERO:
return threshold<RVV_F32M4, CV_HAL_THRESH_TOZERO>(start, end, src_data, src_step, dst_data, dst_step, width, static_cast<float>(thresh), static_cast<float>(maxValue));
case CV_HAL_THRESH_TOZERO_INV:
return threshold<RVV_F32M4, CV_HAL_THRESH_TOZERO_INV>(start, end, src_data, src_step, dst_data, dst_step, width, static_cast<float>(thresh), static_cast<float>(maxValue));
}
break;
case CV_64F:
switch (thresholdType)
{
case CV_HAL_THRESH_BINARY:
return threshold<RVV_F64M4, CV_HAL_THRESH_BINARY>(start, end, src_data, src_step, dst_data, dst_step, width, thresh, maxValue);
case CV_HAL_THRESH_BINARY_INV:
return threshold<RVV_F64M4, CV_HAL_THRESH_BINARY_INV>(start, end, src_data, src_step, dst_data, dst_step, width, thresh, maxValue);
case CV_HAL_THRESH_TRUNC:
return threshold<RVV_F64M4, CV_HAL_THRESH_TRUNC>(start, end, src_data, src_step, dst_data, dst_step, width, thresh, maxValue);
case CV_HAL_THRESH_TOZERO:
return threshold<RVV_F64M4, CV_HAL_THRESH_TOZERO>(start, end, src_data, src_step, dst_data, dst_step, width, thresh, maxValue);
case CV_HAL_THRESH_TOZERO_INV:
return threshold<RVV_F64M4, CV_HAL_THRESH_TOZERO_INV>(start, end, src_data, src_step, dst_data, dst_step, width, thresh, maxValue);
}
break;
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
static inline int otsu(int start, int end, const uchar* src_data, size_t src_step, int width, std::atomic<int>* cnt, int N, int* h)
{
const int c = cnt->fetch_add(1) % cv::getNumThreads();
h += c * N;
for (int i = start; i < end; i++)
{
for (int j = 0; j < width; j++)
h[src_data[i * src_step + j]]++;
}
return CV_HAL_ERROR_OK;
}
// the algorithm is copied from imgproc/src/thresh.cpp,
// in the function void cv::adaptiveThreshold
template<int ksize, int method, int type>
static inline int adaptiveThreshold(int start, int end, const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, double maxValue, double C)
{
auto saturate = [](double x){ return static_cast<uchar>(std::min(std::max(x, static_cast<double>(std::numeric_limits<uchar>::lowest())), static_cast<double>(std::numeric_limits<uchar>::max()))); };
uchar mval = saturate(std::round(maxValue));
if (method == CV_HAL_ADAPTIVE_THRESH_MEAN_C)
{
int cval = static_cast<int>(std::round(C));
if (cval != C)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
std::vector<short> res(width * ksize);
auto process = [&](int x, int y) {
int sum = 0;
for (int i = 0; i < ksize; i++)
{
int q = std::min(std::max(y + i - ksize / 2, 0), width - 1);
sum += src_data[x * src_step + q];
}
res[(x % ksize) * width + y] = sum;
};
const int left = ksize - 1, right = width - (ksize - 1);
for (int i = start - ksize / 2; i < end + ksize / 2; i++)
{
if (i >= 0 && i < height)
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m4(right - j);
const uchar* row = src_data + i * src_step + j - ksize / 2;
auto src = __riscv_vreinterpret_v_u16m8_i16m8(__riscv_vzext_vf2(__riscv_vle8_v_u8m4(row, vl), vl));
auto sum = src;
src = __riscv_vslide1down(src, row[vl], vl);
sum = __riscv_vadd(sum, src, vl);
src = __riscv_vslide1down(src, row[vl + 1], vl);
sum = __riscv_vadd(sum, src, vl);
if (ksize == 5)
{
src = __riscv_vslide1down(src, row[vl + 2], vl);
sum = __riscv_vadd(sum, src, vl);
src = __riscv_vslide1down(src, row[vl + 3], vl);
sum = __riscv_vadd(sum, src, vl);
}
__riscv_vse16(res.data() + (i % ksize) * width + j, sum, vl);
}
}
int cur = i - ksize / 2;
if (cur >= start)
{
const short* row0 = res.data() + std::min(std::max(cur - ksize / 2, 0), height - 1) % ksize * width;
const short* row1 = res.data() + std::min(std::max(cur + 1 - ksize / 2, 0), height - 1) % ksize * width;
const short* row2 = res.data() + std::min(std::max(cur + 2 - ksize / 2, 0), height - 1) % ksize * width;
const short* row3 = res.data() + std::min(std::max(cur + 3 - ksize / 2, 0), height - 1) % ksize * width;
const short* row4 = res.data() + std::min(std::max(cur + 4 - ksize / 2, 0), height - 1) % ksize * width;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e16m8(width - j);
auto sum = __riscv_vle16_v_i16m8(row0 + j, vl);
sum = __riscv_vadd(sum, __riscv_vle16_v_i16m8(row1 + j, vl), vl);
sum = __riscv_vadd(sum, __riscv_vle16_v_i16m8(row2 + j, vl), vl);
if (ksize == 5)
{
sum = __riscv_vadd(sum, __riscv_vle16_v_i16m8(row3 + j, vl), vl);
sum = __riscv_vadd(sum, __riscv_vle16_v_i16m8(row4 + j, vl), vl);
}
auto mean = __riscv_vsub(__riscv_vdiv(sum, ksize * ksize, vl), cval, vl);
auto cmp = __riscv_vmsgt(__riscv_vreinterpret_v_u16m8_i16m8(__riscv_vzext_vf2(__riscv_vle8_v_u8m4(src_data + cur * src_step + j, vl), vl)), mean, vl);
if (type == CV_HAL_THRESH_BINARY)
{
__riscv_vse8(dst_data + cur * dst_step + j, __riscv_vmerge(__riscv_vmv_v_x_u8m4(0, vl), mval, cmp, vl), vl);
}
else
{
__riscv_vse8(dst_data + cur * dst_step + j, __riscv_vmerge(__riscv_vmv_v_x_u8m4(mval, vl), 0, cmp, vl), vl);
}
}
}
}
}
else
{
constexpr float kernel[2][5] = {{0.25f, 0.5f, 0.25f}, {0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f}};
std::vector<float> res(width * ksize);
auto process = [&](int x, int y) {
float sum = 0;
for (int i = 0; i < ksize; i++)
{
int q = std::min(std::max(y + i - ksize / 2, 0), width - 1);
sum += kernel[ksize == 5][i] * src_data[x * src_step + q];
}
res[(x % ksize) * width + y] = sum;
};
const int left = ksize - 1, right = width - (ksize - 1);
for (int i = start - ksize / 2; i < end + ksize / 2; i++)
{
if (i >= 0 && i < height)
{
for (int j = 0; j < left; j++)
process(i, j);
for (int j = right; j < width; j++)
process(i, j);
int vl;
for (int j = left; j < right; j += vl)
{
vl = __riscv_vsetvl_e8m2(right - j);
const uchar* row = src_data + i * src_step + j - ksize / 2;
auto src = __riscv_vfwcvt_f(__riscv_vzext_vf2(__riscv_vle8_v_u8m2(row, vl), vl), vl);
auto sum = __riscv_vfmul(src, kernel[ksize == 5][0], vl);
src = __riscv_vfslide1down(src, row[vl], vl);
sum = __riscv_vfmacc(sum, kernel[ksize == 5][1], src, vl);
src = __riscv_vfslide1down(src, row[vl + 1], vl);
sum = __riscv_vfmacc(sum, kernel[ksize == 5][2], src, vl);
if (ksize == 5)
{
src = __riscv_vfslide1down(src, row[vl + 2], vl);
sum = __riscv_vfmacc(sum, kernel[1][3], src, vl);
src = __riscv_vfslide1down(src, row[vl + 3], vl);
sum = __riscv_vfmacc(sum, kernel[1][4], src, vl);
}
__riscv_vse32(res.data() + (i % ksize) * width + j, sum, vl);
}
}
int cur = i - ksize / 2;
if (cur >= start)
{
const float* row0 = res.data() + std::min(std::max(cur - ksize / 2, 0), height - 1) % ksize * width;
const float* row1 = res.data() + std::min(std::max(cur + 1 - ksize / 2, 0), height - 1) % ksize * width;
const float* row2 = res.data() + std::min(std::max(cur + 2 - ksize / 2, 0), height - 1) % ksize * width;
const float* row3 = res.data() + std::min(std::max(cur + 3 - ksize / 2, 0), height - 1) % ksize * width;
const float* row4 = res.data() + std::min(std::max(cur + 4 - ksize / 2, 0), height - 1) % ksize * width;
int vl;
for (int j = 0; j < width; j += vl)
{
vl = __riscv_vsetvl_e32m8(width - j);
auto sum = __riscv_vfmv_v_f_f32m8(-C, vl);
sum = __riscv_vfmacc(sum, kernel[ksize == 5][0], __riscv_vle32_v_f32m8(row0 + j, vl), vl);
sum = __riscv_vfmacc(sum, kernel[ksize == 5][1], __riscv_vle32_v_f32m8(row1 + j, vl), vl);
sum = __riscv_vfmacc(sum, kernel[ksize == 5][2], __riscv_vle32_v_f32m8(row2 + j, vl), vl);
if (ksize == 5)
{
sum = __riscv_vfmacc(sum, kernel[1][3], __riscv_vle32_v_f32m8(row3 + j, vl), vl);
sum = __riscv_vfmacc(sum, kernel[1][4], __riscv_vle32_v_f32m8(row4 + j, vl), vl);
}
auto mean = __riscv_vnclipu(__riscv_vfncvt_rtz_xu(sum, vl), 0, __RISCV_VXRM_RNU, vl);
auto cmp = __riscv_vmsgtu(__riscv_vle8_v_u8m2(src_data + cur * src_step + j, vl), mean, vl);
if (type == CV_HAL_THRESH_BINARY)
{
__riscv_vse8(dst_data + cur * dst_step + j, __riscv_vmerge(__riscv_vmv_v_x_u8m2(0, vl), mval, cmp, vl), vl);
}
else
{
__riscv_vse8(dst_data + cur * dst_step + j, __riscv_vmerge(__riscv_vmv_v_x_u8m2(mval, vl), 0, cmp, vl), vl);
}
}
}
}
}
return CV_HAL_ERROR_OK;
}
} // anonymous
int threshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, int cn, double thresh, double maxValue, int thresholdType)
{
return threshold_range(0, height, src_data, src_step, dst_data, dst_step, width, depth, cn, thresh, maxValue, thresholdType);
}
// the algorithm is copied from imgproc/src/thresh.cpp,
// in the function template static double getThreshVal_Otsu
int threshold_otsu(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, int depth, double maxValue, int thresholdType, double* thresh)
{
if (depth != CV_8UC1 || width * height < (1 << 15))
return CV_HAL_ERROR_NOT_IMPLEMENTED;
const int N = std::numeric_limits<uchar>::max() + 1;
const int nums = cv::getNumThreads();
std::vector<int> _h(N * nums, 0);
int* h = _h.data();
std::atomic<int> cnt(0);
cv::parallel_for_(Range(0, height), ThresholdInvoker({otsu}, src_data, src_step, width, &cnt, N, h), nums);
for (int i = N; i < nums * N; i++)
{
h[i % N] += h[i];
}
double mu = 0, scale = 1. / (width*height);
for (int i = 0; i < N; i++)
{
mu += i*(double)h[i];
}
mu *= scale;
double mu1 = 0, q1 = 0;
double max_sigma = 0, max_val = 0;
for (int i = 0; i < N; i++)
{
double p_i, q2, mu2, sigma;
p_i = h[i]*scale;
mu1 *= q1;
q1 += p_i;
q2 = 1. - q1;
if (std::min(q1,q2) < FLT_EPSILON || std::max(q1,q2) > 1. - FLT_EPSILON)
continue;
mu1 = (mu1 + i*p_i)/q1;
mu2 = (mu - q1*mu1)/q2;
sigma = q1*q2*(mu1 - mu2)*(mu1 - mu2);
if (sigma > max_sigma)
{
max_sigma = sigma;
max_val = i;
}
}
*thresh = max_val;
if (dst_data == nullptr)
return CV_HAL_ERROR_OK;
return invoke(width, height, {threshold_range}, src_data, src_step, dst_data, dst_step, width, depth, 1, max_val, maxValue, thresholdType);
}
int adaptiveThreshold(const uchar* src_data, size_t src_step, uchar* dst_data, size_t dst_step, int width, int height, double maxValue, int adaptiveMethod, int thresholdType, int blockSize, double C)
{
if (thresholdType != CV_HAL_THRESH_BINARY && thresholdType != CV_HAL_THRESH_BINARY_INV)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if (adaptiveMethod != CV_HAL_ADAPTIVE_THRESH_MEAN_C && adaptiveMethod != CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
if ((blockSize != 3 && blockSize != 5) || width < blockSize * 2)
return CV_HAL_ERROR_NOT_IMPLEMENTED;
switch (blockSize*100 + adaptiveMethod*10 + thresholdType)
{
case 300 + CV_HAL_ADAPTIVE_THRESH_MEAN_C*10 + CV_HAL_THRESH_BINARY:
return invoke(width, height, {adaptiveThreshold<3, CV_HAL_ADAPTIVE_THRESH_MEAN_C, CV_HAL_THRESH_BINARY>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 300 + CV_HAL_ADAPTIVE_THRESH_MEAN_C*10 + CV_HAL_THRESH_BINARY_INV:
return invoke(width, height, {adaptiveThreshold<3, CV_HAL_ADAPTIVE_THRESH_MEAN_C, CV_HAL_THRESH_BINARY_INV>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 500 + CV_HAL_ADAPTIVE_THRESH_MEAN_C*10 + CV_HAL_THRESH_BINARY:
return invoke(width, height, {adaptiveThreshold<5, CV_HAL_ADAPTIVE_THRESH_MEAN_C, CV_HAL_THRESH_BINARY>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 500 + CV_HAL_ADAPTIVE_THRESH_MEAN_C*10 + CV_HAL_THRESH_BINARY_INV:
return invoke(width, height, {adaptiveThreshold<5, CV_HAL_ADAPTIVE_THRESH_MEAN_C, CV_HAL_THRESH_BINARY_INV>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 300 + CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C*10 + CV_HAL_THRESH_BINARY:
return invoke(width, height, {adaptiveThreshold<3, CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C, CV_HAL_THRESH_BINARY>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 300 + CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C*10 + CV_HAL_THRESH_BINARY_INV:
return invoke(width, height, {adaptiveThreshold<3, CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C, CV_HAL_THRESH_BINARY_INV>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 500 + CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C*10 + CV_HAL_THRESH_BINARY:
return invoke(width, height, {adaptiveThreshold<5, CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C, CV_HAL_THRESH_BINARY>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
case 500 + CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C*10 + CV_HAL_THRESH_BINARY_INV:
return invoke(width, height, {adaptiveThreshold<5, CV_HAL_ADAPTIVE_THRESH_GAUSSIAN_C, CV_HAL_THRESH_BINARY_INV>}, src_data, src_step, dst_data, dst_step, width, height, maxValue, C);
}
return CV_HAL_ERROR_NOT_IMPLEMENTED;
}
#endif // CV_HAL_RVV_1P0_ENABLED
}}} /// cv::rvv_hal::imgproc
File diff suppressed because it is too large Load Diff