Opencv视频处理中的目标跟踪经常用到要在视频上画一个矩形框ROI,标注出要跟踪的物体,这里介绍两种在视频中绘制矩形框的方法,一种是“静态的”,一种是“动态的”。

静态的是指在绘制过程中,视频暂停播放,画面定格在鼠标左键单击上去时候播放的画面,这时候按着鼠标左键并拖动出一个感兴趣的区域,鼠标左键抬起完成矩形框的绘制。在整个绘制过程中,矩形是连续显示出来的,跟随鼠标位置变化而变化。

过程和实现都很简单,以下是具体代码实现,主要用到了鼠标响应事件:


#include "core/core.hpp"  
#include "highgui/highgui.hpp"  
#include "imgproc/imgproc.hpp"  
#include<iostream>  

using namespace cv;  
using namespace std;  

Mat image;
Mat imageCopy; //绘制矩形框时用来拷贝原图的图像
bool leftButtonDownFlag=false; //左键单击后视频暂停播放的标志位
Point originalPoint; //矩形框起点
Point processPoint; //矩形框终点

void onMouse(int event,int x,int y,int flags ,void* ustc); //鼠标回调函数

int main(int argc,char*argv[])  
{  
	VideoCapture video(argv[1]);
	double fps=video.get(CV_CAP_PROP_FPS); //获取视频帧率
	double pauseTime=1000/fps; //两幅画面中间间隔
	namedWindow("Friends");
	setMouseCallback("Friends",onMouse);
	while(true)
	{
		if(!leftButtonDownFlag) //判定鼠标左键没有按下,采取播放视频,否则暂停
		{
			video>>image;
		}
		if(!image.data||waitKey(pauseTime)==27)  //图像为空或Esc键按下退出播放
		{
			break;
		}
		//两种情况下不在原始视频图像上刷新矩形
		//1. 起点等于终点
		//2. 左键按下且未抬起
		if(originalPoint!=processPoint&&!leftButtonDownFlag)
		{
			rectangle(image,originalPoint,processPoint,Scalar(255,0,0),2);
		}
		imshow("Friends",image);		
	}
	return 0;
}  

//*******************************************************************//  
//鼠标回调函数  
void onMouse(int event,int x,int y,int flags,void *ustc)  
{     

	if(event==CV_EVENT_LBUTTONDOWN)  
	{  
		leftButtonDownFlag=true; //标志位
		originalPoint=Point(x,y);  //设置左键按下点的矩形起点
		processPoint=originalPoint;
	}  
	if(event==CV_EVENT_MOUSEMOVE&&leftButtonDownFlag)  
	{  
		imageCopy=image.clone();
		processPoint=Point(x,y);
		if(originalPoint!=processPoint)
		{
			//在复制的图像上绘制矩形
			rectangle(imageCopy,originalPoint,processPoint,Scalar(255,0,0),2);
		}
		imshow("Friends",imageCopy);
	}  
	if(event==CV_EVENT_LBUTTONUP)  
	{  
		leftButtonDownFlag=false;
		Mat rectImage=image(Rect(originalPoint,processPoint)); //子图像显示
		imshow("Sub Image",rectImage);		 
	}	 
}


鼠标左键按下,此时视频画面暂停,拖动左键,绘制出需要的矩形:

android openvc 区域矩形检测 opencv 矩形框_#include


截取出来单独显示的子画面:

android openvc 区域矩形检测 opencv 矩形框_#include_02


对应的,动态的是说在绘制矩形框的过程中,视频还是在正常播放的,截取的子画面是鼠标抬起时当前视频帧的画面。动态绘制不需要在鼠标事件中处理矩形框的绘制,相比静态的还更为简单一点:



#include "core/core.hpp"  
#include "highgui/highgui.hpp"  
#include "imgproc/imgproc.hpp"  
#include<iostream>  

using namespace cv;  
using namespace std;  

Mat image;
Mat imageCopy; //绘制矩形框时用来拷贝原图的图像
bool leftButtonDownFlag=false; //左键单击后视频暂停播放的标志位
Point originalPoint; //矩形框起点
Point processPoint; //矩形框终点

void onMouse(int event,int x,int y,int flags ,void* ustc); //鼠标回调函数

int main(int argc,char*argv[])  
{  
	VideoCapture video(argv[1]);
	double fps=video.get(CV_CAP_PROP_FPS); //获取视频帧率
	double pauseTime=1000/fps; //两幅画面中间间隔
	namedWindow("Friends");
	setMouseCallback("Friends",onMouse);
	while(true)
	{		
		video>>image;		
		if(!image.data||waitKey(pauseTime)==27)  //图像为空或Esc键按下退出播放
		{
			break;
		}
		//两种情况下不在原始视频图像上刷新矩形
		//1. 起点等于终点
		//2. 左键按下且未抬起
		if(originalPoint!=processPoint)
		{
			rectangle(image,originalPoint,processPoint,Scalar(255,0,0),2);
		}
		imshow("Friends",image);		
	}
	return 0;
}  

//*******************************************************************//  
//鼠标回调函数  
void onMouse(int event,int x,int y,int flags,void *ustc)  
{     

	if(event==CV_EVENT_LBUTTONDOWN)  
	{  
		leftButtonDownFlag=true; //标志位
		originalPoint=Point(x,y);  //设置左键按下点的矩形起点
		processPoint=originalPoint;
	}  
	if(event==CV_EVENT_MOUSEMOVE&&leftButtonDownFlag)  
	{  		
		processPoint=Point(x,y);		
	}  
	if(event==CV_EVENT_LBUTTONUP)  
	{  
		leftButtonDownFlag=false;
		Mat rectImage=image(Rect(originalPoint,processPoint)); //子图像显示
		imshow("Sub Image",rectImage);		 
	}	 
}


鼠标左键按下,视频仍会继续播放,拖动鼠标,画出矩形框:



android openvc 区域矩形检测 opencv 矩形框_回调函数_03



截取出来单独显示的子画面:

android openvc 区域矩形检测 opencv 矩形框_ide_04