📄 cvshapedescr.cpp
字号:
/* area of a whole sequence */
static CvStatus
icvContourArea( const CvSeq* contour, double *area )
{
if( contour->total )
{
CvSeqReader reader;
int lpt = contour->total;
double a00 = 0, xi_1, yi_1;
int is_float = CV_SEQ_ELTYPE(contour) == CV_32FC2;
cvStartReadSeq( contour, &reader, 0 );
if( !is_float )
{
xi_1 = ((CvPoint*)(reader.ptr))->x;
yi_1 = ((CvPoint*)(reader.ptr))->y;
}
else
{
xi_1 = ((CvPoint2D32f*)(reader.ptr))->x;
yi_1 = ((CvPoint2D32f*)(reader.ptr))->y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
while( lpt-- > 0 )
{
double dxy, xi, yi;
if( !is_float )
{
xi = ((CvPoint*)(reader.ptr))->x;
yi = ((CvPoint*)(reader.ptr))->y;
}
else
{
xi = ((CvPoint2D32f*)(reader.ptr))->x;
yi = ((CvPoint2D32f*)(reader.ptr))->y;
}
CV_NEXT_SEQ_ELEM( contour->elem_size, reader );
dxy = xi_1 * yi - xi * yi_1;
a00 += dxy;
xi_1 = xi;
yi_1 = yi;
}
*area = a00 * 0.5;
}
else
*area = 0;
return CV_OK;
}
/****************************************************************************************\
copy data from one buffer to other buffer
\****************************************************************************************/
static CvStatus
icvMemCopy( double **buf1, double **buf2, double **buf3, int *b_max )
{
int bb;
if( *buf1 == NULL && *buf2 == NULL || *buf3 == NULL )
return CV_NULLPTR_ERR;
bb = *b_max;
if( *buf2 == NULL )
{
*b_max = 2 * (*b_max);
*buf2 = (double *)cvAlloc( (*b_max) * sizeof( double ));
if( *buf2 == NULL )
return CV_OUTOFMEM_ERR;
memcpy( *buf2, *buf3, bb * sizeof( double ));
*buf3 = *buf2;
cvFree( buf1 );
*buf1 = NULL;
}
else
{
*b_max = 2 * (*b_max);
*buf1 = (double *) cvAlloc( (*b_max) * sizeof( double ));
if( *buf1 == NULL )
return CV_OUTOFMEM_ERR;
memcpy( *buf1, *buf3, bb * sizeof( double ));
*buf3 = *buf1;
cvFree( buf2 );
*buf2 = NULL;
}
return CV_OK;
}
/* area of a contour sector */
static CvStatus icvContourSecArea( CvSeq * contour, CvSlice slice, double *area )
{
CvPoint pt; /* pointer to points */
CvPoint pt_s, pt_e; /* first and last points */
CvSeqReader reader; /* points reader of contour */
int p_max = 2, p_ind;
int lpt, flag, i;
double a00; /* unnormalized moments m00 */
double xi, yi, xi_1, yi_1, x0, y0, dxy, sk, sk1, t;
double x_s, y_s, nx, ny, dx, dy, du, dv;
double eps = 1.e-5;
double *p_are1, *p_are2, *p_are;
assert( contour != NULL );
if( contour == NULL )
return CV_NULLPTR_ERR;
if( !CV_IS_SEQ_POLYGON( contour ))
return CV_BADFLAG_ERR;
lpt = cvSliceLength( slice, contour );
/*if( n2 >= n1 )
lpt = n2 - n1 + 1;
else
lpt = contour->total - n1 + n2 + 1;*/
if( contour->total && lpt > 2 )
{
a00 = x0 = y0 = xi_1 = yi_1 = 0;
sk1 = 0;
flag = 0;
dxy = 0;
p_are1 = (double *) cvAlloc( p_max * sizeof( double ));
if( p_are1 == NULL )
return CV_OUTOFMEM_ERR;
p_are = p_are1;
p_are2 = NULL;
cvStartReadSeq( contour, &reader, 0 );
cvSetSeqReaderPos( &reader, slice.start_index );
CV_READ_SEQ_ELEM( pt_s, reader );
p_ind = 0;
cvSetSeqReaderPos( &reader, slice.end_index );
CV_READ_SEQ_ELEM( pt_e, reader );
/* normal coefficients */
nx = pt_s.y - pt_e.y;
ny = pt_e.x - pt_s.x;
cvSetSeqReaderPos( &reader, slice.start_index );
while( lpt-- > 0 )
{
CV_READ_SEQ_ELEM( pt, reader );
if( flag == 0 )
{
xi_1 = (double) pt.x;
yi_1 = (double) pt.y;
x0 = xi_1;
y0 = yi_1;
sk1 = 0;
flag = 1;
}
else
{
xi = (double) pt.x;
yi = (double) pt.y;
/**************** edges intersection examination **************************/
sk = nx * (xi - pt_s.x) + ny * (yi - pt_s.y);
if( fabs( sk ) < eps && lpt > 0 || sk * sk1 < -eps )
{
if( fabs( sk ) < eps )
{
dxy = xi_1 * yi - xi * yi_1;
a00 = a00 + dxy;
dxy = xi * y0 - x0 * yi;
a00 = a00 + dxy;
if( p_ind >= p_max )
icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
p_are[p_ind] = a00 / 2.;
p_ind++;
a00 = 0;
sk1 = 0;
x0 = xi;
y0 = yi;
dxy = 0;
}
else
{
/* define intersection point */
dv = yi - yi_1;
du = xi - xi_1;
dx = ny;
dy = -nx;
if( fabs( du ) > eps )
t = ((yi_1 - pt_s.y) * du + dv * (pt_s.x - xi_1)) /
(du * dy - dx * dv);
else
t = (xi_1 - pt_s.x) / dx;
if( t > eps && t < 1 - eps )
{
x_s = pt_s.x + t * dx;
y_s = pt_s.y + t * dy;
dxy = xi_1 * y_s - x_s * yi_1;
a00 += dxy;
dxy = x_s * y0 - x0 * y_s;
a00 += dxy;
if( p_ind >= p_max )
icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
p_are[p_ind] = a00 / 2.;
p_ind++;
a00 = 0;
sk1 = 0;
x0 = x_s;
y0 = y_s;
dxy = x_s * yi - xi * y_s;
}
}
}
else
dxy = xi_1 * yi - xi * yi_1;
a00 += dxy;
xi_1 = xi;
yi_1 = yi;
sk1 = sk;
}
}
xi = x0;
yi = y0;
dxy = xi_1 * yi - xi * yi_1;
a00 += dxy;
if( p_ind >= p_max )
icvMemCopy( &p_are1, &p_are2, &p_are, &p_max );
p_are[p_ind] = a00 / 2.;
p_ind++;
/* common area calculation */
*area = 0;
for( i = 0; i < p_ind; i++ )
(*area) += fabs( p_are[i] );
if( p_are1 != NULL )
cvFree( &p_are1 );
else if( p_are2 != NULL )
cvFree( &p_are2 );
return CV_OK;
}
else
return CV_BADSIZE_ERR;
}
/* external contour area function */
CV_IMPL double
cvContourArea( const void *array, CvSlice slice )
{
double area = 0;
CV_FUNCNAME( "cvContourArea" );
__BEGIN__;
CvContour contour_header;
CvSeq* contour = 0;
CvSeqBlock block;
if( CV_IS_SEQ( array ))
{
contour = (CvSeq*)array;
if( !CV_IS_SEQ_POLYLINE( contour ))
CV_ERROR( CV_StsBadArg, "Unsupported sequence type" );
}
else
{
CV_CALL( contour = cvPointSeqFromMat(
CV_SEQ_KIND_CURVE, array, &contour_header, &block ));
}
if( cvSliceLength( slice, contour ) == contour->total )
{
IPPI_CALL( icvContourArea( contour, &area ));
}
else
{
if( CV_SEQ_ELTYPE( contour ) != CV_32SC2 )
CV_ERROR( CV_StsUnsupportedFormat,
"Only curves with integer coordinates are supported in case of contour slice" );
IPPI_CALL( icvContourSecArea( contour, slice, &area ));
}
__END__;
return area;
}
/* for now this function works bad with singular cases
You can see in the code, that when some troubles with
matrices or some variables occur -
box filled with zero values is returned.
However in general function works fine.
*/
static void
icvFitEllipse_F( CvSeq* points, CvBox2D* box )
{
CvMat* D = 0;
CV_FUNCNAME( "icvFitEllipse_F" );
__BEGIN__;
double S[36], C[36], T[36];
int i, j;
double eigenvalues[6], eigenvectors[36];
double a, b, c, d, e, f;
double x0, y0, idet, scale, offx = 0, offy = 0;
int n = points->total;
CvSeqReader reader;
int is_float = CV_SEQ_ELTYPE(points) == CV_32FC2;
CvMat _S = cvMat(6,6,CV_64F,S), _C = cvMat(6,6,CV_64F,C), _T = cvMat(6,6,CV_64F,T);
CvMat _EIGVECS = cvMat(6,6,CV_64F,eigenvectors), _EIGVALS = cvMat(6,1,CV_64F,eigenvalues);
/* create matrix D of input points */
CV_CALL( D = cvCreateMat( n, 6, CV_64F ));
cvStartReadSeq( points, &reader );
/* shift all points to zero */
for( i = 0; i < n; i++ )
{
if( !is_float )
{
offx += ((CvPoint*)reader.ptr)->x;
offy += ((CvPoint*)reader.ptr)->y;
}
else
{
offx += ((CvPoint2D32f*)reader.ptr)->x;
offy += ((CvPoint2D32f*)reader.ptr)->y;
}
CV_NEXT_SEQ_ELEM( points->elem_size, reader );
}
offx /= n;
offy /= n;
// fill matrix rows as (x*x, x*y, y*y, x, y, 1 )
for( i = 0; i < n; i++ )
{
double x, y;
double* Dptr = D->data.db + i*6;
if( !is_float )
{
x = ((CvPoint*)reader.ptr)->x - offx;
y = ((CvPoint*)reader.ptr)->y - offy;
}
else
{
x = ((CvPoint2D32f*)reader.ptr)->x - offx;
y = ((CvPoint2D32f*)reader.ptr)->y - offy;
}
CV_NEXT_SEQ_ELEM( points->elem_size, reader );
Dptr[0] = x * x;
Dptr[1] = x * y;
Dptr[2] = y * y;
Dptr[3] = x;
Dptr[4] = y;
Dptr[5] = 1.;
}
// S = D^t*D
cvMulTransposed( D, &_S, 1 );
cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
for( i = 0; i < 6; i++ )
{
double a = eigenvalues[i];
a = a < DBL_EPSILON ? 0 : 1./sqrt(sqrt(a));
for( j = 0; j < 6; j++ )
eigenvectors[i*6 + j] *= a;
}
// C = Q^-1 = transp(INVEIGV) * INVEIGV
cvMulTransposed( &_EIGVECS, &_C, 1 );
cvZero( &_S );
S[2] = 2.;
S[7] = -1.;
S[12] = 2.;
// S = Q^-1*S*Q^-1
cvMatMul( &_C, &_S, &_T );
cvMatMul( &_T, &_C, &_S );
// and find its eigenvalues and vectors too
//cvSVD( &_S, &_EIGVALS, &_EIGVECS, 0, CV_SVD_MODIFY_A + CV_SVD_U_T );
cvEigenVV( &_S, &_EIGVECS, &_EIGVALS, 0 );
for( i = 0; i < 3; i++ )
if( eigenvalues[i] > 0 )
break;
if( i >= 3 /*eigenvalues[0] < DBL_EPSILON*/ )
{
box->center.x = box->center.y =
box->size.width = box->size.height =
box->angle = 0.f;
EXIT;
}
// now find truthful eigenvector
_EIGVECS = cvMat( 6, 1, CV_64F, eigenvectors + 6*i );
_T = cvMat( 6, 1, CV_64F, T );
// Q^-1*eigenvecs[0]
cvMatMul( &_C, &_EIGVECS, &_T );
// extract vector components
a = T[0]; b = T[1]; c = T[2]; d = T[3]; e = T[4]; f = T[5];
///////////////// extract ellipse axes from above values ////////////////
/*
1) find center of ellipse
it satisfy equation
| a b/2 | * | x0 | + | d/2 | = |0 |
| b/2 c | | y0 | | e/2 | |0 |
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -