苦学Opencv的第十三天:视频处理

Python OpenCV入门到精通学习日记:视频处理

前言

视频处理是计算机视觉领域的一个热门话题。视频不仅仅是一系列静态图像的集合,它包含了随时间变化的动态信息。OpenCV作为一个强大的图像和视频处理库,提供了丰富的功能来处理视频数据。我们将学习如何使用OpenCV进行视频处理。说到底其实还是对图像的处理,毕竟视频就是由大量的图像组成的。

这里我用流程图展示一下视频处理的流程:

帧数据
帧数据
帧结束
开始
打开摄像头
读取帧
显示帧
处理帧
写入处理后的帧到视频文件
检查是否退出
释放资源
结束

1. 读取并显示摄像头视频

处理视频的第一步是捕获视频数据。摄像头视频指的是从摄像头中实时读取到的视频。为了读取并显示摄像头视频,OpenCV提供了VideoCapture类来实现这一功能。这些方法包括摄像头的初始化方法、检验摄像头初始化是否成功的方法、从摄像头中读取帧的方法和关闭摄像头的方法等。

🌟视频是由大量的图像构成的,把这些图像称作

VideoCapture类提供了构造方法VideoCapture(),用于完成摄像头的初始化工作。

capture = cv2.VideoCapture(index)
参数说明:
 capture:要打开的摄像头。
 index:摄像头的设备索引。

例如:

cap = cv2.VideoCapture(0)  # 0代表第一个摄像头设备

⚠️这里需要注意:
摄像头的数量及其设备索引的先后顺序由操作系统决定,因为OpenCV没有提供查询摄像头的数量及其设备索引的任何方法。

当index的值为0时,表示要打开的是第1个摄像头;对于64位的Windows 10笔记本,当index的值为0时,表示要打开的是笔记本内置摄像头。

当index的值为1时,表示要打开的是第2个摄像头;对于64位的Windows 10笔记本,当index的值为1时,表示要打开的是一个连接笔记本的外置摄像头。

1.1 检查摄像头是否成功打开

为了检验摄像头初始化是否成功,VideoCapture类提供了isOpened()方法。

retval = cv2.VideoCapture.isOpened()

参数说明:
	retval:isOpened()方法的返回值。如果摄像头初始化成功,retval的值为True;否则,retval的值为False。

☀️在VideoCapture()的语法格式基础上,isOpened()方法的语法格式可以简写为:

retval = capture.isOpened()

比如我们可以这样写个判定:

if not cap.isOpened():
    print("无法打开摄像头")
    exit()

1.2 读取视频帧

摄像头初始化后,可以从摄像头中读取帧,为此VideoCapture类提供了read()方法。

retval, image = cv2.VideoCapture.read()   # 可以简写为retval, image = capture.read()

参数说明:
	retval:是否读取到帧。如果读取到帧,retval的值为True;否则,retval的值为False。
	image:读取到的帧。因为帧指的是构成视频的图像,所以可以把“读取到的帧”理解为“读取到的图像”。

我们可以写一个这个:

ret, frame = cap.read()
if not ret:
    print("无法读取视频帧")

⚠️OpenCV官网特别强调,在不需要摄像头时,要关闭摄像头。

为此,VideoCapture类提供了release()方法。

cv2.VideoCapture.release()    # 可以简写为capture.release()

当你使用OpenCV的VideoCapture类来访问摄像头并捕获视频时,你需要在完成视频捕获后,通过调用release()方法来告诉操作系统,你的程序不再需要使用摄像头了。release()方法的作用是释放VideoCapture对象所占用的资源,包括摄像头设备、内存等。这是一个重要的清理步骤,确保系统资源得到合理管理和释放。

1.3 如何使用VideoCapture类

我们已经学会了这些基础的操作了,那么让我们把他们运用到实际中。

首先,编写一个程序,打开笔记本内置摄像头实时读取并显示视频。当按下空格键时,关闭笔记本内置摄像头,销毁显示摄像头视频的窗口。

