From b902a8e792e1702b40f19dbd48dff0bfdca8b36d Mon Sep 17 00:00:00 2001 From: amane-ame Date: Tue, 18 Mar 2025 15:53:05 +0800 Subject: [PATCH] Add equalize_hist. Co-authored-by: Liutong HAN --- 3rdparty/hal_rvv/hal_rvv.hpp | 1 + 3rdparty/hal_rvv/hal_rvv_1p0/histogram.hpp | 108 +++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 3rdparty/hal_rvv/hal_rvv_1p0/histogram.hpp diff --git a/3rdparty/hal_rvv/hal_rvv.hpp b/3rdparty/hal_rvv/hal_rvv.hpp index 2135cc355d..2a76f6d54d 100644 --- a/3rdparty/hal_rvv/hal_rvv.hpp +++ b/3rdparty/hal_rvv/hal_rvv.hpp @@ -48,6 +48,7 @@ #include "hal_rvv_1p0/pyramids.hpp" // imgproc #include "hal_rvv_1p0/color.hpp" // imgproc #include "hal_rvv_1p0/thresh.hpp" // imgproc +#include "hal_rvv_1p0/histogram.hpp" // imgproc #endif #endif diff --git a/3rdparty/hal_rvv/hal_rvv_1p0/histogram.hpp b/3rdparty/hal_rvv/hal_rvv_1p0/histogram.hpp new file mode 100644 index 0000000000..48f6123b0d --- /dev/null +++ b/3rdparty/hal_rvv/hal_rvv_1p0/histogram.hpp @@ -0,0 +1,108 @@ +// 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_HAL_RVV_HISTOGRAM_HPP_INCLUDED +#define OPENCV_HAL_RVV_HISTOGRAM_HPP_INCLUDED + +#include + +namespace cv { namespace cv_hal_rvv { + +namespace equalize_hist { +#undef cv_hal_equalize_hist +#define cv_hal_equalize_hist cv::cv_hal_rvv::equalize_hist::equalize_hist + +class HistogramInvoker : public ParallelLoopBody +{ +public: + template + HistogramInvoker(std::function _func, Args&&... args) + { + func = std::bind(_func, std::placeholders::_1, std::placeholders::_2, std::forward(args)...); + } + + virtual void operator()(const Range& range) const override + { + func(range.start, range.end); + } + +private: + std::function func; +}; + +constexpr int HIST_SZ = std::numeric_limits::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 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); + } + } +} + +// the algorithm is copied from imgproc/src/histogram.cpp, +// in the function void cv::equalizeHist +inline 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(hist), &m), static_cast(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(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(lut)), static_cast(width * height) / (1 << 15)); + + return CV_HAL_ERROR_OK; +} +} // cv::cv_hal_rvv::equalize_hist + +}} + +#endif