OpenCV中 视频的读取、图像序列的读取、摄像头的调用

说明

最近看了一些C++中的流的概念。下面几句话,是自己结合看到的书和博文所得到的理解,阅历有限,欢迎留言指正哈!!!

1、C++中,由于类可以实例化创建对象,所以,其实类的实例化创建对象的过程就是创建流的过程。所以我们有时候也把类的实例化创建的对象叫做流对象。任何一个类都可以实例化创建对象,也即任何一个类都可以创建流(流对象),当然了,也要排除某些基类。

2、C++中的数据传递是靠 “流” 来实现的。流,也叫流对象,你就把类的实例化得到的对象叫做流(流对象),对象可以调用许多的方法,那么流(流对象)也可以调用许多的方法。这样理解的话,流的本质就是一个对象(流对象)。

3、在实现C++的数据传递过程中:一般地,流对象都要与某个具体的设备或者文件相联系起来。当流对象与某个具体的设备或文件相联系起来之后,此时,对流对象的操作就等价于是对某个设备或文件的操作,对某个设备或文件的操作就等价于是对流对象的操作。这种操作关系可以简化成:流对象=某个具体的设备或文件
经常接触到的,C++中的流主要分成三类:

  • 标准I/O流:“标准”的意思就是,默认的程序输入是指从键盘输入,默认的程序输出是指输出到屏幕。
  • 文件I/O流:程序输入是指从文件读取数据,程序输出是指把数据写入文件。
  • 字符串I/O流:程序输入是指从字符串中读取数据,程序输出是指把数据写入字符串中。

4、从“流”的观点来理解C++中的 cin >> xcout << y 的含义:

  • cin >> x :由于“cin”是一个标准输入流对象,而“>>”是流中的提取运算符。因为在头文件istream中创建“cin”标准输入流对象时,就已经把该流对象与某个具体的设备(这里指键盘)建立了联系,所以,对输入流对象“cin”的操作就等价于是对键盘的操作,对键盘的操作就等价于是对输入流对象“cin”的操作。这里的含义是,从输入流对象“cin”中去提取数据,然后把从输入流对象“cin”中提取出来的数据赋值给程序中的x变量(也即,从键盘输入中去提取数据,然后把从键盘输入中提取出来的数据赋值给程序中的x变量)。
  • cout << y :由于“cout”是一个标准输出流对象,而“<<”是流中的插入运算符。因为在头文件ostream中创建“cout”标准输出流对象时,就已经把该流对象与某个具体的设备(这里指屏幕)建立了联系,所以,对输出流对象“cout”的操作就等价于是对屏幕的操作,对屏幕的操作就等价于是对输出流对象“cout”的操作。这里的含义是,把程序中y变量的值插入到输出流对象“cout”中去,(也即,把程序中y变量的值插入到屏幕中去)。

5、OpenCV中,视频数据的读取、图像序列的读取、摄像头的调用,三者都是使用的 cv::VideoCapture类,该类的作用是创建一个 视频流对象(包括输入视频流对象和输出视频流对象);下面的视频,你就要把它理解成一个文件,视频文件。

一、视频的读取

#include<iostream>
#include<opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    
    
	//cv::VideoCapture video_capture;//默认构造,创建视频流video_caputure,但此时视频流还没有与某个具体的视频文件相联系
	//video_capture.open("C:/Users/Administrator/Desktop/testVideo.mp4");//视频流调用open方法打开了testVideo.mp4视频,表示video_capture视频流已经与testVideo.mp4视频文件建立联系了。此时,对video_capture视频流的操作就等价于是对testVideo.mp4文件的操作,对testVideo.mp4文件的操作就等价于是对video_capture视频流的操作。
	
	//也可以带参构造,创建视频流video_caputure,上面默认构造的区别是:使用带参构造创建的视频流video_caputure已经与某个具体的视频文件testVideo.mp4建立联系了,因为带参构造函数中会去自动调用open函数,去建立视频流video_caputure与具体视频文件test.Video.mp4的联系。此时,对video_capture视频流的操作也就等价于是对testVideo.mp4文件的操作,对testVideo.mp4文件的操作也就等价于是对video_capture视频流的操作。
	cv::VideoCapture video_capture("C:/Users/Administrator/Desktop/testVideo.mp4");
	
	//判断视频是否读取成功
	if (video_capture.isOpened()) {
    
    
		cout << "视频读取成功" << endl;
		cout << "视频文件的当前位置=" << video_capture.get(CAP_PROP_POS_MSEC) << endl;
		cout << "视频流中图像的宽度=" << video_capture.get(CAP_PROP_FRAME_WIDTH) << endl;
		cout << "视频流中图像的高度=" << video_capture.get(CAP_PROP_FRAME_HEIGHT) << endl;
		cout << "视频流中图像的帧率=" << video_capture.get(CAP_PROP_FPS) << endl;
		cout << "视频流中图像的帧数=" << video_capture.get(CAP_PROP_FRAME_COUNT) << endl;
	}
	else {
    
    
		cout << "视频读取失败" << endl;
		return 0;
	}
	
	//获取视频中的图像
	while (1) {
    
    //循环:将视频流中的图像一帧一帧的赋值给Mat对象
		cv::Mat frame;
		video_capture >> frame;//重点,从视频流对象video_capture中提取数据(图像),并将提取出来的数据赋值给frame
		if (frame.empty()) {
    
    //true说明视频流的图像已经提取完啦
			cout << "视频流的图像已经读取完啦" << endl;
			break;
		}
		//
		cv::namedWindow("myWindow");//创建窗口
		cv::imshow("myWindow", frame);
		//cv::waitKey(1000);//暂停1000ms,即显示一帧之后,停顿一秒
		cv::waitKey(1000 / video_capture.get(CAP_PROP_FPS));//即为帧率的速度
	}
	
	return 0;
}

