Add threaded version of equalizeHist
This commit is contained in:

committed by
Andrey Kamaev

parent
0bbba847a4
commit
98d7d99244
@@ -2404,6 +2404,146 @@ cvCalcProbDensity( const CvHistogram* hist, const CvHistogram* hist_mask,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EqualizeHistCalcHist_Invoker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {HIST_SZ = 256};
|
||||||
|
|
||||||
|
#ifdef HAVE_TBB
|
||||||
|
typedef tbb::mutex* MutextPtr;
|
||||||
|
#else
|
||||||
|
typedef void* MutextPtr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
EqualizeHistCalcHist_Invoker(cv::Mat& src, int* histogram, MutextPtr histogramLock)
|
||||||
|
: src_(src), globalHistogram_(histogram), histogramLock_(histogramLock)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()( const cv::BlockedRange& rowRange ) const
|
||||||
|
{
|
||||||
|
int localHistogram[HIST_SZ] = {0, };
|
||||||
|
|
||||||
|
const size_t sstep = src_.step;
|
||||||
|
|
||||||
|
int width = src_.cols;
|
||||||
|
int height = rowRange.end() - rowRange.begin();
|
||||||
|
|
||||||
|
if (src_.isContinuous())
|
||||||
|
{
|
||||||
|
width *= height;
|
||||||
|
height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const uchar* ptr = src_.ptr<uchar>(rowRange.begin()); height--; ptr += sstep)
|
||||||
|
{
|
||||||
|
int x = 0;
|
||||||
|
for (; x <= width - 4; x += 4)
|
||||||
|
{
|
||||||
|
int t0 = ptr[x], t1 = ptr[x+1];
|
||||||
|
localHistogram[t0]++; localHistogram[t1]++;
|
||||||
|
t0 = ptr[x+2]; t1 = ptr[x+3];
|
||||||
|
localHistogram[t0]++; localHistogram[t1]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; x < width; ++x, ++ptr)
|
||||||
|
localHistogram[ptr[x]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_TBB
|
||||||
|
tbb::mutex::scoped_lock lock(*histogramLock_);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for( int i = 0; i < HIST_SZ; i++ )
|
||||||
|
globalHistogram_[i] += localHistogram[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isWorthParallel( const cv::Mat& src )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_TBB
|
||||||
|
return ( src.total() >= 640*480 );
|
||||||
|
#else
|
||||||
|
(void)src;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EqualizeHistCalcHist_Invoker& operator=(const EqualizeHistCalcHist_Invoker&);
|
||||||
|
|
||||||
|
cv::Mat& src_;
|
||||||
|
int* globalHistogram_;
|
||||||
|
MutextPtr histogramLock_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EqualizeHistLut_Invoker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EqualizeHistLut_Invoker( cv::Mat& src, cv::Mat& dst, int* lut )
|
||||||
|
: src_(src),
|
||||||
|
dst_(dst),
|
||||||
|
lut_(lut)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
void operator()( const cv::BlockedRange& rowRange ) const
|
||||||
|
{
|
||||||
|
const size_t sstep = src_.step;
|
||||||
|
const size_t dstep = dst_.step;
|
||||||
|
|
||||||
|
int width = src_.cols;
|
||||||
|
int height = rowRange.end() - rowRange.begin();
|
||||||
|
int* lut = lut_;
|
||||||
|
|
||||||
|
if (src_.isContinuous() && dst_.isContinuous())
|
||||||
|
{
|
||||||
|
width *= height;
|
||||||
|
height = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uchar* sptr = src_.ptr<uchar>(rowRange.begin());
|
||||||
|
uchar* dptr = dst_.ptr<uchar>(rowRange.begin());
|
||||||
|
|
||||||
|
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]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isWorthParallel( const cv::Mat& src )
|
||||||
|
{
|
||||||
|
#ifdef HAVE_TBB
|
||||||
|
return ( src.total() >= 640*480 );
|
||||||
|
#else
|
||||||
|
(void)src;
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EqualizeHistLut_Invoker& operator=(const EqualizeHistLut_Invoker&);
|
||||||
|
|
||||||
|
cv::Mat& src_;
|
||||||
|
cv::Mat& dst_;
|
||||||
|
int* lut_;
|
||||||
|
};
|
||||||
|
|
||||||
CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr )
|
CV_IMPL void cvEqualizeHist( const CvArr* srcarr, CvArr* dstarr )
|
||||||
{
|
{
|
||||||
@@ -2421,35 +2561,25 @@ void cv::equalizeHist( InputArray _src, OutputArray _dst )
|
|||||||
if(src.empty())
|
if(src.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const int hist_sz = (1 << (8*sizeof(uchar)));
|
#ifdef HAVE_TBB
|
||||||
|
tbb::mutex histogramLockInstance;
|
||||||
|
EqualizeHistCalcHist_Invoker::MutextPtr histogramLock = &histogramLockInstance;
|
||||||
|
#else
|
||||||
|
EqualizeHistCalcHist_Invoker::MutextPtr histogramLock = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const int hist_sz = EqualizeHistCalcHist_Invoker::HIST_SZ;
|
||||||
int hist[hist_sz] = {0,};
|
int hist[hist_sz] = {0,};
|
||||||
|
int lut[hist_sz];
|
||||||
|
|
||||||
const size_t sstep = src.step;
|
EqualizeHistCalcHist_Invoker calcBody(src, hist, histogramLock);
|
||||||
const size_t dstep = dst.step;
|
EqualizeHistLut_Invoker lutBody(src, dst, lut);
|
||||||
|
cv::BlockedRange heightRange(0, src.rows);
|
||||||
|
|
||||||
int width = src.cols;
|
if(EqualizeHistCalcHist_Invoker::isWorthParallel(src))
|
||||||
int height = src.rows;
|
parallel_for(heightRange, calcBody);
|
||||||
|
else
|
||||||
if (src.isContinuous())
|
calcBody(heightRange);
|
||||||
{
|
|
||||||
width *= height;
|
|
||||||
height = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const uchar* ptr = src.ptr<uchar>(); height--; ptr += sstep)
|
|
||||||
{
|
|
||||||
int x = 0;
|
|
||||||
for (; x <= width - 4; x += 4)
|
|
||||||
{
|
|
||||||
int t0 = ptr[x], t1 = ptr[x+1];
|
|
||||||
hist[t0]++; hist[t1]++;
|
|
||||||
t0 = ptr[x+2]; t1 = ptr[x+3];
|
|
||||||
hist[t0]++; hist[t1]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; x < width; ++x, ++ptr)
|
|
||||||
hist[ptr[x]]++;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while (!hist[i]) ++i;
|
while (!hist[i]) ++i;
|
||||||
@@ -2464,49 +2594,16 @@ void cv::equalizeHist( InputArray _src, OutputArray _dst )
|
|||||||
float scale = (hist_sz - 1.f)/(total - hist[i]);
|
float scale = (hist_sz - 1.f)/(total - hist[i]);
|
||||||
int sum = 0;
|
int sum = 0;
|
||||||
|
|
||||||
int lut[hist_sz];
|
|
||||||
|
|
||||||
for (lut[i++] = 0; i < hist_sz; ++i)
|
for (lut[i++] = 0; i < hist_sz; ++i)
|
||||||
{
|
{
|
||||||
sum += hist[i];
|
sum += hist[i];
|
||||||
lut[i] = saturate_cast<uchar>(sum * scale);
|
lut[i] = saturate_cast<uchar>(sum * scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cols = src.cols;
|
if(EqualizeHistLut_Invoker::isWorthParallel(src))
|
||||||
int rows = src.rows;
|
parallel_for(heightRange, lutBody);
|
||||||
|
else
|
||||||
if (src.isContinuous() && dst.isContinuous())
|
lutBody(heightRange);
|
||||||
{
|
|
||||||
cols *= rows;
|
|
||||||
rows = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uchar* sptr = src.ptr<uchar>();
|
|
||||||
uchar* dptr = dst.ptr<uchar>();
|
|
||||||
|
|
||||||
for (; rows--; sptr += sstep, dptr += dstep)
|
|
||||||
{
|
|
||||||
int x = 0;
|
|
||||||
for (; x <= cols - 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 < cols; ++x)
|
|
||||||
dptr[x] = (uchar)lut[sptr[x]];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Implementation of RTTI and Generic Functions for CvHistogram */
|
/* Implementation of RTTI and Generic Functions for CvHistogram */
|
||||||
|
Reference in New Issue
Block a user