mirror of
https://github.com/opencv/opencv.git
synced 2025-06-12 12:22:51 +08:00
imgproc: accurate histogram value thresholding
This commit is contained in:
parent
a105f56957
commit
f301f17b61
@ -50,6 +50,8 @@ namespace cv
|
|||||||
|
|
||||||
////////////////// Helper functions //////////////////////
|
////////////////// Helper functions //////////////////////
|
||||||
|
|
||||||
|
#define CV_CLAMP_INT(v, vmin, vmax) (v < vmin ? vmin : (vmax < v ? vmax : v))
|
||||||
|
|
||||||
static const size_t OUT_OF_RANGE = (size_t)1 << (sizeof(size_t)*8 - 2);
|
static const size_t OUT_OF_RANGE = (size_t)1 << (sizeof(size_t)*8 - 2);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -71,15 +73,18 @@ calcHistLookupTables_8u( const Mat& hist, const SparseMat& shist,
|
|||||||
int sz = !issparse ? hist.size[i] : shist.size(i);
|
int sz = !issparse ? hist.size[i] : shist.size(i);
|
||||||
size_t step = !issparse ? hist.step[i] : 1;
|
size_t step = !issparse ? hist.step[i] : 1;
|
||||||
|
|
||||||
|
double v_lo = ranges[i][0];
|
||||||
|
double v_hi = ranges[i][1];
|
||||||
|
|
||||||
for( j = low; j < high; j++ )
|
for( j = low; j < high; j++ )
|
||||||
{
|
{
|
||||||
int idx = cvFloor(j*a + b);
|
int idx = cvFloor(j*a + b);
|
||||||
size_t written_idx;
|
size_t written_idx = OUT_OF_RANGE;
|
||||||
if( (unsigned)idx < (unsigned)sz )
|
if (j >= v_lo && j < v_hi)
|
||||||
|
{
|
||||||
|
idx = CV_CLAMP_INT(idx, 0, sz - 1);
|
||||||
written_idx = idx*step;
|
written_idx = idx*step;
|
||||||
else
|
}
|
||||||
written_idx = OUT_OF_RANGE;
|
|
||||||
|
|
||||||
tab[i*(high - low) + j - low] = written_idx;
|
tab[i*(high - low) + j - low] = written_idx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -197,6 +202,10 @@ static void histPrepareImages( const Mat* images, int nimages, const int* channe
|
|||||||
double t = histSize[i]/(high - low);
|
double t = histSize[i]/(high - low);
|
||||||
uniranges[i*2] = t;
|
uniranges[i*2] = t;
|
||||||
uniranges[i*2+1] = -t*low;
|
uniranges[i*2+1] = -t*low;
|
||||||
|
#if 0 // This should be true by math, but it is not accurate numerically
|
||||||
|
CV_Assert(cvFloor(low * uniranges[i*2] + uniranges[i*2+1]) == 0);
|
||||||
|
CV_Assert((high * uniranges[i*2] + uniranges[i*2+1]) < histSize[i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -243,22 +252,33 @@ calcHist_( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
|
|||||||
int sz = size[0], d0 = deltas[0], step0 = deltas[1];
|
int sz = size[0], d0 = deltas[0], step0 = deltas[1];
|
||||||
const T* p0 = (const T*)ptrs[0];
|
const T* p0 = (const T*)ptrs[0];
|
||||||
|
|
||||||
|
double v0_lo = _ranges[0][0];
|
||||||
|
double v0_hi = _ranges[0][1];
|
||||||
|
|
||||||
for( ; imsize.height--; p0 += step0, mask += mstep )
|
for( ; imsize.height--; p0 += step0, mask += mstep )
|
||||||
{
|
{
|
||||||
if( !mask )
|
if( !mask )
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0 )
|
for( x = 0; x < imsize.width; x++, p0 += d0 )
|
||||||
{
|
{
|
||||||
int idx = cvFloor(*p0*a + b);
|
double v0 = (double)*p0;
|
||||||
if( (unsigned)idx < (unsigned)sz )
|
int idx = cvFloor(v0*a + b);
|
||||||
((int*)H)[idx]++;
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
idx = CV_CLAMP_INT(idx, 0, sz - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx < (unsigned)sz);
|
||||||
|
((int*)H)[idx]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0 )
|
for( x = 0; x < imsize.width; x++, p0 += d0 )
|
||||||
if( mask[x] )
|
if( mask[x] )
|
||||||
{
|
{
|
||||||
int idx = cvFloor(*p0*a + b);
|
double v0 = (double)*p0;
|
||||||
if( (unsigned)idx < (unsigned)sz )
|
int idx = cvFloor(v0*a + b);
|
||||||
((int*)H)[idx]++;
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
idx = CV_CLAMP_INT(idx, 0, sz - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx < (unsigned)sz);
|
||||||
|
((int*)H)[idx]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -273,24 +293,45 @@ calcHist_( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
|
|||||||
const T* p0 = (const T*)ptrs[0];
|
const T* p0 = (const T*)ptrs[0];
|
||||||
const T* p1 = (const T*)ptrs[1];
|
const T* p1 = (const T*)ptrs[1];
|
||||||
|
|
||||||
|
double v0_lo = _ranges[0][0];
|
||||||
|
double v0_hi = _ranges[0][1];
|
||||||
|
double v1_lo = _ranges[1][0];
|
||||||
|
double v1_hi = _ranges[1][1];
|
||||||
|
|
||||||
for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep )
|
for( ; imsize.height--; p0 += step0, p1 += step1, mask += mstep )
|
||||||
{
|
{
|
||||||
if( !mask )
|
if( !mask )
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
|
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
|
||||||
{
|
{
|
||||||
int idx0 = cvFloor(*p0*a0 + b0);
|
double v0 = (double)*p0;
|
||||||
int idx1 = cvFloor(*p1*a1 + b1);
|
double v1 = (double)*p1;
|
||||||
if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 )
|
int idx0 = cvFloor(v0*a0 + b0);
|
||||||
((int*)(H + hstep0*idx0))[idx1]++;
|
int idx1 = cvFloor(v1*a1 + b1);
|
||||||
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
if (v1 < v1_lo || v1 >= v1_hi)
|
||||||
|
continue;
|
||||||
|
idx0 = CV_CLAMP_INT(idx0, 0, sz0 - 1);
|
||||||
|
idx1 = CV_CLAMP_INT(idx1, 0, sz1 - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1);
|
||||||
|
((int*)(H + hstep0*idx0))[idx1]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
|
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1 )
|
||||||
if( mask[x] )
|
if( mask[x] )
|
||||||
{
|
{
|
||||||
int idx0 = cvFloor(*p0*a0 + b0);
|
double v0 = (double)*p0;
|
||||||
int idx1 = cvFloor(*p1*a1 + b1);
|
double v1 = (double)*p1;
|
||||||
if( (unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1 )
|
int idx0 = cvFloor(v0*a0 + b0);
|
||||||
((int*)(H + hstep0*idx0))[idx1]++;
|
int idx1 = cvFloor(v1*a1 + b1);
|
||||||
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
if (v1 < v1_lo || v1 >= v1_hi)
|
||||||
|
continue;
|
||||||
|
idx0 = CV_CLAMP_INT(idx0, 0, sz0 - 1);
|
||||||
|
idx1 = CV_CLAMP_INT(idx1, 0, sz1 - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx0 < (unsigned)sz0 && (unsigned)idx1 < (unsigned)sz1);
|
||||||
|
((int*)(H + hstep0*idx0))[idx1]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -309,30 +350,63 @@ calcHist_( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
|
|||||||
const T* p1 = (const T*)ptrs[1];
|
const T* p1 = (const T*)ptrs[1];
|
||||||
const T* p2 = (const T*)ptrs[2];
|
const T* p2 = (const T*)ptrs[2];
|
||||||
|
|
||||||
|
double v0_lo = _ranges[0][0];
|
||||||
|
double v0_hi = _ranges[0][1];
|
||||||
|
double v1_lo = _ranges[1][0];
|
||||||
|
double v1_hi = _ranges[1][1];
|
||||||
|
double v2_lo = _ranges[2][0];
|
||||||
|
double v2_hi = _ranges[2][1];
|
||||||
|
|
||||||
for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep )
|
for( ; imsize.height--; p0 += step0, p1 += step1, p2 += step2, mask += mstep )
|
||||||
{
|
{
|
||||||
if( !mask )
|
if( !mask )
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
|
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
|
||||||
{
|
{
|
||||||
int idx0 = cvFloor(*p0*a0 + b0);
|
double v0 = (double)*p0;
|
||||||
int idx1 = cvFloor(*p1*a1 + b1);
|
double v1 = (double)*p1;
|
||||||
int idx2 = cvFloor(*p2*a2 + b2);
|
double v2 = (double)*p2;
|
||||||
if( (unsigned)idx0 < (unsigned)sz0 &&
|
int idx0 = cvFloor(v0*a0 + b0);
|
||||||
|
int idx1 = cvFloor(v1*a1 + b1);
|
||||||
|
int idx2 = cvFloor(v2*a2 + b2);
|
||||||
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
if (v1 < v1_lo || v1 >= v1_hi)
|
||||||
|
continue;
|
||||||
|
if (v2 < v2_lo || v2 >= v2_hi)
|
||||||
|
continue;
|
||||||
|
idx0 = CV_CLAMP_INT(idx0, 0, sz0 - 1);
|
||||||
|
idx1 = CV_CLAMP_INT(idx1, 0, sz1 - 1);
|
||||||
|
idx2 = CV_CLAMP_INT(idx2, 0, sz2 - 1);
|
||||||
|
CV_DbgAssert(
|
||||||
|
(unsigned)idx0 < (unsigned)sz0 &&
|
||||||
(unsigned)idx1 < (unsigned)sz1 &&
|
(unsigned)idx1 < (unsigned)sz1 &&
|
||||||
(unsigned)idx2 < (unsigned)sz2 )
|
(unsigned)idx2 < (unsigned)sz2);
|
||||||
((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
|
((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
|
for( x = 0; x < imsize.width; x++, p0 += d0, p1 += d1, p2 += d2 )
|
||||||
if( mask[x] )
|
if( mask[x] )
|
||||||
{
|
{
|
||||||
int idx0 = cvFloor(*p0*a0 + b0);
|
double v0 = (double)*p0;
|
||||||
int idx1 = cvFloor(*p1*a1 + b1);
|
double v1 = (double)*p1;
|
||||||
int idx2 = cvFloor(*p2*a2 + b2);
|
double v2 = (double)*p2;
|
||||||
if( (unsigned)idx0 < (unsigned)sz0 &&
|
int idx0 = cvFloor(v0*a0 + b0);
|
||||||
(unsigned)idx1 < (unsigned)sz1 &&
|
int idx1 = cvFloor(v1*a1 + b1);
|
||||||
(unsigned)idx2 < (unsigned)sz2 )
|
int idx2 = cvFloor(v2*a2 + b2);
|
||||||
((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
|
if (v0 < v0_lo || v0 >= v0_hi)
|
||||||
|
continue;
|
||||||
|
if (v1 < v1_lo || v1 >= v1_hi)
|
||||||
|
continue;
|
||||||
|
if (v2 < v2_lo || v2 >= v2_hi)
|
||||||
|
continue;
|
||||||
|
idx0 = CV_CLAMP_INT(idx0, 0, sz0 - 1);
|
||||||
|
idx1 = CV_CLAMP_INT(idx1, 0, sz1 - 1);
|
||||||
|
idx2 = CV_CLAMP_INT(idx2, 0, sz2 - 1);
|
||||||
|
CV_DbgAssert(
|
||||||
|
(unsigned)idx0 < (unsigned)sz0 &&
|
||||||
|
(unsigned)idx1 < (unsigned)sz1 &&
|
||||||
|
(unsigned)idx2 < (unsigned)sz2);
|
||||||
|
((int*)(H + hstep0*idx0 + hstep1*idx1))[idx2]++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,9 +420,14 @@ calcHist_( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
|
|||||||
uchar* Hptr = H;
|
uchar* Hptr = H;
|
||||||
for( i = 0; i < dims; i++ )
|
for( i = 0; i < dims; i++ )
|
||||||
{
|
{
|
||||||
int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
|
double v_lo = _ranges[i][0];
|
||||||
if( (unsigned)idx >= (unsigned)size[i] )
|
double v_hi = _ranges[i][1];
|
||||||
|
double v = *ptrs[i];
|
||||||
|
if (v < v_lo || v >= v_hi)
|
||||||
break;
|
break;
|
||||||
|
int idx = cvFloor(v*uniranges[i*2] + uniranges[i*2+1]);
|
||||||
|
idx = CV_CLAMP_INT(idx, 0, size[i] - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx < (unsigned)size[i]);
|
||||||
ptrs[i] += deltas[i*2];
|
ptrs[i] += deltas[i*2];
|
||||||
Hptr += idx*hstep[i];
|
Hptr += idx*hstep[i];
|
||||||
}
|
}
|
||||||
@ -367,9 +446,14 @@ calcHist_( std::vector<uchar*>& _ptrs, const std::vector<int>& _deltas,
|
|||||||
if( mask[x] )
|
if( mask[x] )
|
||||||
for( ; i < dims; i++ )
|
for( ; i < dims; i++ )
|
||||||
{
|
{
|
||||||
int idx = cvFloor(*ptrs[i]*uniranges[i*2] + uniranges[i*2+1]);
|
double v_lo = _ranges[i][0];
|
||||||
if( (unsigned)idx >= (unsigned)size[i] )
|
double v_hi = _ranges[i][1];
|
||||||
|
double v = *ptrs[i];
|
||||||
|
if (v < v_lo || v >= v_hi)
|
||||||
break;
|
break;
|
||||||
|
int idx = cvFloor(v*uniranges[i*2] + uniranges[i*2+1]);
|
||||||
|
idx = CV_CLAMP_INT(idx, 0, size[i] - 1);
|
||||||
|
CV_DbgAssert((unsigned)idx < (unsigned)size[i]);
|
||||||
ptrs[i] += deltas[i*2];
|
ptrs[i] += deltas[i*2];
|
||||||
Hptr += idx*hstep[i];
|
Hptr += idx*hstep[i];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user