我是靠谱客的博主 贤惠御姐,这篇文章主要介绍Opencv基础 (二):使用OpenCV读取和写入视频,现在分享给大家,希望可以做个参考。


在OpenCV中读写视频与读写图像非常相似。视频就是一系列通常被称为帧的图像。所以,你需要做的就是循环播放视频序列中的所有帧,然后一次处理一帧。在这篇文章中,我们将演示如何从一个文件、一个图像序列和一个网络摄像头读取、显示和写入视频。我们还将研究流程中可能发生的一些错误,并帮助理解如何解决这些错误。

让我们先看一下读取视频文件的代码示例。它本质上包含了从磁盘读取视频并显示它的功能。随着您的深入,我们将详细讨论这个实现中使用的函数。

Python

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import cv2 # Create a video capture object, in this case we are reading the video from a file vid_capture = cv2.VideoCapture('Resources/Cars.mp4') if (vid_capture.isOpened() == False): print("Error opening the video file") # Read fps and frame count else: # Get frame rate information # You can replace 5 with CAP_PROP_FPS as well, they are enumerations fps = vid_capture.get(5) print('Frames per second : ', fps,'FPS') # Get frame count # You can replace 7 with CAP_PROP_FRAME_COUNT as well, they are enumerations frame_count = vid_capture.get(7) print('Frame count : ', frame_count) while(vid_capture.isOpened()): # vid_capture.read() methods returns a tuple, first element is a bool # and the second is frame ret, frame = vid_capture.read() if ret == True: cv2.imshow('Frame',frame) # 20 is in milliseconds, try to increase the value, say 50 and observe key = cv2.waitKey(20) if key == ord('q'): break else: break # Release the video capture object vid_capture.release() cv2.destroyAllWindows()

C++

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Include Libraries #include<opencv2/opencv.hpp> #include<iostream> // Namespace to nullify use of cv::function(); syntax using namespace std; using namespace cv; int main() { // initialize a video capture object VideoCapture vid_capture("Resources/Cars.mp4"); // Print error message if the stream is invalid if (!vid_capture.isOpened()) { cout << "Error opening video stream or file" << endl; } else { // Obtain fps and frame count by get() method and print // You can replace 5 with CAP_PROP_FPS as well, they are enumerations int fps = vid_capture.get(5); cout << "Frames per second :" << fps; // Obtain frame_count using opencv built in frame count reading method // You can replace 7 with CAP_PROP_FRAME_COUNT as well, they are enumerations int frame_count = vid_capture.get(7); cout << " Frame count :" << frame_count; } // Read the frames to the last frame while (vid_capture.isOpened()) { // Initialise frame matrix Mat frame; // Initialize a boolean to check if frames are there or not bool isSuccess = vid_capture.read(frame); // If frames are present, show it if(isSuccess == true) { //display frames imshow("Frame", frame); } // If frames are not there, close it if (isSuccess == false) { cout << "Video camera is disconnected" << endl; break; } //wait 20 ms between successive frames and break the loop if key q is pressed int key = waitKey(20); if (key == 'q') { cout << "q key is pressed by the user. Stopping the video" << endl; break; } } // Release the video capture object vid_capture.release(); destroyAllWindows(); return 0; }

以下是我们将在这篇博文中讨论的OpenCV视频I/O的主要功能:

  • cv2.videoccapture—创建一个视频捕获对象,它将帮助流或显示视频。
  • cv2.VideoWriter -将输出的视频保存到一个目录中。
  • 此外,我们还讨论了其他需要的函数,如cv2.imshow(), cv2.waitKey()和get()方法,用于读取视频元数据,如帧高度,宽度,帧数等。

