// 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 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::max(), vlmax); auto vec_max = VEC_T::vmv(std::numeric_limits::lowest(), vlmax); T val_min, val_max; if (mask) { for (int i = 0; i < height; i++) { const T* src_row = reinterpret_cast(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::max(), vlmax); auto sc_maxval = VEC_T::vmv(std::numeric_limits::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(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(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::max(), vlmax); auto sc_maxval = VEC_T::vmv(std::numeric_limits::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(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 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::max(), vlmax); auto vec_max = VEC_T::vmv(std::numeric_limits::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(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(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::max(); val_max = std::numeric_limits::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(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_8SC1: return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_16UC1: return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_16SC1: return minMaxIdxReadTwice(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_32SC1: return minMaxIdxReadOnce(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_32FC1: return minMaxIdxReadOnce(src_data, src_step, width, height, minVal, maxVal, minIdx, maxIdx, mask, mask_step); case CV_64FC1: return minMaxIdxReadOnce(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