// camshift.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "stdio.h"
#include "ctype.h"
IplImage *image=0,*hsv=0,*hue=0,*mask=0,*backproject=0,
*histimg=0;
CvHistogram *hist=0;
int backproject_mode=0;
int select_object=0;
int track_object=0;
int show_hist=1;
CvPoint origin;
CvRect selection;
CvRect track_window;
CvBox2D track_box; //tracking返回的区域box,带角度
//Meanshift跟踪算法返回的Box类
//typedef struct CvBox2D{
//CvPoint2D32f center; /* 盒子的中心 */
//CvSize2D32f size; /* 盒子的长和宽 */
//float angle; /* 水平轴与第一个边的夹角,用弧度表示*/
//}CvBox2D;
CvConnectedComp track_comp;
//连接部件
//typedef struct CvConnectedComp{
//double area; /* 连通域的面积 */
//float value; /* 分割域的灰度缩放值 */
//CvRect rect; /* 分割域的 ROI */
//} CvConnectedComp;
int hdims=48;//划分HIST的个数,越高越精确//划分直方图bins的个数,越多越精确
float hranges_arr[]={0,180};//像素值的范围
float *hranges=hranges_arr;//用于初始化CvHistogram类
int vmin=10,vmax=256,smin=30;
//鼠标回调函数,该函数用鼠标进行跟踪目标的选择
void on_mouse(int event,int x,int y,int flags,void* param )
{
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;
//如果选择物体有效,则打开跟踪功能
break;
}
}
CvScalar hsv2rgb( float hue )
//用于将Hue量转换成RGB量
{
int rgb[3], p, sector;
static const int sector_data[][3]=
{{0,2,1}, {1,2,0}, {1,0,2}, {2,0,1}, {2,1,0}, {0,1,2}};
hue *= 0.033333333333333333333333333333333f;
//cvFloor 返回不大于参数的最大整数值
sector = cvFloor(hue);
p = cvRound(255*(hue - sector));
p ^= sector & 1 ? 255 : 0;
rgb[sector_data[sector][0]] = 255;
rgb[sector_data[sector][1]] = 0;
rgb[sector_data[sector][2]] = p;
return cvScalar(rgb[2], rgb[1], rgb[0],0);
}
int main(int argc, char* argv[])
{
CvCapture* capture=0;
IplImage * frame=0;
//strlen 计算字符串S的长度并返回长度 isdigit判断字符是否是数字0-9返回非零的值
capture=cvCaptureFromCAM(-1);
//打开视频流的失败
printf( "Hot keys: \n"
"\tESC - quit the program\n"
"\tc - stop the tracking\n"
"\tb - switch to/from backprojection view\n"
"\th - show/hide object histogram\n"
"To initialize tracking, select the object with mouse\n" );
//程序功能列表
cvNamedWindow("Histogram",1);
//用于显示直方图
cvNamedWindow("CamShiftDemo",1);
//用于显示视频
cvSetMouseCallback("CamShiftDemo",on_mouse,NULL);
//设置鼠标回调函数
cvCreateTrackbar("Vmin","CamShiftDemo",&vmin,256,0);
cvCreateTrackbar("Vmin","CamShiftDemo",&vmax,256,0);
cvCreateTrackbar("Vmin","CamShiftDemo",&smin,256,0);
//设置滑动条
//进入视频帧处理主循环
for(;;)
{
int i,bin_w,c;
frame=cvQueryFrame(capture); //获得图像
if(!frame)
break;
//第一步
if(!image)
//image为0,表明刚开始还未对image操作过,先建立一些缓冲区
{
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);
//分配反向投影图空间,大小一样,单通道
hist=cvCreateHist(1,&hdims,CV_HIST_ARRAY,&hranges,1);
//创建一维直方图
histimg=cvCreateImage(cvSize(320,200),8,3);
//一维直方图显示空间
cvZero(histimg);
//初始化
}
cvCopy(frame,image); //image得到整个图像
cvCvtColor(image,hsv,CV_BGR2HSV);//把图像从RGB表色系转为HSV表色系
if(track_object)
//track_object非零,表示有需要跟踪的物体
{
int _vmin=vmin, _vmax=vmax;
cvInRangeS( hsv, cvScalar(0,smin,MIN(_vmin,_vmax),0),
cvScalar(180,256,MAX(_vmin,_vmax),0), mask );
//制作掩膜板,只处理像素值为H:0~180,S:smin~256,V:vmin~vmax之间的部分
cvSplit( hsv, hue, 0, 0, 0 );
//分离H分量
if(track_object<0)
//如果需要跟踪的物体还没有进行属性提取,则进行选取框类的图像属性提取
{
float max_val=0.f;
//设置原选择框为ROI
cvSetImageROI( hue, selection );
cvSetImageROI( mask, selection );
//设置掩膜板选择框为ROI
cvCalcHist( &hue, hist, 0, mask );
//得到选择框内且满足掩膜板内的直方图 hist 记录下来
cvGetMinMaxHistValue( hist, 0, &max_val, 0, 0 );
cvConvertScale( hist->bins, hist->bins, max_val ? 255. / max_val : 0., 0 );
// 对直方图的数值转为0~255
cvResetImageROI( hue );
//去除ROI
cvResetImageROI( mask );
//去除ROI
track_window = selection;
track_object = 1;
//置track_object为1,表明属性提取完成
cvZero( histimg );
bin_w=histimg->width/hdims;
//画直方图到图像空间
for(i=0;i<hdims;i++)
{
int val = cvRound( cvGetReal1D(hist->bins,i)*histimg->height/255 );
printf("%d",val);
CvScalar color = hsv2rgb(i*180.f/hdims);
cvRectangle( histimg, cvPoint(i*bin_w,histimg->height),
cvPoint((i+1)*bin_w,histimg->height - val),
color, -1, 8, 0 );
}
}
cvCalcBackProject(&hue,backproject,hist);//使用backproject计算hue的反向投影图
//project大小=HIST
cvAnd( backproject, mask, backproject, 0 );
//得到掩膜内的反向投影
cvCamShift( backproject, track_window,
cvTermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ),
&track_comp, &track_box );
//使用MeanShift算法对backproject中的内容进行搜索,返回跟踪结果
track_window = track_comp.rect;
//得到跟踪结果的矩形框
if( backproject_mode )
cvCvtColor( backproject, image, CV_GRAY2BGR );
if( image->origin )
track_box.angle = -track_box.angle;//反向
cvEllipseBox( image, track_box, CV_RGB(255,0,0), 3, CV_AA, 0 );
//画出跟踪结果的位置
}
if( select_object && selection.width > 0 && selection.height > 0 )
//如果正处于物体选择,画出选择框
{
cvSetImageROI( image, selection );
cvXorS( image, cvScalarAll(255), image, 0 );
cvResetImageROI( image );
}
cvShowImage( "CamShiftDemo", image );
cvShowImage( "Histogram", histimg );
c = cvWaitKey(10);
if( (char) c == 27 )
break;
switch( (char) c )
//按键切换功能
{
case 'b':
backproject_mode ^= 1;
break;
case 'c':
track_object = 0;
cvZero( histimg );
break;
case 'h':
show_hist ^= 1;
if( !show_hist )
cvDestroyWindow( "Histogram" );
else
cvNamedWindow( "Histogram", 1 );
break;
default:
;
}
}
cvReleaseCapture( &capture );
cvDestroyWindow("CamShiftDemo");
return 0;
}
cvCamShift得到掩膜内的反向投影
最新推荐文章于 2023-01-23 16:47:12 发布