关键词:
使用OpenCV读取和编写视频
在OpenCV中读取和写入视频与读取和写入图像非常相似。视频只不过是一系列通常被称为帧的图像。因此,您只需要在视频序列中循环所有帧,然后一次处理一帧。在这篇文章中,我们将演示如何从文件、图像序列和网络摄像头中读取、显示和写入视频。我们还将调查流程中可能出现的一些错误,并帮助了解如何解决这些错误。
1.读取视频
让我们先浏览一下读取视频文件的代码示例。这本质上包含从磁盘读取视频并显示它的功能。随着您进一步推进,我们将详细讨论此实现中使用的功能。
Python
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++
// 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.VideoCapture - 创建一个视频捕获对象,这将有助于流式传输或显示视频。
- cv2.VideoWriter - 将输出视频保存到目录中。
此外,还有其他需要的功能,如cv2.imshow()、cv2.waitKey()和get()方法,该方法用于读取视频元数据,如帧高度、宽度、fps等。
1.1 从一个文件中读取
下面的下一个代码块使用VideoCapture()类创建一个VideoCapture对象,然后我们将使用它来读取视频文件。使用此类的语法如下所示:
VideoCapture(path, apiPreference)
Python
# Create a video capture object, in this case we are reading the video from a file
vid_capture = cv2.VideoCapture('Resources/Cars.mp4')
C++
# Create a video capture object, in this case we are reading the video from a file
VideoCapture vid_capture("Resources/Cars.mp4");
isOpened()
现在我们有一个视频捕获对象,我们可以使用isOpened()方法来确认视频文件是否已成功打开。isOpened()方法返回一个布尔值,指示视频流是否有效。否则,您将收到一条错误消息。错误信息可能意味着很多事情。其中之一是整个视频被损坏,或者一些帧被损坏了。
假设视频文件已成功打开,我们可以使用get()方法检索与视频流关联的重要元数据。请注意,这种方法不适用于网络摄像头。Get()方法从此处记录的枚举选项列表中取出单个参数。
在下面的示例中,我们提供了数字值5和7,它们对应于帧速(CAP_PROP_FPS)和帧计数(CAP_PROP_FRAME_COUNT)。可以提供数字值或名称。
Python
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++
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()函数在视频帧之间暂停20ms。调用waitKey()函数可以让您监控键盘的用户输入。例如,在这种情况下,如果用户按下“q”键,您将退出循环。
Python
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++
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
# Release the objects
vid_capture.release()
cv2.destroyAllWindows()
C++
// Release video capture object
vid_capture.release();
destroyAllWindows();
1.2 从图像序列中读取
从图像序列中处理图像帧与从视频流中处理帧非常相似。只需指定正在读取的图像文件。
在下面的示例中,使用视频捕获对象
但是,您只需指定图像序列,而不是指定视频文件
使用下图所示的符号(Cars%04d.jpg),其中%04d表示四位数的序列命名约定(例如Cars0001.jpg、Cars0002.jpg、Cars0003.jpg等)。
如果您指定了“Race_Cars_%02d.jpg”,那么您将寻找表单的文件:
(Race_Cars_01.jpg、Race_Cars_02.jpg、Race_Cars_03.jpg等…)。
第一个示例中描述的所有其他代码都是一样的。
Python
vid_capture = cv2.VideoCapture('Resources/Image_sequence/Cars%04d.jpg')
C++
VideoCapture vid_capture("Resources/Image_sequence/Cars%04d.jpg");
1.3 从网络摄像头读取
从网络摄像头阅读视频
从网络摄像头读取视频流也与上面讨论的示例非常相似。这怎么可能?这都要归功于OpenCV中视频捕获类的灵活性,为了方便起见,该类有几个重载功能,可以接受不同的输入参数。与其为视频文件或图像序列指定源位置,您只需给出视频捕获设备索引,如下所示。
如果您的系统有一个内置的网络摄像头,那么相机的设备索引将是“0”。
如果您的系统连接了多个摄像头,则与每个附加相机关联的设备索引会增加(例如1、2等)。
Python
vid_capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
C++
VideoCapture vid_capture(0);
2.写入视频
现在让我们来看看如何写入视频。就像视频读取一样,我们可以写入来自任何来源(视频文件、图像序列或网络摄像头)的视频。要编写视频文件:
- 使用get()方法检索图像帧的高度和宽度。
- 初始化视频捕获对象(如前几节所述),使用之前描述的任何来源将视频流读取到内存中。
- 创建一个视频编写器对象。
- 使用视频编写器对象将视频流保存到磁盘
继续我们的运行示例,让我们从使用get()方法获取视频帧宽度和高度开始。
Python
# 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++
// 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;
如前所述,VideoCapture()类的get()方法需要:
- 枚举列表中的单个参数,允许您检索与视频帧关联的各种元数据。
在这里下,通过指定3(CAP_PROP_FRAME_WIDTH)和4(CAP_PROP_FRAME_HEIGHT)来检索帧宽度和高度。在将视频文件写入磁盘时,您将在下面使用这些维度。
要编写视频文件,您需要首先从VideoWriter()类创建一个视频写入对象,如下代码所示。
VideoWriter():
VideoWriter(filename, apiPreference, fourcc, fps, frameSize[, isColor])
VideoWriter()类接受以下参数:
- 文件名:输出视频文件的路径名
- apiPreference:API后端标识符
- Fourcc:编解码器的4个字符代码,用于压缩
- Fps:创建的视频流的帧速率
- Frame_size:视频帧的大小
- isColor:如果不是零,编码器将期望并编码颜色帧。否则,它将适用于灰度帧(该标志目前仅在Windows上受支持)。
以下代码创建视频编写器对象,从VideoWriter()类输出。使用特殊的便利功能来检索四字符编解码器,这是视频编写器对象cv2的第二个参数。
- Python:VideoWriter_fourcc(‘M’、‘J’、‘P’、‘G’)
- C++:VideoWriter::fourcc(‘M’, ‘J’, ‘P’, ‘G’)
视频编解码器指定了视频流是如何压缩的。它将未压缩的视频转换为压缩格式,反之亦然。要创建AVI或MP4格式:
- AVI:cv2.VideoWriter_fourcc(‘M’,‘J’,‘P’,‘G’)
- MP4:cv2.VideoWriter_fourcc(*‘XVID’)
接下来的两个输入参数指定FPS中的帧速率和帧大小(宽度、高度)。
Python
# Initialize video writer object
output = cv2.VideoWriter('Resources/output_video_from_file.avi', cv2.VideoWriter_fourcc('M','J','P','G'), 20, frame_size)
C++
//Initialize video writer object
VideoWriter output("Resources/output.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'),frames_per_second, frame_size);
现在已经创建了一个视频写入器对象,请使用它将视频文件写入磁盘,一次一帧。在这里,您正在以每秒20帧的速度将AVI视频文件写入磁盘。注意我们如何简化为从前面的示例中循环。
Python
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++
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
# Release the objects
vid_capture.release()
output.release()
C++
// Release the objects
vid_capture.release();
output.release();
3.读取或写入视频时可能面临的错误
3.1 视频读取
在读取帧时,如果路径错误或文件损坏或帧缺失,它可能会抛出错误。这就是为什么我们在while循环中使用if语句。如果ret == True,可以在行中看到。这样,只有当框架存在时,它才会处理它。以下是在这种情况下观察到的错误日志示例。它不是完整的日志,只包含关键参数。
cap_gstreamer.cpp:890: error: (-2) GStreamer: unable to start pipeline in function
3.2 错误的路径:
当您提供视频的错误路径时,它不会使用VideoCapture()类显示任何错误或警告。当您尝试对视频帧进行任何操作时,会出现这些问题。为此,您可以使用一个简单的if块来检查您是否像我们在示例中所做的那样阅读了视频文件。这应该打印以下消息。
Error opening the video file
3.3 视频写作
在此步骤中,可能会出现各种错误。最常见的是帧大小错误和api首选项错误。如果帧大小与视频不相似,那么即使我们在输出目录中收到一个视频文件,它也会是空白的。
如果您正在使用NumPy形状方法来检索帧大小,请记住反向输出,因为OpenCV将返回高度x宽度x通道。如
果它抛出api首选项错误,我们可能需要在VideoCapture()参数中传递CAP_ANY标志。这可以在网络摄像头示例中看到,我们使用CAP_DHOW来避免生成警告。
以下是错误日志的示例:
当CAP_DSHOW未通过时:
[WARN:0]...cap_msmf.cpp(438) …. terminating async callback
当帧尺寸不正确时:
cv2.error: OpenCV(4.5.2) :-1: error: (-5:Bad argument) in function 'VideoWriter'
> Overload resolution failed:
> - Can't parse 'frameSize'. Sequence item with index 0 has a wrong type
> - VideoWriter() missing required argument 'frameSize' (pos 5)
> - VideoWriter() missing required argument 'params' (pos 5)
> - VideoWriter() missing required argument 'frameSize' (pos 5)VideoWriter()缺少必需的参数'frameSize'(pos 5)
入门opencv(代码片段)
电气人学opencvDay1(图片与视频的读取及可能出现的问题)在学习opencv之前,首先应该选择语言。在我的认知里c++与python是最合适的两种,由于个人的学习原因选择了python,所以以下所有的程序都是python实现... 查看详情
tensorflow初入门(代码片段)
想要使用Tensorflow必须先要安装上这个,我用的是win10系统,之前也装了python环境所以我就直接使用pipinstalltensorflow命令安装上就可以使用了。 想要使用tensorflow,就必须明白tensorflow:1、使用图(graph)来表示计算任务。2、在... 查看详情
opencv最详细入门-python(代码全部可以直接运行)(代码片段)
OpenCV详细入门(基础篇)一、上篇回顾在上一篇(OpenCV最详细入门(一)-python(代码全部可以直接运行))中我们学会了使用OpenCV显示图片和视频、更改图片颜色通道、灰度图、滤波、形态学和图... 查看详情
c/c++vs2017opencv简单入门(代码片段)
...关的知识点,只是简单学了一点皮毛!目录一、OpenCV环境搭建二、使用opencv常用接口说明使用案例1. 图像色彩空间转换2. Mat对象的创建与赋值3. 图像像素的读写操作4. 图像像素的算术操作5. 滚动条操作演示6. 键盘响... 查看详情
超详细opencv之python操作(代码片段)
简介OpenCV是一款由Intel公司俄罗斯团队发起并参与和维护的一个计算机视觉处理开源软件库,支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。OpenCV-PythonOpenCV-Python是一个Python绑定库,旨在解决计算... 查看详情
尝试在openCV(python)中使用HoughCircles检测所有圆圈
】尝试在openCV(python)中使用HoughCircles检测所有圆圈【英文标题】:TryingtodetectallthecircleswithHoughCirclesinopenCV(python)【发布时间】:2021-01-2604:07:26【问题描述】:我正在关注本教程:https://www.pyimagesearch.com/2014/07/21/detecting-circles-image... 查看详情
opencv入门笔记图片的文件操作
...一下重要的几个,设计基本图片处理的函数,依次来了解OpenCV的入门知识。具体的具体使用方法还是以官方的API【OfficialTutorials】【Python-OpenCV】为准。imread图片读取函数。使用方法例如以下#readimagewithcolorimg=cv2.imread("./lena.jpg")#ORr... 查看详情
opencv图像处理应用(面向python)之入门操作
OpenCV图像处理应用(面向Python)欢迎来到梁老湿课堂课前闲聊进入正题使用的软件我们先来进行图像读取、显示、保存温馨提醒图像像素处理课后练习课堂总结多练多学多坚持,我们下期再见。欢迎来到梁老湿课堂版... 查看详情
史上最全的opencv入门教程!这篇够你学习半个月了!万字长文入门(代码片段)
一、PythonOpenCV入门欢迎阅读系列教程,内容涵盖OpenCV,它是一个图像和视频处理库,包含C++,C,Python和Java的绑定。OpenCV用于各种图像和视频分析,如面部识别和检测,车牌阅读,照片编辑,高级机器人视觉,光学字符识别等等... 查看详情
opencv-python极速入门
opencv-python极速入门什么是OpenCV-Python?OpenCV是一个开源的计算机视觉(computervision)和机器学习库。它拥有超过2500个优化算法,包括经典和最先进的计算机视觉和机器学习算法。它有很多语言接口,包括Python、Java、... 查看详情
dlib vs opencv 啥时候使用
】dlibvsopencv啥时候使用【英文标题】:dlibvsopencvwhichonetousewhendlibvsopencv什么时候使用【发布时间】:2016-09-0922:44:51【问题描述】:我目前正在使用Python学习OpenCVAPI,一切都很好。我正在取得不错的进展。它的一部分来自Python语法... 查看详情
为python(使用opencv)包装c ++类,给出错误
】为python(使用opencv)包装c++类,给出错误【英文标题】:Wrappingc++classforpython(withopencv),givesERROR【发布时间】:2016-02-0509:41:47【问题描述】:我正在尝试在.so文件中生成C++代码并在python中导入.so文件。我的C++代码是extern"C"inttop(in... 查看详情
将opencv c++代码转换为opencv python代码
】将opencvc++代码转换为opencvpython代码【英文标题】:convertopencvc++codetoopencvpythoncode【发布时间】:2020-12-0518:39:15【问题描述】:您好,我有以下c++代码并想将其转换为python代码,但是对于cv2,opencv函数在python中不可用。我怎样才... 查看详情
如何从入门开始学习opencv?
一、OpenCV简介OpenCV是一款由Intel公司俄罗斯团队发起并参与和维护的一个计算机视觉处理开源软件库,支持与计算机视觉和机器学习相关的众多算法,并且正在日益扩展。1.1OpenCV的优势:编程语言OpenCV基于C++实现,同时提供python,... 查看详情
使用多线程调试 DLL (/MDd) C 运行时库构建静态 Opencv 库
】使用多线程调试DLL(/MDd)C运行时库构建静态Opencv库【英文标题】:BuildthestaticOpencvlibrarywithmulti-threadeddebugDLL(/MDd)Cruntimelibrary【发布时间】:2013-11-0416:34:28【问题描述】:我现在正在尝试使用cmake构建opencv,如果我使用以下命令:c... 查看详情
python+opencv(入门级)车道线检测学习笔记(代码片段)
文章目录前言一、openCV安装二、尝试使用cv2中库函数1.读取图片2.图片显示3.延时/暂停4.保存图片5.清楚所有窗口三、Canny边缘检测1.高斯滤波2.图片转换3.边缘检测四、ROIandmask五、霍夫变换六、离群值过滤七、最小二乘法拟合八、... 查看详情
python图像处理(opencv入门)
【声明:版权所有,欢迎转载,请勿用于商业用途。联系信箱:feixiaoxing@163.com】 前面我们讨论了fpga的基本操作,这些都是作为整个图像处理的基础部分进行学习的,本质上还是希望用fpga来对部分算法进行加速... 查看详情
学习opencv4基于opencv的手写数字识别(代码片段)
本内容分享于课程《OpenCV入门精讲(C++/Python双语教学)》,地址:OpenCV入门精讲(C++/Python双语教学)如果想提升C++的编程水平,可以参考课程:C++进阶学习OpenCV课程中还有... 查看详情