Add equalize_hist.

Co-authored-by: Liutong HAN <liutong2020@iscas.ac.cn>
This commit is contained in:
amane-ame 2025-03-18 15:53:05 +08:00
parent 0142231e4d
commit b902a8e792
2 changed files with 109 additions and 0 deletions

View File

@ -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

View File

@ -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 <riscv_vector.h>
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<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);
}
}
}
// 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<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;
}
} // cv::cv_hal_rvv::equalize_hist
}}
#endif