video
在这个例子中,你将读取上面的视频(’ Cars.mp4 ')并显示它

现在让我们从它开始。

首先,我们导入OpenCV库。请注意,对于c++,你通常会使用cv::function(),但因为我们选择使用cv命名空间(使用cv命名空间),所以我们可以直接访问OpenCV函数,而不需要在函数名前添加cv::。

C++

复制代码
1
2
3
4
5
6
// Include Libraries #include<opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv;

从文件中读取视频

面的代码块使用VideoCapture()类来创建VideoCapture对象,然后我们将使用它来读取视频文件。使用这个类的语法如下所示:

复制代码
1
2
VideoCapture(path, apiPreference)

第一个参数是视频文件的文件名/路径。第二个参数是一个可选参数,指示API首选项。与这个可选参数相关的一些选项将在下面进一步讨论。要了解更多关于apiPreference,请访问官方文档链接videocaptureapi。

Python

复制代码
1
2
3
# Create a video capture object, in this case we are reading the video from a file vid_capture = cv2.VideoCapture('Resources/Cars.mp4')

C++

复制代码
1
2
3
# Create a video capture object, in this case we are reading the video from a file VideoCapture vid_capture("Resources/Cars.mp4");

现在我们有了一个视频捕获对象,我们可以使用isopen()方法来确认视频文件已成功打开。isopen()方法返回一个布尔值,指示视频流是否有效。否则,您将得到一条错误消息。错误消息可以包含许多内容。其中之一就是整个视频都损坏了,或者一些帧损坏了。假设视频文件已成功打开,我们可以使用get()方法检索与视频流相关联的重要元数据。请注意,此方法不适用于网络摄像机。get()方法从这里记录的选项枚举列表中获取一个参数。在下面的例子中,我们提供了数值5和7,它们对应于帧速率(CAP_PROP_FPS)和帧计数(CAP_PROP_FRAME_COUNT)。可以提供数值或名称。

Python

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
if (vid_capture.isOpened() == False): print("Error opening the video file") else: # Get frame rate information fps = int(vid_capture.get(5)) print("Frame Rate : ",fps,"frames per second") # Get frame count frame_count = vid_capture.get(7) print("Frame count : ", frame_count)

C++

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
if (!vid_capture.isOpened()) { cout << "Error opening video stream or file" << endl; } else { // Obtain fps and frame count by get() method and print int fps = vid_capture.get(5): cout << "Frames per second :" << fps; frame_count = vid_capture.get(7); cout << "Frame count :" << frame_count; }

在获取与视频文件相关联的所需元数据之后,我们现在就可以从文件中读取每个图像帧了。这是通过创建一个循环并使用vid_capture.read()方法从视频流中每次读取一帧来实现的。

vid_capture.read()方法返回一个元组,其中第一个元素是布尔值,下一个元素是实际的视频帧。当第一个元素为True时,它表示视频流包含一个要读取的帧。

如果有要读取的帧,那么可以使用imshow()在窗口中显示当前帧,否则退出循环。注意,您还使用waitKey()函数在视频帧之间暂停20毫秒。调用waitKey()函数可以监视键盘以获取用户输入。例如,在本例中,如果用户按下' q '键,则退出循环。

Python

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(vid_capture.isOpened()): # vCapture.read() methods returns a tuple, first element is a bool # and the second is frame ret, frame = vid_capture.read() if ret == True: cv2.imshow('Frame',frame) k = cv2.waitKey(20) # 113 is ASCII code for q key if k == 113: break else: break

C++

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
while (vid_capture.isOpened()) { // Initialize frame matrix Mat frame; // Initialize a boolean to check if frames are there or not bool isSuccess = vid_capture.read(frame); // If frames are present, show it if(isSuccess == true) { //display frames imshow("Frame", frame); } // If frames are not there, close it if (isSuccess == false) { cout << "Video camera is disconnected" << endl; break; } //wait 20 ms between successive frames and break the loop if key q is pressed int key = waitKey(20); if (key == 'q') { cout << "q key is pressed by the user. Stopping the video" << endl; break; } }

一旦视频流被完全处理或用户提前退出循环,你释放视频捕获对象(vid_capture)并关闭窗口,使用以下代码:

Python

复制代码
1
2
3
4
# Release the objects vid_capture.release() cv2.destroyAllWindows()

C++

复制代码
1
2
3
4
// Release video capture object vid_capture.release(); destroyAllWindows();

读取图像序列

处理来自图像序列的图像帧与处理来自视频流的图像帧非常相似。只需指定正在读取的图像文件。

在下面的例子中,

  • 继续使用视频捕获对象
  • 但是,您只需指定一个图像序列,而不是指定一个视频文件
    • 使用下面所示的符号(Cars%04d.jpg),其中%04d表示四位数序列命名约定(例如Cars0001.jpg、Cars0002.jpg、Cars0003.jpg等)。
    • 如果您指定了" Race_Cars_%02d.jpg ",那么您将查找的文件的形式:
复制代码
1
2
(Race_Cars_01.jpg, Race_Cars_02.jpg, Race_Cars_03.jpg, etc…).

第一个示例中描述的所有其他代码都是相同的。
Python

复制代码
1
2
vid_capture = cv2.VideoCapture('Resources/Image_sequence/Cars%04d.jpg')

C++

复制代码
1
2
VideoCapture vid_capture("Resources/Image_sequence/Cars%04d.jpg");

从摄像头读取视频

从网络摄像机读取视频流也非常类似于上面讨论的例子。那怎么可能?这都要感谢OpenCV中视频捕获类的灵活性,它有几个方便接受不同输入参数的重载函数。不需要为视频文件或图像序列指定源位置,只需给出一个视频捕获设备索引,如下所示。

  • 如果你的系统有一个内置的网络摄像头,那么摄像头的设备索引将是“0”
  • 如果你有多个摄像头连接到你的系统,那么与每个额外摄像头相关联的设备索引将递增(例如1、2、3等)。

Python

复制代码
1
2
vid_capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)

C++

复制代码
1
2
VideoCapture vid_capture(0);

您可能想知道标志CAP_DSHOW。这是一个可选参数,因此不是必需的。CAP_DSHOW只是另一个视频捕获API首选项,它是directshow通过视频输入的简称。

写视频

现在让我们来看看如何写视频。就像视频读取一样,我们可以编写来自任何源(视频文件、图像序列或网络摄像头)的视频。写入视频文件:

  • 使用get()方法检索图像帧的高度和宽度。
  • 初始化一个视频捕获对象(如前面所讨论的),使用前面描述的任何源代码将视频流读入内存。
  • 创建一个视频写入器对象。
  • 使用视频写入器对象将视频流保存到磁盘。

继续我们的运行示例,让我们首先使用get()方法来获取视频帧的宽度和高度。

Python

复制代码
1
2
3
4
5
6
# Obtain frame size information using get() method frame_width = int(vid_capture.get(3)) frame_height = int(vid_capture.get(4)) frame_size = (frame_width,frame_height) fps = 20

C++

复制代码
1
2
3
4
5
6
// Obtain frame size information using get() method Int frame_width = static_cast<int>(vid_capture.get(3)); int frame_height = static_cast<int>(vid_capture.get(4)); Size frame_size(frame_width, frame_height); int fps = 20;

如前所述,videoccapture()类的get()方法需要:

  • 来自枚举列表的单个参数,它允许您检索与视频帧关联的各种元数据。

可用的元数据非常广泛,可以在这里找到。

  • 在本例中,您通过指定3 (CAP_PROP_FRAME_WIDTH)和4 (CAP_PROP_FRAME_HEIGHT)来检索帧的宽度和高度。当将视频文件写入磁盘时,您将在下面进一步使用这些尺寸。

为了编写视频文件,首先需要从VideoWriter()类中创建一个视频编写器对象,如下面的代码所示。

以下是VideoWriter()的语法:

复制代码
1
2
VideoWriter(filename, apiPreference, fourcc, fps, frameSize[, isColor]

VideoWriter()类接受以下参数:

  • filename:输出视频文件的路径名
  • apiPreference: API后端标识符
  • fourcc: 4个字符的编解码器代码,用于压缩帧(fourcc)
  • fps:创建的视频流的帧率
  • frame_size:视频帧的大小
  • isColor:如果不是0,编码器将期望并编码彩色帧。否则它将与灰度帧工作(该标志目前仅在Windows上支持)。

下面的代码创建了视频写入器对象,输出自VideoWriter()类。一个特殊的方便函数用于检索四个字符的编解码器,需要作为视频编写器对象cv2的第二个参数。

  • VideoWriter_fourcc(‘M’, ‘J’, ‘P’, ‘G’) in Python.
  • VideoWriter::fourcc(‘M’, ‘J’, ‘P’, ‘G’) in C++.

视频编解码器指定视频流如何压缩。它将未压缩的视频转换为压缩格式,反之亦然。创建AVIMP4格式,使用以下的fourcc规格:

复制代码
1
2
3
AVI: cv2.VideoWriter_fourcc('M','J','P','G') MP4: cv2.VideoWriter_fourcc(*'XVID')

接下来的两个输入参数指定帧速率(FPS)和帧大小(宽度、高度)。

Python

复制代码
1
2
3
# Initialize video writer object output = cv2.VideoWriter('Resources/output_video_from_file.avi', cv2.VideoWriter_fourcc('M','J','P','G'), 20, frame_size)

C++

复制代码
1
2
3
//Initialize video writer object VideoWriter output("Resources/output.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'),frames_per_second, frame_size);

在您已经创建了一个视频写入器对象,使用它将视频文件写入磁盘,一次一帧,如下面的代码所示。在这里,您正在以每秒20帧的速度将一个AVI视频文件写入磁盘。请注意我们是如何将前面的例子简化为循环的。
Python

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
while(vid_capture.isOpened()): # vid_capture.read() methods returns a tuple, first element is a bool # and the second is frame ret, frame = vid_capture.read() if ret == True: # Write the frame to the output files output.write(frame) else: print(‘Stream disconnected’) break

C++

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
while (vid_capture.isOpened()) { // Initialize frame matrix Mat frame; // Initialize a boolean to check if frames are there or not bool isSuccess = vid_capture.read(frame); // If frames are not there, close it if (isSuccess == false) { cout << "Stream disconnected" << endl; break; } // If frames are present if(isSuccess == true) { //display frames output.write(frame); // display frames imshow("Frame", frame); // wait for 20 ms between successive frames and break // the loop if key q is pressed int key = waitKey(20); if (key == ‘q’) { cout << "Key q key is pressed by the user. Stopping the video" << endl; break; } } }

最后,在下面的代码中,释放视频捕获和视频编写对象。
Python

复制代码
1
2
3
4
# Release the objects vid_capture.release() output.release()

C++

复制代码
1
2
3
4
// Release the objects vid_capture.release(); output.release();

最后

以上就是贤惠御姐最近收集整理的关于Opencv基础 (二):使用OpenCV读取和写入视频的全部内容,更多相关Opencv基础内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(92)

评论列表共有 0 条评论

立即
投稿
返回
顶部