import cv2

capture = cv2.VideoCapture(0) # 打开笔记本内置摄像头
while (capture.isOpened()): # 笔记本内置摄像头被打开后
    retval, image = capture.read() # 从摄像头中实时读取视频
    cv2.imshow("Video", image) # 在窗口中显示读取到的视频
    key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
    if key == 32: # 如果按下空格键
        break
capture.release() # 关闭笔记本内置摄像头
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口

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

很好,我们现在已经可以使用摄像头获取视频了,那么接下来我们需要对视频进行处理,从头到尾看了我的博客的小伙伴都知道,彩色图像是很难进行处理的,为了能对视频进行更好的处理,我们需要将彩色视频处理为灰度视频。

import cv2

capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 打开笔记本内置摄像头
while (capture.isOpened()): # 笔记本内置摄像头被打开后
    retval, image = capture.read() # 从摄像头中实时读取视频
    # 把彩色视频转换为灰度视频
    image_Gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    if retval == True: # 读取到摄像头视频后
        cv2.imshow("Video", image) # 在窗口中显示彩色视频
        cv2.imshow("Video_Gray", image_Gray) # 在窗口中显示灰度视频
    key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
    if key == 32: # 如果按下空格键
        break
capture.release() # 关闭笔记本内置摄像头
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口

这段代码可以让我们获取灰度视频,这段代码可以让我们同时获得两个窗口,一个彩色视频,一个灰度视频,我觉得这样太繁琐了,我们可以对代码进行修改。

import cv2

# 初始化一个变量来控制显示模式
display_mode = 'color'  # 'color' 或 'gray'

capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)  # 打开笔记本内置摄像头
while (capture.isOpened()):  # 笔记本内置摄像头被打开后
    retval, image = capture.read()  # 从摄像头中实时读取视频
    if retval == True:  # 读取到摄像头视频后
        if display_mode == 'color':
            cv2.imshow("Video", image)  # 在窗口中显示彩色视频
        elif display_mode == 'gray':
            image_Gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            cv2.imshow("Video", image_Gray)  # 在窗口中显示灰度视频

    key = cv2.waitKey(1)  # 窗口的图像刷新时间为1毫秒
    if key == 32:  # 如果按下空格键
        display_mode = 'gray' if display_mode == 'color' else 'color'  # 切换显示模式
    if key == 49:  # 按下数字键1
        break

capture.release()  # 关闭笔记本内置摄像头
cv2.destroyAllWindows()  # 销毁显示摄像头视频的窗口

这样窗口默认为彩色视频,当按下空格后为灰度视频,再次按下又会变成彩色视频,当按下‘1’后退出。

如果想要读取某一时刻的图像呢?我们可以设置程序获取某一刻的图像并将他保存。

import cv2

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 打开笔记本内置摄像头
while (cap.isOpened()): # 笔记本内置摄像头被打开后
    ret, frame = cap.read() # 从摄像头中实时读取视频
    cv2.imshow("Video", frame) # 在窗口中显示视频
    k = cv2.waitKey(1) # 图像的刷新时间为1毫秒
    if k == 32: # 按下空格键
        cap.release() # 关闭笔记本内置摄像头
        cv2.destroyWindow("Video") # 销毁名为Video的窗口
        cv2.imwrite("copy.png", frame) # 保存按下空格键时摄像头视频中的图像
        cv2.imshow('img', frame) # 显示按下空格键时摄像头视频中的图像
        cv2.waitKey() # 刷新图像
        break
cv2.destroyAllWindows() # 销毁显示图像的窗口

❤️因为我没有外置摄像头,这里就不给大家展示了,具体的操作其实就是修改索引。

2. 视频文件的读取与显示

除了捕获摄像头视频,OpenCV也能够读取和显示存储在磁盘上的视频文件。

具体用法如下:

cap = cv2.VideoCapture('video.mp4')

