mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
Merge pull request #29250 from amd:fast_lut8u_simd
imgproc: optimized LUT and equalizeHist with SIMD #29250 - optimized lut with SIMD - support equalizeHist with v_lut ### Pull Request Readiness Checklist See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request - [x] I agree to contribute to the project under Apache 2 License. - [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV - [x] The PR is proposed to the proper branch - [ ] There is a reference to the original bug report and related work - [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable Patch to opencv_extra has the same branch name. - [x] The feature is well documented and sample code can be built with the project CMake
This commit is contained in:
committed by
GitHub
parent
d0925fa360
commit
70a2c50b43
@@ -0,0 +1,37 @@
|
||||
// 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) 2026, Advanced Micro Devices, Inc., all rights reserved.
|
||||
|
||||
#include "precomp.hpp"
|
||||
|
||||
#include "equalize_hist.simd.hpp"
|
||||
#include "equalize_hist.simd_declarations.hpp" // defines CV_CPU_DISPATCH_MODES_ALL=AVX512_ICL,...,BASELINE
|
||||
|
||||
namespace cv {
|
||||
|
||||
namespace {
|
||||
|
||||
typedef void (*EqualizeHistLutFunc)( const uchar*, uchar*, int, const uchar* );
|
||||
|
||||
static EqualizeHistLutFunc resolveEqualizeHistLutFunc()
|
||||
{
|
||||
#if CV_TRY_AVX512_ICL
|
||||
if (cv::checkHardwareSupport(CV_CPU_AVX512_ICL))
|
||||
return opt_AVX512_ICL::equalizeHistLut_;
|
||||
#endif
|
||||
return cpu_baseline::equalizeHistLut_;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void equalizeHistLut_dispatch( const uchar* src, uchar* dst, int len, const uchar* lut );
|
||||
|
||||
void equalizeHistLut_dispatch( const uchar* src, uchar* dst, int len, const uchar* lut )
|
||||
{
|
||||
CV_INSTRUMENT_REGION();
|
||||
static EqualizeHistLutFunc fn = resolveEqualizeHistLutFunc();
|
||||
fn(src, dst, len, lut);
|
||||
}
|
||||
|
||||
} // namespace cv
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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) 2026, Advanced Micro Devices, Inc., all rights reserved.
|
||||
|
||||
#include "precomp.hpp"
|
||||
#include "opencv2/core/hal/intrin.hpp"
|
||||
|
||||
// VBMI vpermb is the only x86 SIMD path faster than scalar for byte LUT.
|
||||
// Non-VBMI x86 SIMD (gather-based) is slower than scalar for byte LUT.
|
||||
// Non-x86 (NEON, RVV, etc.) benefits from v_lut implementation.
|
||||
#if CV_AVX_512VBMI
|
||||
#define CV_EQUALIZE_HIST_SIMD 1
|
||||
#elif (defined(CV_CPU_COMPILE_SSE) || defined(CV_CPU_COMPILE_SSE2) || defined(CV_CPU_COMPILE_SSE3) || \
|
||||
defined(CV_CPU_COMPILE_SSSE3) || defined(CV_CPU_COMPILE_SSE4_1) || defined(CV_CPU_COMPILE_SSE4_2) || \
|
||||
defined(CV_CPU_COMPILE_AVX) || defined(CV_CPU_COMPILE_AVX2) || defined(CV_CPU_COMPILE_AVX_512F) || \
|
||||
defined(CV_CPU_COMPILE_AVX512_COMMON) || defined(CV_CPU_COMPILE_AVX512_SKX) || \
|
||||
defined(CV_CPU_COMPILE_AVX512_CNL) || defined(CV_CPU_COMPILE_AVX512_CLX))
|
||||
#define CV_EQUALIZE_HIST_SIMD 0
|
||||
#elif CV_SIMD || CV_SIMD_SCALABLE
|
||||
#define CV_EQUALIZE_HIST_SIMD 1
|
||||
#else
|
||||
#define CV_EQUALIZE_HIST_SIMD 0
|
||||
#endif
|
||||
|
||||
namespace cv {
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_BEGIN
|
||||
|
||||
void equalizeHistLut_( const uchar* src, uchar* dst, int len, const uchar* lut );
|
||||
|
||||
#ifndef CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
void equalizeHistLut_( const uchar* src, uchar* dst, int len, const uchar* lut )
|
||||
{
|
||||
int x = 0;
|
||||
#if CV_EQUALIZE_HIST_SIMD
|
||||
const int nlanes = VTraits<v_uint8>::vlanes();
|
||||
for( ; x <= len - nlanes; x += nlanes )
|
||||
{
|
||||
v_uint8 idx = vx_load(src + x);
|
||||
v_uint8 result = v_lut(lut, idx);
|
||||
v_store(dst + x, result);
|
||||
}
|
||||
#endif
|
||||
for( ; x <= len - 4; x += 4 )
|
||||
{
|
||||
uchar v0 = src[x], v1 = src[x+1];
|
||||
dst[x] = lut[v0];
|
||||
dst[x+1] = lut[v1];
|
||||
v0 = src[x+2]; v1 = src[x+3];
|
||||
dst[x+2] = lut[v0];
|
||||
dst[x+3] = lut[v1];
|
||||
}
|
||||
for( ; x < len; x++ )
|
||||
dst[x] = lut[src[x]];
|
||||
}
|
||||
|
||||
#endif // CV_CPU_OPTIMIZATION_DECLARATIONS_ONLY
|
||||
|
||||
CV_CPU_OPTIMIZATION_NAMESPACE_END
|
||||
} // namespace cv
|
||||
@@ -3321,10 +3321,14 @@ private:
|
||||
cv::Mutex* histogramLock_;
|
||||
};
|
||||
|
||||
namespace cv {
|
||||
void equalizeHistLut_dispatch( const uchar* src, uchar* dst, int len, const uchar* lut );
|
||||
}
|
||||
|
||||
class EqualizeHistLut_Invoker : public cv::ParallelLoopBody
|
||||
{
|
||||
public:
|
||||
EqualizeHistLut_Invoker( cv::Mat& src, cv::Mat& dst, int* lut )
|
||||
EqualizeHistLut_Invoker( cv::Mat& src, cv::Mat& dst, uchar* lut )
|
||||
: src_(src),
|
||||
dst_(dst),
|
||||
lut_(lut)
|
||||
@@ -3337,7 +3341,7 @@ public:
|
||||
|
||||
int width = src_.cols;
|
||||
int height = rowRange.end - rowRange.start;
|
||||
int* lut = lut_;
|
||||
const uchar* lut = lut_;
|
||||
|
||||
if (src_.isContinuous() && dst_.isContinuous())
|
||||
{
|
||||
@@ -3350,26 +3354,7 @@ public:
|
||||
|
||||
for (; height--; sptr += sstep, dptr += dstep)
|
||||
{
|
||||
int x = 0;
|
||||
for (; x <= width - 4; x += 4)
|
||||
{
|
||||
int v0 = sptr[x];
|
||||
int v1 = sptr[x+1];
|
||||
int x0 = lut[v0];
|
||||
int x1 = lut[v1];
|
||||
dptr[x] = (uchar)x0;
|
||||
dptr[x+1] = (uchar)x1;
|
||||
|
||||
v0 = sptr[x+2];
|
||||
v1 = sptr[x+3];
|
||||
x0 = lut[v0];
|
||||
x1 = lut[v1];
|
||||
dptr[x+2] = (uchar)x0;
|
||||
dptr[x+3] = (uchar)x1;
|
||||
}
|
||||
|
||||
for (; x < width; ++x)
|
||||
dptr[x] = (uchar)lut[sptr[x]];
|
||||
cv::equalizeHistLut_dispatch(sptr, dptr, width, lut);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3383,7 +3368,7 @@ private:
|
||||
|
||||
cv::Mat& src_;
|
||||
cv::Mat& dst_;
|
||||
int* lut_;
|
||||
uchar* lut_;
|
||||
};
|
||||
|
||||
CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr )
|
||||
@@ -3464,10 +3449,9 @@ void cv::equalizeHist( InputArray _src, OutputArray _dst )
|
||||
|
||||
const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
|
||||
int hist[hist_sz] = {0,};
|
||||
int lut[hist_sz];
|
||||
int lut[hist_sz] = {0,};
|
||||
|
||||
EqualizeHistCalcHist_Invoker calcBody(src, hist, &histogramLockInstance);
|
||||
EqualizeHistLut_Invoker lutBody(src, dst, lut);
|
||||
cv::Range heightRange(0, src.rows);
|
||||
|
||||
if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
|
||||
@@ -3494,6 +3478,12 @@ void cv::equalizeHist( InputArray _src, OutputArray _dst )
|
||||
lut[i] = saturate_cast<uchar>(sum * scale);
|
||||
}
|
||||
|
||||
uchar lut_u8[hist_sz];
|
||||
for (int j = 0; j < hist_sz; ++j)
|
||||
lut_u8[j] = (uchar)lut[j];
|
||||
|
||||
EqualizeHistLut_Invoker lutBody(src, dst, lut_u8);
|
||||
|
||||
if(EqualizeHistLut_Invoker::isWorthParallel(src))
|
||||
parallel_for_(heightRange, lutBody);
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user