opencv录制视频,在视频上画线等操作,保存这段视频到磁盘

基本思路:
(1)画线操作与视频读取工作空间分离,否则的话画线不连续
(2)读入视频的一帧,在这帧上触发鼠标事件记录当前点到单向链表中
(3)每次读入视频都画出链表中的所有点和线
(4)键盘事件,空格开始暂停录制视频,以及ESC退出程序保存视频到磁盘

废话少说,上代码,代码注释已经画了一点时间整理完善过了

代码:

//***************************************************************************
//***************************************************************************
录制视频及用户对其鼠标的画线操作,保存RecordVideo.avi
//***************************************************************************
//****************************************************************************

#include<iostream>
#include<time.h>
#include <opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>									//图像处理的库,circle()要用到
#include<opencv2/highgui/highgui.hpp>
using namespace cv;
using namespace std;


struct myPoint															//点p, 该点是否是一条线的起始点
{
	Point p;
	bool start;															//true是一条线的起始点,false不是起始点
};

struct pointNode{														//链表数据节点,数据value,指针next
	myPoint value;
	pointNode *next;
};

struct startNode{														//链表起始节点,指针next指向下一个数据节点
	pointNode *next;
};



int point_num = 0;														//record_point()函数中用于确定是否是当前连续线的起始点
int heapPoint_num = 0;													//保存的所有点的数量
clock_t previous = clock(), current;									//record_point()函数中用于记录上一个时间和现在的时间的变量
double duration;														//画两个点之间的时间差
Mat frame;																//摄像头读入的一帧图像
startNode *heapPoint = new startNode;									//整个链表的起始节点
pointNode *last_node = new pointNode;									//链表中最后一个节点


//*********************************************
//画点函数,从链表中连续读取各点,然后画出来
//********************************************
static void draw_point()
{
	pointNode *node = new pointNode;									//new出当前要画的节点
	Point previous_p;													//保存的画直线的上一个点
	node = heapPoint->next;												//node初始节点被赋值为第一个有数据的链表节点
	for (int i = 0; i < heapPoint_num; i++)
	{
		if (node->value.start == true)									//如果当前点是一条连续线的起始点
		{
			circle(frame, node->value.p, 1, Scalar(0, 0, 255));			//画这条线的第一个点
		}
		else															//如果当前点不是一条连续线的起始点
		{
			line(frame, previous_p, node->value.p, Scalar(0, 0, 255));  //在当前点与上一个点之间画出一条直线
		}
		previous_p = node->value.p;										//将上一个点更新为当前点
		node = node->next;												//链表指针下移,指向下一个节点
	}
}


//***********************************************
//响应函数,记录鼠标点信息
//传递过来的参数:鼠标事件,鼠标事件发生处的坐标,FLAG
//***********************************************
static void record_point(int event, int x, int y, int flags, void *)
{
	if ((event == CV_EVENT_MOUSEMOVE) && (flags&CV_EVENT_FLAG_LBUTTON))	//鼠标左键按下并且光标移动
	{

		cout << "Mouse Event" << endl;
		pointNode *node = new pointNode;								//new出当前节点
		if (heapPoint_num == 0)											//如果这是要记录的第一个点
		{
			heapPoint->next = node;										//就将起始指针指向当前节点
		}
		else															//如果这不是要记录的第一个点
		{
			last_node->next = node;										//将上一个节点的指针指向当前节点
		}


		Point p = Point(x, y);											//当前要记录的点
		current = clock();												//clock返回ms, time则返回s
		duration = (double)(current - previous);						//返回的是double类型的s


																		
		if (duration > 200)												//如果停顿时间很长,则重新起点画线,经验阈值200
		{
			point_num = 0;
		}
		

		
		if (point_num != 0)												//判断当前点是否是起点,写入当前节点标志位
		{
			node->value.start = false;
		}
		else
		{
			node->value.start = true;
		}

		node->value.p = p;												//将当前点写入当前节点
		node->next = NULL;												//当前节点的next指针赋值为NULL,代表终节点
		last_node = node;												//将当前节点的地址保存一份到last_node中



		previous = current;												//将先前时间更新为当前时间
		heapPoint_num++;												//节点总数量+1
		point_num++;													//当前连续节点总数量+1

	}
}


void main()
{
	VideoCapture cap(0);												//打开电脑摄像头
	if (!cap.isOpened())
	{
		cout << "error" << endl;
		waitKey(0);
		return;
	}

	
	int w = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_WIDTH));			//获得cap的分辨率
	int h = static_cast<int>(cap.get(CV_CAP_PROP_FRAME_HEIGHT));
	Size videoSize(w, h);
	VideoWriter writer("RecordVideo.avi", CV_FOURCC('M', 'J', 'P', 'G'), 25, videoSize);


	int key;															//记录键盘按键
	char startOrStop = 1;												//0  开始录制视频; 1 结束录制视频
	char flag = 0;														//正在录制标志 0-不在录制; 1-正在录制

	namedWindow("image");												//打开一个窗口,名字叫image
	setMouseCallback("image", record_point);							//回调record_point(),记录鼠标点的信息




	while (1)
	{
		cap >> frame;													//从摄像头读入一帧
		key = waitKey(100);												//读入键盘按键
		draw_point();													//画点
		if (key == 32)													//按下空格开始录制、暂停录制   可以来回切换
		{
			startOrStop = 1 - startOrStop;								//录制开始、录制暂停的切换标志
			if (startOrStop == 0)										//如果录制开始,置flag=1,表明正在录制
			{
				flag = 1;
			}
		}
		if (key == 27)													//按下ESC退出整个程序,保存视频文件到磁盘
		{
			break;
		}

		if (startOrStop == 0 && flag == 1)								//如果接收到录制命令并且录制已经开始
		{
			writer << frame;											//将当前帧继续写入视频
			cout << "recording" << endl;
		}
		else if (startOrStop == 1)										//如果接收到录制结束命令
		{
			flag = 0;													//将正在录制标志flag置0,停止录制
			cout << "end recording" << endl;

		}
		imshow("image", frame);											//不断在窗口显示画线和摄像头图像
		
	}
	cap.release();														//摄像头释放
	writer.release();													//视频写入器释放
	destroyAllWindows();												//销毁所有打开的windows
}

*/

Tips
视频获取同时对帧操作,希望后一帧的图像不覆盖前一帧画的点和线,只有与把所有点的数据先存储起来,等读入每一帧再重新从头到尾画上去


BY LEO ON DEC8,2018, AT YUQUAN CAMPUS ZJU

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值