使用VideoCapture类读取视频文件的方法与捕获摄像头视频类似。不同之处在于,视频文件的路径作为参数传递给VideoCapture

这里给一个示例:

import cv2

video = cv2.VideoCapture("测试.mp4") # 打开视频文件
while (video.isOpened()): # 视频文件被打开后
    retval, image = video.read() # 读取视频文件
    # 设置“Video”窗口的宽为420,高为300
    cv2.namedWindow("Video", 0)
    cv2.resizeWindow("Video", 420, 300)
    if retval == True: # 读取到视频文件后
        cv2.imshow("Video", image) # 在窗口中显示读取到的视频文件
    else: # 没有读取到视频文件
        break
    key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒,调整刷新时间可以改变视频速度
    if key == 27: # 如果按下Esc键
        break
video.release() # 关闭视频文件
cv2.destroyAllWindows() # 销毁显示视频文件的窗口

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

至于如何把彩色视频转化为灰度视频,还是和之前提到的一样。

除此之外,我们还可以实现视频的暂停和开始。

import cv2

video = cv2.VideoCapture("test.mp4") # 打开视频文件
while (video.isOpened()): # 视频文件被打开后
    retval, image = video.read() # 读取视频文件
    # 设置“Video”窗口的宽为420,高为300
    cv2.namedWindow("Video", 0)
    cv2.resizeWindow("Video", 420, 300)
    if retval == True: # 读取到视频文件后
        cv2.imshow("Video", image) # 在窗口中显示读取到的视频文件
    else: # 没有读取到视频文件
        break
    key = cv2.waitKey(50) # 窗口的图像刷新时间为50毫秒
    if key == 32: # 如果按下空格键
        cv2.waitKey(0) # 不刷新图像,实现暂停效果
        continue # 再按一次空格键,继续播放
    if key == 27: # 如果按下Esc键
        break
video.release() # 关闭视频文件
cv2.destroyAllWindows() # 销毁显示视频文件的窗口

在实际开发中,我们可能还会需要视频的属性。我们可以使用get()方法。

retval = cv2.VideoCapture.get(propId)

参数说明:
	retval:获取与propId对应的属性值。
	propId:视频文件的属性值。VideoCapture类提供视频文件的属性值及其含义如表所示。
属性值含义
CV2.CAP_PROP_POS_MSEC视频文件播放时的当前位置(单位:ms)
cv2.CAP_PROP_POS_FRAMES帧的索引,从0开始
CV2.CAP_PROP_POS_AVI_RATIO视频文件的相对位置(0表示开始播放,1表示结束播放)
CV2.CAP_PROP_FRAME_WIDTH视频文件的帧宽度
CV2.CAP_PROP_FRAME_HEIGHT视频文件的帧高度
CV2.CAP_PROP_FPS帧速率
CV2.CAP_PROP_FOURCC用4个字符表示的视频编码格式
CV2.CAP_PROP_FRAME_COUNT视频文件的帧数
CV2.CAP_PROP_FORMATretrieve()方法返回的Mat对象的格式
CV2.CAP_PROP_MODE指示当前捕获模式的后端专用的值
CV2.CAP_PROP_CONVERT_RGB指示是否应将图像转换为RGB

例如:

import cv2

video = cv2.VideoCapture("test.mp4") # 打开视频文件
fps = video.get(cv2.CAP_PROP_FPS) # 获取视频文件的帧速率
frame_Count = video.get(cv2.CAP_PROP_FRAME_COUNT) # 获取视频文件的帧数
frame_Width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) # 获取视频文件的帧宽度
frame_Height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)) # 获取视频文件的帧高度
# 输出获取到的属性值
print("帧速率:", fps)
print("帧数:", frame_Count)
print("帧宽度:", frame_Width)
print("帧高度:", frame_Height)

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

获取了属性值,我们在查看视频时可能需要实时查看这些内容,怎么办呢?我们可以添加代码:

