CV_IMPL
int
cvCamShift(
const
void
*
imgProb, CvRect windowIn,
CvTermCriteria criteria,
CvConnectedComp
*
_comp,
CvBox2D
*
box )
{
const
int
TOLERANCE
=
10
;
CvMoments moments;
double
m00
=
0
, m10, m01, mu20, mu11, mu02, inv_m00;
double
a, b, c, xc, yc;
double
rotate_a, rotate_c;
double
theta
=
0
, square;
double
cs, sn;
double
length
=
0
, width
=
0
;
int
itersUsed
=
0
;
CvConnectedComp comp;
CvMat cur_win, stub,
*
mat
=
(CvMat
*
)imgProb;
CV_FUNCNAME(
"
cvCamShift
"
);
comp.rect
=
windowIn;
//
初始化comp
__BEGIN__;
CV_CALL( mat
=
cvGetMat( mat,
&
stub ));
CV_CALL( itersUsed
=
cvMeanShift( mat, windowIn, criteria,
&
comp ));
//
调用meanshift计算质心
windowIn
=
comp.rect;
//
获得新的窗口的位置
//
为了容错,窗口的四边都增大了TOLERANCE
windowIn.x
-=
TOLERANCE;
if
( windowIn.x
<
0
)
windowIn.x
=
0
;
windowIn.y
-=
TOLERANCE;
if
( windowIn.y
<
0
)
windowIn.y
=
0
;
windowIn.width
+=
2
*
TOLERANCE;
if
( windowIn.x
+
windowIn.width
>
mat
->
width )
windowIn.width
=
mat
->
width
-
windowIn.x;
windowIn.height
+=
2
*
TOLERANCE;
if
( windowIn.y
+
windowIn.height
>
mat
->
height )
windowIn.height
=
mat
->
height
-
windowIn.y;
CV_CALL( cvGetSubRect( mat,
&
cur_win, windowIn ));
//
获得指向子窗口的数据指针
/*
Calculating moments in new center mass
*/
CV_CALL( cvMoments(
&
cur_win,
&
moments ));
//
重新计算窗口内的各种矩
m00
=
moments.m00;
m10
=
moments.m10;
m01
=
moments.m01;
mu11
=
moments.mu11;
mu20
=
moments.mu20;
mu02
=
moments.mu02;
if
( fabs(m00)
<
DBL_EPSILON )
EXIT;
inv_m00
=
1
.
/
m00;
xc
=
cvRound( m10
*
inv_m00
+
windowIn.x );
//
新的中心坐标
yc
=
cvRound( m01
*
inv_m00
+
windowIn.y );
a
=
mu20
*
inv_m00;
b
=
mu11
*
inv_m00;
c
=
mu02
*
inv_m00;
/*
Calculating width & height
*/
square
=
sqrt(
4
*
b
*
b
+
(a
-
c)
*
(a
-
c) );
/*
Calculating orientation
*/
theta
=
atan2(
2
*
b, a
-
c
+
square );
/*
Calculating width & length of figure
*/
cs
=
cos( theta );
sn
=
sin( theta );
rotate_a
=
cs
*
cs
*
mu20
+
2
*
cs
*
sn
*
mu11
+
sn
*
sn
*
mu02;
rotate_c
=
sn
*
sn
*
mu20
-
2
*
cs
*
sn
*
mu11
+
cs
*
cs
*
mu02;
length
=
sqrt( rotate_a
*
inv_m00 )
*
4
;
//
长与宽的计算
width
=
sqrt( rotate_c
*
inv_m00 )
*
4
;
/*
In case, when tetta is 0 or 1.57... the Length & Width may be exchanged
*/
if
( length
<
width )
{
double
t;
CV_SWAP( length, width, t );
CV_SWAP( cs, sn, t );
theta
=
CV_PI
*
0.5
-
theta;
}
/*
Saving results
*/
//
由于有宽和高的重新计算,使得能自动调整窗口大小
if
( _comp
||
box )
{
int
t0, t1;
int
_xc
=
cvRound( xc );
//
取整
int
_yc
=
cvRound( yc );
t0
=
cvRound( fabs( length
*
cs ));
t1
=
cvRound( fabs( width
*
sn ));
t0
=
MAX( t0, t1 )
+
2
;
//
宽的重新计算
comp.rect.width
=
MIN( t0, (mat
->
width
-
_xc)
*
2
);
//
保证宽不超出范围
t0
=
cvRound( fabs( length
*
sn ));
t1
=
cvRound( fabs( width
*
cs ));
t0
=
MAX( t0, t1 )
+
2
;
//
高的重新计算
comp.rect.height
=
MIN( t0, (mat
->
height
-
_yc)
*
2
);
//
保证高不超出范围
comp.rect.x
=
MAX(
0
, _xc
-
comp.rect.width
/
2
);
comp.rect.y
=
MAX(
0
, _yc
-
comp.rect.height
/
2
);
comp.rect.width
=
MIN( mat
->
width
-
comp.rect.x, comp.rect.width );
comp.rect.height
=
MIN( mat
->
height
-
comp.rect.y, comp.rect.height );
comp.area
=
(
float
) m00;
}
__END__;
if
( _comp )
*
_comp
=
comp;
if
( box )
{
box
->
size.height
=
(
float
)length;
box
->
size.width
=
(
float
)width;
box
->
angle
=
(
float
)(theta
*
180
.
/
CV_PI);
box
->
center
=
cvPoint2D32f( comp.rect.x
+
comp.rect.width
*
0.5f
,
comp.rect.y
+
comp.rect.height
*
0.5f
);
}
return
itersUsed;
}