CamShift+Kalman跟踪[转载]

// CamShift+Kalman.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

//#include 
#include 
#include 
#include 
//*************************************
//调整矩形框B,使其在A的范围
CvRect my_ChangeRect(CvRect A,CvRect B)
{
if(B.x<a.x)
B.x=A.x;
if(B.x+B.width>A.width)
B.width=A.width-B.x;
if(B.y<a.y)
B.y=A.y;
if(B.y+B.height>A.height)
B.height=A.height-B.y;
return(B);
}
//**************************************
//kalman初始化
CvKalman* InitializeKalman(CvKalman* kalman)
{

const float A[] = {1,0,1,0,
0,1,0,1,
0,0,1,0,
0,0,0,1};
kalman = cvCreateKalman( 4, 2, 0 );
memcpy( kalman->transition_matrix->data.fl, A, sizeof(A));//A
cvSetIdentity( kalman->measurement_matrix, cvScalarAll(1) );//H
cvSetIdentity( kalman->process_noise_cov, cvScalarAll(1e-5) );//Q w ;
cvSetIdentity( kalman->measurement_noise_cov, cvScalarAll(1e-1) );//R v
cvSetIdentity( kalman->error_cov_post, cvScalarAll(1));//P
return kalman;
}
//***************************************
//point1上一帧中心,point2当前帧中心,把x,y,vx,vy存入kalman->state_post
void GetCurentState( CvKalman* kalman, CvPoint point1, CvPoint point2)
{
float input[4] = {point2.x, point2.y, point2.x-point1.x, point2.y-point1.y};//currentstate
memcpy( kalman->state_post->data.fl, input, sizeof(input));
}
//****************************************
//point1上一帧中心,point2当前帧中心,把x,y,vx,vy存入矩阵
CvMat* GetMeasurement(CvMat* mat,CvPoint point1, CvPoint point2)
{
float input[4] = {point2.x, point2.y, point2.x-point1.x, point2.y-point1.y};
memcpy( mat->data.fl, input, sizeof(input));
return mat;
}
/*****************************************/
#define region 50
#define calc_point(kalman) cvPoint( cvRound(kalman[0]),cvRound(kalman[1]))

IplImage *image = 0, *hsv = 0, *hue = 0, *mask = 0, *histimg = 0;
CvHistogram *hist;
IplImage *backproject;

CvPoint lastpoint; //上一帧的中心坐标
CvPoint predictpoint, measurepoint;//预测坐标以及当前帧的坐标

int select_object = 0;
int track_object;

CvPoint origin;
CvPoint point_text;
CvRect selection;
CvRect origin_box;

CvRect track_window;
CvBox2D track_box; // tracking 返回的区域 box,带角度
CvConnectedComp track_comp;
int hdims = 256; // 划分HIST的个数,越高越精确
float hranges_arr[] = {0,180};
float* hranges = hranges_arr;
int vmin = 10, vmax = 256, smin = 30;
int start_track=0;
CvFont font;//显示的文本字体
char nchar[10];//显示数字字符串用
CvMat* measurement;
CvMat* realposition;
const CvMat* prediction;
CvRect search_window;
int filename1_n=0;
int frame_count=0;