import cv2

video = cv2.VideoCapture("test.mp4") # 打开视频文件
fps = video.get(cv2.CAP_PROP_FPS) # 获取视频文件的帧速率
frame_Num = 1 # 用于记录第几幅图像(即第几帧),初始值为1(即第1幅图像)
while (video.isOpened()): # 视频文件被打开后
   retval, frame = video.read() # 读取视频文件
   # 设置“Video”窗口的宽为420,高为300
   cv2.namedWindow("Video", 0)
   cv2.resizeWindow("Video", 420, 300)
   if retval == True: # 读取到视频文件后
      # 当前视频播放到第几帧
      cv2.putText(frame, "frame: " + str(frame_Num), (0, 100),
               cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
      # 该帧对应着视频的第几秒
      cv2.putText(frame, "second: " + str(round(frame_Num / fps, 2)) + "s",
               (0, 200), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
      cv2.imshow("Video", frame) # 在窗口中显示读取到的视频文件
   else: # 没有读取到视频文件
      break
   key = cv2.waitKey(50) # 窗口的图像刷新时间为50毫秒
   frame_Num += 1 #
   if key == 27: # 如果按下Esc键
      break
video.release() # 关闭视频文件
cv2.destroyAllWindows() # 销毁显示视频文件的窗口

3. 视频的保存

在捕获或处理视频数据后,我们可能需要将结果保存到文件中。OpenCV提供了VideoWriter类来实现视频的保存。

<VideoWriter object> = cv2.VideoWriter(filename, fourcc,fps, frameSize)

参数说明:
 VideoWriter object:VideoWriter类对象。
 filename:保存视频时的路径(含有文件名)。
 fourcc:用4个字符表示的视频编码格式。
 fps:帧速率。
 frameSize:每一帧的大小。

在OpenCV中,使用cv2.VideoWriter_fourcc()来确定视频编码格式。表列出了几个常用的视频编码格式。

编码格式fourcc文件扩展名
Motion JPEG"MJPG".avi
MPEG-4 Part 2"XVID""MP4V".avi.mp4
DivX Codec"DIVX".avi
H.264 Codec"X264""H264".mp4
Windows Media Video 9"WMV1""WMV2".wmv
H.265 Codec"X265".mp4
VP8 Codec"VP80".webm
VP9 Codec"VP90".webm

如果想要把视频以某种编码格式保存,可以按照下面方法:

fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))

3.1 写入帧到视频文件

为了保存一段视频,除需要使用VideoWriter类的构造方法外,还需要使用VideoWriter类提供的write()方法。write()方法的作用是在创建好的VideoWriter类对象中写入读取到的帧。

cv2.VideoWriter.write(frame)

🌟使用write()方法时,需要由VideoWriter类对象进行调用。例如,在创建好的VideoWriter类对象output中写入读取到的帧frame,关键代码如下:

output.write(frame)

3.2 释放视频写入资源

当不需要使用VideoWriter类对象时,需要将其释放掉。为此,VideoWriter类提供了release()方法,

output.release()

4. 如何使用VideoWriter类

4.1 保存一段时长为10s的摄像头视频

首先打开笔记本内置摄像头,实时读取并显示视频;然后录制一段时长为10s的摄像头视频;10s后,自动关闭笔记本内置摄像头,同时销毁显示摄像头视频的窗口,并且把这段时长为10s 的 摄 像 头 视 频 保 存 为 PyCharm 当 前 项 目 路 径 下 的ten_Seconds.avi。

import cv2

