学习笔记之——Opencv视频处理模块

版权声明: https://blog.csdn.net/gwplovekimi/article/details/80545274

视频信号是重要的视觉信息来源。视频由一系列图像构成,这些图像称为。帧以固定的时间间隔获取(称为帧速率,通常用帧/秒表示)。大多数计算机视觉方面的应用都是基于视频来处理的,为此本博文作为Opencv视频处理模块的学习笔记~

帧的数据类型也是Mat。


读取视频序列。要从视频序列读取帧,只需创建一个cv::VideoCapture类的实例,然后再一个循环中提取并显示视频的每帧,如下面代码所示:

#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<iostream>



using namespace cv;
using namespace std;


int main()
{
	//打开视频文件。创建VideoCapture类对象capture,用初始化为括号里的视频(VideoCapture类的构造函数)。
	//VideoCapture capture("video.mp4");//创建VideoCapture类对象capture
	//或
	VideoCapture capture;
	capture.open("video.mp4");//VideoCapture类的方法
	//0时,打开usb摄像头。输入一个正确的网址,可以加载web上的视频


	//检查是否打开成功
	if (!capture.isOpened())
	{
		cout << "视频没有打开"<<endl;
		return 1;
	}


	//获取视频的帧速率(一般是30或者60)
	double frame_rate = capture.get(CV_CAP_PROP_FPS);
	cout << frame_rate << endl;


	//获取视频的总帧数目
	long num_frame = static_cast<long>(capture.get(CV_CAP_PROP_FRAME_COUNT));
	cout << num_frame << endl;


	//从特定帧开始
	auto position = num_frame/2;
	capture.set(CV_CAP_PROP_POS_FRAMES, position);


	Mat frame;
	namedWindow("提取的视频");


	//根据帧速率计算帧之间的等待时间,单位ms
	int delat = 1000 / frame_rate;

	//循环遍历视频中的全部帧
	while (1)
	{
		capture >> frame;

		if (!frame.empty())//如果读完就结束
		{
			imshow("提取的视频", frame);
		}
		else
		{
			break;
		}

		waitKey(delat);//要有这句,才会输出视频
		//在显示每一帧都采用了延时方法。延时的时长取决于视频的帧频率(fps为帧速率,1000/fps为两帧之间的毫秒数)
		//通过修改delat的值,可以使视频快进或慢进
		//将delat设置为0,按照用户按键,才播放。
	}
	capture.release();//不是必须的(由于在VideoCapture类的析构函数中已经调用了)。用于关闭视频文件
	return 0;
}

具体分析见代码注释。下面再给出一些例程


移动感知(基于光流法)代码:

#include<opencv2\video\tracking.hpp>
#include<opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc.hpp>
#include<iostream>


using namespace cv;
using namespace std;


static void drawOptFlowMap(const Mat & flow, Mat & cflowmap, int step, double, const Scalar & color)
{
	for (int y = 0;y < cflowmap.rows;y += step)//光流图的行,step为步长
	{
		for (int x = 0;x < cflowmap.cols;x += step)
		{
			const Point2f & fxy = flow.at<Point2f>(y, x);//关于Point2f类和at操作请见下面程序补充

			//移动方向线
			line(cflowmap, Point(x, y), Point(cvRound(x + fxy.x), cvRound(y + fxy.y)), color);//cvRound对一个double型的数进行四舍五入,并返回一个整型数
			//line函数可见下面程序补充

			//绿色固定的点。关于circle函数可见下面程序补充
			circle(cflowmap, Point(x, y), 2, color, -1);
		}
	}
}


int main()
{
	//读入视频
	VideoCapture cap("video.mp4");
	if (!cap.isOpened())
	{
		cout << "读取失败" << endl;
		return -1;
	}
	Mat prevgray, gray, flow, cflow, frame;//分别为:前一帧灰度图、当前灰度图、计算出来的光流图、前一帧的RGB图(画出来的光流)、当前帧
	namedWindow("flow", 1);

	while (1)
	{
		cap >> frame;
		//转换为灰度图
		cvtColor(frame, gray, COLOR_BGR2GRAY);
		if (prevgray.data)//uchar类型的指针,指向Mat数据矩阵的首地址。基本就是前一帧图像prevgray有数据,则可以
		{
			//使用Gunnar Farneback算法计算光流(optical flow)密度
			calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
			cvtColor(prevgray, cflow, COLOR_GRAY2BGR);//将前一帧的灰度图转化为RGB图
			//绘制绿点(绘制光流图)
			drawOptFlowMap(flow, cflow, 16, 1.5, Scalar(0, 255, 0));//关于Scalar类见下文程序补充。
			imshow("flow", cflow);
		}
		
		waitKey(16);
	
		//图像交换
		swap(prevgray, gray);//其实就是当前帧会成为下一帧的前一帧
	}

	return 0;
}

效果如下图所示:


处理速度比较慢~~~

对上述程序的一些补充:

Opencv中点的表示:Point类

Point point;

point.x=10;

point.y=8;

或者

Point point=Point(10,8);

另外,在OpenCV中有如下定义:

typedef Point_<int> Point2i;

typedef Point2i Point;

typedef Point_<float> Point2f;

at操作


circle函数


计算光流的CalcOpticalFlowFarneback()函数:


关于line函数


颜色表示,Scalar类:

Scalar()表示具有4个元素的数组,在Opencv中被大量用于传递像素值,如RGB颜色值。而RGB颜色值为3个参数(第四个参数没查到尴尬)Scalar(a,b,c)红色分量为c,绿色分量为b,蓝色分量为a。




猜你喜欢

转载自blog.csdn.net/gwplovekimi/article/details/80545274