运行结果
在这里插入图片描述

二、图像序列的读取(两种方式)

有时候,我们从数据库中下载下来的数据,有些直接是视频,而有些是一帧一帧的图像,就比如下面的这种情况:
在这里插入图片描述

方式一(笨一点的)

方法一:将每个图片的文件名按顺序存放在一个文本文件中,然后可以从文本文件中逐个提取文件名。
方法二:先将数字0015转化成字符串“0015”,然后再把字符串“0015”与字符串“frame_”和字符串“.jpg”一块拼凑成一个新的字符串“frame_0015.jpg”(即为图像的名字),最后再采取读取图像的方式逐一读取文件夹下的所有图像。

方式二(推荐的)

殊不知,在OpenCV中可以直接使用 VideoCapture类 来读取图像序列的

#include<iostream>
#include<opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    
    
	//图像名称frame_0015.jpg:采用"前缀+%04d+后缀"的形式,这里为"frame_%04d.jpg";
	//图像名称frame_015.jpg:采用"前缀+%03d+后缀"的形式,这里为"frame_%03d.jpg";
	//图像名称frame_15.jpg:采用"前缀+%02d+后缀"的形式,这里为"frame_%02d.jpg";

	//图像名称frame0015.jpg:采用"前缀+%04d+后缀"的形式,这里为"frame%04d.jpg";
	//图像名称frame015.jpg:采用"前缀+%03d+后缀"的形式,这里为"frame%03d.jpg";
	//图像名称frame15.jpg:采用"前缀+%02d+后缀"的形式,这里为"frame%02d.jpg";
	string first_image = "C:/....../frame_%04d.jpg";
	cv::VideoCapture image_sequence(first_image);//image_sequence:图像序列流

	if (image_sequence.isOpened()) {
    
    
		cout << "图像序列读取成功" << endl;
	}
	else {
    
    
		cout << "图像序列读取失败" << endl;
		return -1;
	}

	//获取图像序列中的图像
	while (1) {
    
    //循环:将图像序列中的图像一帧一帧的赋值给Mat对象
		cv::Mat frame;
		image_sequence >> frame;//重点,从图像序列流中提取数据(图像),并将提出出来的数据帧赋值给frame
		if (frame.empty()) {
    
    //true说明图像序列中的图像已经提取完啦
			cout << "图像序列中的图像已经读取完啦" << endl;
			break;
		}
		//
		cv::namedWindow("myWindow");//创建窗口
		cv::imshow("myWindow", frame);
		cv::waitKey(1000);//暂停1000ms,即显示一帧之后,停顿一秒
	}

	return 0;
}

三、摄像头的调用

1、调用摄像头与读取视频文件相比,只有一行代码不同;
2、从摄像头中读取图像数据的方式与视频中读取图像数据的方式相同,都是通过 “>>” 符号读取当前时刻相机拍摄到的图像。

#include<iostream>
#include<opencv2\opencv.hpp>

using namespace std;
using namespace cv;

int main() {
    
    
	//cv::VideoCapture video_capture;//默认构造,创建视频流
	//video_capture.open("C:/Users/Administrator/Desktop/testVideo.mp4");//将视频流与某个具体的视频文件联系起来
	
	//也可以带参构造,创建视频流,构造函数中自动调用open函数,将视频流与某个具体的视频文件联系起来
	//cv::VideoCapture video_capture("C:/Users/Administrator/Desktop/testVideo.mp4");

	//调用摄像头
	cv::VideoCapture video_capture(0);//设备的第一个摄像头
	
	//判断视频是否读取成功
	if (video_capture.isOpened()) {
    
    
		cout << "视频读取成功" << endl;
		cout << "视频文件的当前位置=" << video_capture.get(CAP_PROP_POS_MSEC) << endl;
		cout << "视频流中图像的宽度=" << video_capture.get(CAP_PROP_FRAME_WIDTH) << endl;
		cout << "视频流中图像的高度=" << video_capture.get(CAP_PROP_FRAME_HEIGHT) << endl;
		cout << "视频流中图像的帧率=" << video_capture.get(CAP_PROP_FPS) << endl;
		cout << "视频流中图像的帧数=" << video_capture.get(CAP_PROP_FRAME_COUNT) << endl;
	}
	else {
    
    
		cout << "视频读取失败" << endl;
		return 0;
	}
	
	//获取视频中的图像
	while (1) {
    
    //循环,将视频流中的图像一帧一帧的赋值给Mat对象
		cv::Mat frame;
		video_capture >> frame; //从视频流中提数据(图像),并将提取出来的数据赋值给frame
		if (frame.empty()) {
    
    //true说明已经是视频流的图像已经提取完啦
			cout << "视频流中的图像已经读取完啦" << endl;
			break;
		}
		//
		cv::namedWindow("myWindow");
		cv::imshow("myWindow", frame);
		//cv::waitKey(1000);//暂停1000ms,即显示一帧之后,停顿一秒
		cv::waitKey(1000 / video_capture.get(CAP_PROP_FPS));//即为帧率的速度
	}
	
	return 0;
}

运行结果
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_45580017/article/details/129011770