直接贴上代码,代码全部注释完成,需要学习的可以使用。代码有问题请留言。
#include //opencv头文件
bool selectObject = false; //用于是否有选取目标
int trackObject = 0; // 1表示有追踪对象 0 表示无追踪对象
//-1表示追踪对象尚未计算camshift所需的属性
cv::Rect selection;//保存鼠标选择的区域
cv::Mat image;//用于缓存读取到的视频帧
/*
opencv 对所注册的鼠标回调函数定义为:
void onMouse(int event,int x,int y,int flag,void * param)
其中第四个flag为event下的附加状态,param是用户传入的参数
*/
void onMouse( int event, int x, int y, int, void* ) {
static cv::Point origin;
/*static关键字的作用:
1、隐藏功能 利用这一特性可以在不同的文件中定义同名函数和同名变量
2、保持变量内容的持久
*/
if(selectObject) {//如果检测到选取目标进行下面的操作
//确定鼠标选定区域的左上角坐标以及区域的长和宽
selection.x = MIN(x, origin.x);
selection.y = MIN(y, origin.y);
selection.width = std::abs(x - origin.x);
selection.height = std::abs(y - origin.y);
//&运算符被cv::Rect进行重载
//表示两个区域的交集,主要目的是为了处理当鼠标在选择区域时移除画面外
selection &= cv::Rect(0, 0, image.cols, image.rows);
}
switch(event) {
//处理鼠标左键被按下
case CV_EVENT_LBUTTONDOWN:
origin = cv::Point(x, y);
selection = cv::Rect(x, y, 0, 0);
selectObject = true;
break;
//处理鼠标左键被抬起
case CV_EVENT_LBUTTONUP:
selectObject = false;
if( selection.width > 0 && selection.height > 0 )
trackObject = -1;//追踪的目标还未计算camshift所需要的属性
break;
}
}
int main( int argc, const char** argv )
{
cv::VideoCapture video("video.ogv");//读取文件
//如果需要使用摄像头则代码为
//cv::VideoCapture video(0);
cv::namedWindow( "test" );
//注册鼠标事件的回调函数,第三个参数是用户提供给回掉函数的
//也就是回调函数中最后的param参数
cv::setMouseCallback( "test", onMouse, 0 );
/*
捕获画面的容器,opencv中的mat对象
opencv中最关键的mat类,mat是matrix的缩写
opencv中延续了像素图的概念,用矩阵来描述由像素构成的图像
*/
cv::Mat frame, hsv, hue, mask, hist, backproj;
cv::Rect trackWindow; //追踪到的窗口
int hsize = 16;//计算直方图所必备的内容
float hranges[] = {0,180};//计算直方图所必备的内容
const float* phranges = hranges;//计算直方图所必备的内容
while(true) {
//将video中的内容写入到frame中,
//这里的>>运算符是经过opencv重载的
video >> frame;
if( frame.empty() )//没有帧可以读取的时候,退出循环
break;
//将frame中的图像写入全局变量image作为进行camshift的缓存
frame.copyTo(image);
//转换到的HSV空间
cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);
//当有目标时候进行处理
if( trackObject ) {
// 只处理像素值为H:0~180,S:30~256,V:10~256之间的部分,过滤掉其他的部分并复制给 mask
cv::inRange(hsv, cv::Scalar(0, 30, 10), cv::Scalar(180, 256, 256), mask);
//下面三句将hsv图像中的H通道分离出来
int ch[] = {0, 0};
hue.create(hsv.size(), hsv.depth());
cv::mixChannels(&hsv, 1, &hue, 1, ch, 1);
//如果需要追踪的物体还没有进行属性提取,则对选择的目标中的图像属性提取
if( trackObject < 0 ) {
//设置H通道和mask图像的ROI
cv::Mat roi(hue, selection), maskroi(mask, selection);
//计算ROI所在区域的直方图
calcHist(&roi, 1, 0, maskroi, hist, 1, &hsize, &phranges);
//将直方图归一
normalize(hist, hist, 0, 255, CV_MINMAX);
//设置追踪的窗口
trackWindow = selection;
//标记追踪的目标已经计算过直方图属性
trackObject = 1;
}
//将直方图进行反向投影
calcBackProject(&hue, 1, 0, hist, backproj, &phranges);
//取公共部分
backproj &= mask;
//调用camshift算法的接口
cv::RotatedRect trackBox = CamShift(backproj, trackWindow, cv::TermCriteria( CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1 ));
//处理追踪面积过小的情况
if( trackWindow.area() <= 1 ) {
int cols = backproj.cols, rows = backproj.rows, r = (MIN(cols, rows) + 5)/6;
trackWindow = cv::Rect(trackWindow.x - r, trackWindow.y - r,
trackWindow.x + r, trackWindow.y + r) &
cv::Rect(0, 0, cols, rows);
}
//绘制追踪区域
ellipse( image, trackBox, cv::Scalar(0,0,255), 3, CV_AA );
}
//如果正在选择追踪目标,则画出选择框
if( selectObject && selection.width > 0 && selection.height > 0 ) {
cv::Mat roi(image, selection);
bitwise_not(roi, roi);//对选择的区域图像反色
}
imshow( "test", image );//显示当前帧
// 录制视频帧率为 15, 等待 1000/15 保证视频播放流畅。
// waitKey(int delay) 是 OpenCV 提供的一个等待函数,
// 当运行到这个函数时会阻塞 delay 毫秒的时间来等待键盘输入
char c = (char)cv::waitKey(1000/15.0);
if( c == 27 )//当按键为esc时,退出循环
break;
}
//释放申请的相关内存
cv::destroyAllWindows();
video.release();
return 0;
}
/*以下为本程序仿真步骤
需要安装opencv、opengl
提供linux环境下安装opencv的方法
sudo apt-get install libopencv-dev
linux环境安装opengl的命令
//sudo apt-get update && sudo apt-get install freeglut3 freeglut3-dev
另外提供安装linux环境下的屏幕录制工具
sudo apt-get update && sudo apt-get install gtk-recordmydesktop
linux环境下编译命令
g++ main.cpp `pkg-config opencv --libs --cflags opencv` -o main
*/