capture = cv2.VideoCapture(0, cv2.CAP_DSHOW) # 打开笔记本内置摄像头
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D') # 确定视频被保存后的编码格式
fps = 20 # 帧速率
# 创建VideoWriter类对象
output = cv2.VideoWriter("ten_Seconds.avi", fourcc, fps, (640, 480))
frame_Num = 10 * fps # 时长为10秒的摄像头视频含有的帧数
# 笔记本内置摄像头被打开且时长为10秒的摄像头视频含有的帧数大于0
while (capture.isOpened() and frame_Num > 0):
    retval, frame = capture.read() # 从摄像头中实时读取视频
    if retval == True: # 读取到摄像头视频后
        output.write(frame) # 在VideoWriter类对象中写入读取到的帧
        cv2.imshow("frame", frame) # 在窗口中显示摄像头视频
    key = cv2.waitKey(1) # 窗口的图像刷新时间为1毫秒
    frame_Num -= 1 # 时长为10秒的摄像头视频含有的帧数减少一帧
capture.release() # 关闭笔记本内置摄像头
output.release() # 释放VideoWriter类对象
cv2.destroyAllWindows() # 销毁显示摄像头视频的窗口

4.2 保存视频文件

对于存储在磁盘上的视频文件,我们可以读取每一帧,对其进行处理,然后将处理后的帧保存为新的视频文件。

import cv2

video = cv2.VideoCapture("test.avi") # 打开视频文件
fps = video.get(cv2.CAP_PROP_FPS) # 获取视频文件的帧速率
# 获取视频文件的帧大小
size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
        int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D') # 确定视频被保存后的编码格式
output = cv2.VideoWriter("copy.avi", fourcc, fps, size) # 创建VideoWriter类对象
while (video.isOpened()): # 视频文件被打开后
    retval, frame = video.read() # 读取视频文件
    if retval == True: # 读取到视频文件后
        output.write(frame) # 在VideoWriter类对象中写入读取到的帧
    else:
        break
print("test.avi已经保存为PyCharm当前项目路径下的copy.avi。") # 控制台输出提示信息
video.release() # 关闭视频文件
output.release() # 释放VideoWriter类对象
# 注意,这里视频文件不会展示,这是因为我没有imshow()展示视频窗口

如果只想保存视频文件的前十秒的文件呢?该如何操作?我们可以将两个代码融合一下:

import cv2

video = cv2.VideoCapture("test.avi") # 打开视频文件
fps = video.get(cv2.CAP_PROP_FPS) # 获取视频文件的帧速率
# 获取视频文件的帧大小
size = (int(video.get(cv2.CAP_PROP_FRAME_WIDTH)),
        int(video.get(cv2.CAP_PROP_FRAME_HEIGHT)))
fourcc = cv2.VideoWriter_fourcc('X', 'V', 'I', 'D') # 确定视频被保存后的编码格式
output = cv2.VideoWriter("ten_Seconds.avi", fourcc, fps, size) # 创建VideoWriter类对象
frame_Num = 10 * fps # 视频文件的前10秒视频含有的帧数
# 视频文件被打开后且视频文件的前10秒视频含有的帧数大于0
while (video.isOpened() and frame_Num > 0):
    retval, frame = video.read() # 读取视频文件
    if retval == True: # 读取到视频文件后
        output.write(frame) # 在VideoWriter类对象中写入读取到的帧
    frame_Num -= 1 # 视频文件的前10秒视频含有的帧数减少一帧
# 控制台输出提示信息
print("test.avi的前10s视频已经保存为PyCharm当前项目路径下的ten_Seconds.avi。")
video.release() # 关闭视频文件
output.release() # 释放VideoWriter类对象

🌟其实就是添加了frame_Num的变量,设置初始值为总帧数,之后每播放一帧就减少一帧,为零时就结束。

小结

我们学习了如何使用OpenCV进行视频捕获、处理和保存。视频处理是一个充满可能性的领域,无论是实时视频流的处理还是视频文件的后期处理,OpenCV都提供了强大的工具和方法。

希望大家能够通过本篇博客的内容,掌握视频处理的基本技能,并激发出更多的创意和应用。在下一章中,我们将继续学习人脸检测和人脸识别!!!如果你有任何问题或建议,欢迎在评论区讨论。

  • 16
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值