• Opencv在视频中静态、动态方式绘制矩形框ROI


    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);		 
    	}	 
    } 


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


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



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


    #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);		 
    	}	 
    }  


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



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



  • 相关阅读:
    python INFO: Can't locate Tcl/Tk libs and/or headers
    关于 android 中 postDelayed方法的讲解
    python两个dataframe的合并
    Android异步加载访问网络图片-解析json
    ThinkCMF----调用指定栏目的文章列表
    thinkCMF----使用自定义函数
    thinkCMF----公共模板的引入
    thinkCMF----如何写标签
    thinkCMF----列表页跳转
    thinkCMF----导航高亮显示
  • 原文地址:https://www.cnblogs.com/mtcnn/p/9411966.html
Copyright © 2020-2023  润新知