void on_mouse( int event, int x, int y, int flags ,void *p)
{
if( !image )
return;

if( image->origin )
y = image->height - y;

if( select_object )
{
selection.x = MIN(x,origin.x);
selection.y = MIN(y,origin.y);
selection.width = selection.x + CV_IABS(x - origin.x);
selection.height = selection.y + CV_IABS(y - origin.y);

selection.x = MAX( selection.x, 0 );
selection.y = MAX( selection.y, 0 );
selection.width = MIN( selection.width, image->width );
selection.height = MIN( selection.height, image->height );
selection.width -= selection.x;
selection.height -= selection.y;

}

switch( event )
{
case CV_EVENT_LBUTTONDOWN:
origin = cvPoint(x,y);
selection = cvRect(x,y,0,0);
select_object = 1;
break;
case CV_EVENT_LBUTTONUP:
select_object = 0;
if( selection.width > 0 && selection.height > 0 )
track_object = -1; 
origin_box=selection;


#ifdef _DEBUG
printf("\n # 鼠标的选择区域:"); 
printf("\n X = %d, Y = %d, Width = %d, Height = %d",
selection.x, selection.y, selection.width, selection.height);
#endif
break;
}
}
/*************************************main***************************/
int main( int argc, char** argv )
{
CvCapture* capture = 0;
IplImage* frame = 0; 
capture = cvCaptureFromCAM(0); 
if( !capture )
{
fprintf(stderr,"Could not initialize capturing...\n");
return -1;
}

cvNamedWindow( "CamShiftDemo", 1 );
cvSetMouseCallback( "CamShiftDemo", on_mouse, NULL ); // on_mouse 自定义事件
cvCreateTrackbar( "Vmin", "CamShiftDemo", &vmin, 256, 0 );
cvCreateTrackbar( "Vmax", "CamShiftDemo", &vmax, 256, 0 );
cvCreateTrackbar( "Smin", "CamShiftDemo", &smin, 256, 0 );
//初始化kalman
CvKalman* kalman =0; 
kalman= InitializeKalman(kalman);
measurement = cvCreateMat( 2, 1, CV_32FC1 );//Z(k)
realposition = cvCreateMat( 4, 1, CV_32FC1 );//real X(k)

for(;;)
{
int i=0,c;
frame = cvQueryFrame( capture );
if( !frame )
break;
if( !image )
{
/* allocate all the buffers */
image = cvCreateImage( cvGetSize(frame), 8, 3 );
image->origin = frame->origin;
hsv = cvCreateImage( cvGetSize(frame), 8, 3 );
hue = cvCreateImage( cvGetSize(frame), 8, 1 );
mask = cvCreateImage( cvGetSize(frame), 8, 1 );

backproject = cvCreateImage( cvGetSize(frame), 8, 1 ); 
backproject->origin = frame->origin;
hist = cvCreateHist( 1, &hdims, CV_HIST_ARRAY, &hranges, 1 ); // 计算直方图


cvCopy( frame, image, 0 );
cvCvtColor( image, hsv, CV_BGR2HSV ); // 彩色空间转换 BGR to HSV 
frame_count++;
//*******************************************************************************************
if(track_object)
{
int _vmin = vmin, _vmax = vmax; 
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
cvScalar(180,256,MAX(_vmin,_vmax),0), mask ); // 得到二值的MASK
cvSplit( hsv, hue, 0, 0, 0 ); // 只提取 HUE 分量 
if( track_object < 0 )
{
float max_val = 0.f;
cvSetImageROI( hue, origin_box ); // 得到选择区域 for ROI
cvSetImageROI( mask, origin_box ); // 得到选择区域 for mask
cvCalcHist( &hue, hist, 0, mask ); // 计算直方图
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 ); // 只找最大值
cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 ); // 缩放 bin 到区间 [0,255] 
cvResetImageROI( hue ); // remove ROI
cvResetImageROI( mask );
track_window = origin_box; 
track_object=1;
lastpoint = predictpoint = cvPoint(track_window.x + track_window.width/2,
track_window.y + track_window.height/2 );
GetCurentState(kalman, lastpoint, predictpoint);//input curent state
}
//预测目标框的位置(x,y,vx,vy), 
prediction = cvKalmanPredict( kalman, 0 );//predicton=kalman->state_post 
predictpoint = calc_point(prediction->data.fl); 
//预测出的矩形框
track_window = cvRect(predictpoint.x - track_window.width/2, predictpoint.y - track_window.height/2, 
track_window.width, track_window.height); 
track_window=my_ChangeRect(cvRect(0,0,frame->width,frame->height),track_window); 
//只对目标周围计算投影
search_window = cvRect(track_window.x - region, track_window.y - region, 
track_window.width + 2*region, track_window.height + 2*region);
//修正search_window,使其范围在图像内
search_window=my_ChangeRect(cvRect(0,0,frame->width,frame->height),search_window);
cvSetImageROI( hue, search_window );
cvSetImageROI( mask, search_window );
cvSetImageROI( backproject, search_window ); 
cvCalcBackProject( &hue, backproject, hist ); // 使用 back project 方法
cvAnd( backproject, mask, backproject, 0 ); 
//因为设置了_1ROI,所以更新track_window
track_window = cvRect(region, region, track_window.width, track_window.height);
// calling CAMSHIFT 算法模块 
/* cvCamShift( backproject, track_window,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
&track_comp, &track_box );*/
cvMeanShift( backproject, track_window,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
&track_comp);
//******************************************************************************** 
cvResetImageROI( hue);
cvResetImageROI( mask );
cvResetImageROI( backproject );
track_window=track_comp.rect;
track_window = cvRect(track_window.x + search_window.x, track_window.y +search_window.y, 
track_window.width, track_window.height);
//实际的质心坐标 
measurepoint = cvPoint(track_window.x + track_window.width/2, 
track_window.y + track_window.height/2 ); 
realposition->data.fl[0]=measurepoint.x;
realposition->data.fl[1]=measurepoint.y;
realposition->data.fl[2]=measurepoint.x - lastpoint.x;
realposition->data.fl[3]=measurepoint.y - lastpoint.y;
lastpoint = measurepoint;//keep the current real position
//实际算出的measurement只是当前的x,y
cvMatMulAdd( kalman->measurement_matrix/*2x4*/, realposition/*4x1*/,/*measurementstate*/ 0, measurement );
cvKalmanCorrect( kalman, measurement ); 
cvRectangle( image , cvPoint(track_window.x,track_window.y),
cvPoint(track_window.x+track_window.width,track_window.y+track_window.height),
CV_RGB(255,0,0),2, 8, 0 );
//把目标是第几个标出来
cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX,1.0F,1.0F,0,3,8);
sprintf(nchar,"ID:%d",i+1);
point_text=cvPoint(track_window.x,track_window.y+track_window.height);
cvPutText(image,nchar,point_text,&font,CV_RGB(255,255,0)); 
}
//*********************************************************************************************** 
if( select_object && selection.width > 0 && selection.height > 0 )
{
cvSetImageROI( image, selection );
cvXorS( image, cvScalarAll(255), image, 0 );
cvResetImageROI( image );
}
cvShowImage( "CamShiftDemo", image );
c = cvWaitKey(30);
//根据键盘关闭跟踪目标
if( c == 27 )
break; // exit from for-loop 
}
cvReleaseCapture( &capture );
cvDestroyWindow("CamShiftDemo");
return 0;
}

你可能感兴趣的:(跟踪)