【OpenCV】视频录制

news/2024/12/13 23:20:10/

介绍

在 OpenCV 中,视频录制涉及到读取摄像头或视频文件的帧,并将这些帧保存到新的视频文件中。为了实现这个过程,你需要创建一个 VideoCapture 对象来获取视频帧,以及一个 VideoWriter 对象来保存视频帧。以下是使用 OpenCV 进行视频录制的基本步骤和相关函数介绍:

1. 创建 VideoCapture 对象

首先,需要创建一个 cv2.VideoCapture() 对象来捕获视频。你可以指定一个设备索引(通常是整数0表示默认摄像头)或者一个视频文件路径作为参数。

2. 设置 VideoCapture 属性

你可以设置一些属性,比如分辨率、帧率等,以确保录制视频的质量符合要求。可以使用 cap.set() 方法来设置这些属性。

3. 创建 VideoWriter 对象

接下来,创建一个 cv2.VideoWriter() 对象来写入视频。你需要提供输出文件名、编码器(四字符代码)、帧率以及帧大小

4. 录制视频

在一个循环中逐帧读取视频并将其写入到 VideoWriter 对象中。通常会检查是否成功读取了帧,然后进行必要的处理(如显示),最后写入帧到输出文件中。

5. 释放资源

完成录制后,记得释放 VideoCaptureVideoWriter 对象,并关闭所有窗口。

初始化一个视频写入对象,目的是将图像帧序列保存为视频文件。使用了OpenCV库中的cv2.VideoWriter类来创建这个对象,并且设置了视频的编码格式、帧率以及分辨率。

导入库

import cv2
import datetime
  • cv2 是 OpenCV 库的 Python 接口,提供了大量的图像处理和计算机视觉功能。
  • datetime 库用于处理日期和时间。

设置视频参数

fourcc = cv2.VideoWriter_fourcc(*'mp4v')
fps = 30.0
frame_width, frame_height = 640, 480
  • fourcc: 定义了视频编解码器(Four Character Code)。这里使用的是 *'mp4v',表示使用 MPEG-4 编码。VideoWriter_fourcc 函数接受四个字符作为参数,所以用 * 来解包字符串 'mp4v'
  • fps: 每秒帧数(Frames Per Second),决定了视频播放的速度。这里的值是 30.0,意味着每秒钟有 30 帧图像。
  • frame_widthframe_height: 视频帧的宽度和高度,以像素为单位。这里设定的是 640x480 分辨率。

创建输出文件名

output_file = 'video/' + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '.mp4'
  • 使用 datetime.datetime.now() 获取当前的时间。
  • strftime("%Y%m%d%H%M%S") 格式化时间为年月日小时分钟秒的形式,确保每个输出文件都有唯一的文件名,避免覆盖旧文件。
  • 文件路径为 'video/' 目录下,带有时间戳的 .mp4 文件。

初始化 VideoWriter 对象

self.out_record = cv2.VideoWriter(output_file, fourcc, fps, (frame_width, frame_height))
  • self.out_record: 这是一个 VideoWriter 类的对象,用来写入视频帧到文件中。如果这段代码位于类的方法内部,那么 self 表示当前实例。
  • 参数:
    • output_file: 输出视频文件的路径和名称。
    • fourcc: 视频编码器。
    • fps: 视频帧率。
    • (frame_width, frame_height): 每个视频帧的尺寸。

准备好了一个可以开始录制视频的环境,接下来可以通过调用 self.out_record.write(frame) 方法向视频文件中添加帧,其中 frame 是一帧图像数据。当不再需要录制时,应该调用 self.out_record.release() 来关闭视频写入对象并完成文件写入。

完整代码:

import cv2
import datetimefourcc = cv2.VideoWriter_fourcc(*'mp4v')
fps = 30.0
frame_width, frame_height = 640, 480
output_file = 'video/' + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + '.mp4'
self.out_record = cv2.VideoWriter(output_file, fourcc, fps, (frame_width, frame_height))

定义一个名为 updateFrames 的方法。此方法用于持续更新视频帧,并处理视频录制以及将视频帧显示在图形用户界面(GUI)中。

方法 updateFrames

循环结构

while not self.appExit:
  • 通过一个无限循环来不断检查是否应该退出应用程序 (appExit)。如果 appExit 变量为真,则停止循环。

控制帧速率

time.sleep(1 / 30)
  • 使用 time.sleep 函数来控制每秒读取和处理的帧数为大约 30 帧(FPS)。这有助于保持视频播放的平滑性。

视频捕获与处理

if self.cap is not None and self.cap.isOpened():_, frame = self.cap.read()if not _:self.cap = None
  • 检查视频捕获对象 self.cap 是否有效并且打开。
  • 尝试读取一帧图像。如果读取失败(即返回的第一个值 _ 为 False),则将 self.cap 设置为 None,表示没有有效的视频源。

调整帧大小

frame = cv2.resize(frame, video_size)
self.frame = frame.copy()
  • 使用 OpenCV 的 resize 函数调整帧的尺寸到预设的 video_size
  • 创建当前帧的一个副本并保存到 self.frame 中。

录制视频

if self.startRecordFlag:self.out_record.write(frame)cv2.putText(frame, MesConst.VIDEO_RECORDING, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 2)
  • 如果 startRecordFlag 标志为真,则将当前帧写入到 self.out_record 对象中进行录制。
  • 同时,在帧上添加文本以表明正在录制,使用 cv2.putText 函数绘制绿色文字 "VIDEO_RECORDING" 在帧的左上角。

处理无视频输入的情况

else:frame = np.zeros((video_size[1], video_size[0], 3), np.uint8)self.startRecordFlag = False
  • 如果没有有效的视频输入,创建一个全黑的图像作为帧。
  • 确保录制标志 startRecordFlag 为假,防止尝试录制无效帧。

图像转换与显示

h, w, ch = frame.shape
bytesPerLine = ch * w
convertToQtFormat = QImage(frame.data, w, h, bytesPerLine, QImage.Format_RGB888).rgbSwapped()
pixmap = QPixmap.fromImage(convertToQtFormat)
self.lblVideo.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio))
  • 获取帧的高度、宽度和通道数。
  • 计算每一行的字节数 bytesPerLine
  • 将 OpenCV 的 BGR 格式的图像数据转换为 Qt 的 QImage 格式,并交换红色和蓝色通道以适应 RGB 显示。
  • 创建一个 QPixmap 对象,然后将其设置为 GUI 中的 lblVideo 标签的图标,同时保持宽高比缩放。

异常处理

except:pass
  • 使用一个空的 except 子句来捕获所有异常,但不做任何处理。这种做法通常不推荐,因为它会掩盖潜在的问题。更好的做法是指定具体的异常类型或至少记录异常信息以便调试。

完整代码:

    def updateFrames(self):while not self.appExit:time.sleep(1 / 30)try:if self.cap is not None and self.cap.isOpened():_, frame = self.cap.read()if not _:self.cap = Noneframe = cv2.resize(frame, video_size)self.frame = frame.copy()if self.startRecordFlag:self.out_record.write(frame)cv2.putText(frame, MesConst.VIDEO_RECORDING, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.2,(0, 255, 0), 2)else:frame = np.zeros((video_size[1], video_size[0], 3), np.uint8)self.startRecordFlag = Falseh, w, ch = frame.shapebytesPerLine = ch * wconvertToQtFormat = QImage(frame.data, w, h, bytesPerLine, QImage.Format_RGB888).rgbSwapped()pixmap = QPixmap.fromImage(convertToQtFormat)self.lblVideo.setPixmap(pixmap.scaled(w, h, Qt.KeepAspectRatio))except:pass


http://www.ppmy.cn/news/1554875.html

相关文章

四、vue多事件处理器

<template> <view> <!-- 这两个 one() 和 two() 将执行按钮点击事件 --> <button click"one($event); two($event)"> Submit </button> </view> </t…

经纬度解析到省市区【开源】

现在业务中有需要解析经纬度到省市区。 按理说可以直接使用高德&#xff0c;百度之类的。 但是老板太抠。于是去找开源项目。找了一圈&#xff0c;数据都太老了&#xff0c;而且有时候编码还不匹配。 所以诞生了这个项目&#xff0c;提供完整的一套省市区编码和定位反解析。…

软考中级-软件设计师通过心路经验分享

执念&#xff0c;第四次终于通过了 没买书&#xff0c;下班后每天2小时&#xff0c;四个2个月终于过了 学习经验&#xff1a; 1.下班后学习真的靠毅力&#xff0c;和上学的时候考证不是一个状态&#xff0c;大家要及时调整&#xff0c;否则过程很痛苦 2.失败三次的经验&#xf…

自定义生成小游戏提现截图工具的设计与实现

摘要 在游戏开发和测试过程中&#xff0c;开发者经常需要生成游戏截图以展示游戏界面或用于测试。本文将介绍一个自定义生成小游戏截图的工具&#xff0c;该工具可以帮助开发者快速生成游戏界面截图&#xff0c;以满足不同场景下的需求。 视频演示 引言 随着移动游戏市场的迅…

iview date-picker options只可选当前日期之前的

iview date-picker options只可选当前日期之前的 如果日期对象date的时间戳大于当前时间的时间戳&#xff0c;则该日期在当前日期之后&#xff0c;会被禁用。 <template><Row><Col span"12"><DatePickertype"datetime":options&qu…

如何使用 NuGet 程序包管理器

快速入门&#xff1a;在 Visual Studio 中安装和使用 NuGet 包&#xff08;仅适用于 Windows&#xff09; NuGet 包 包含其他开发人员已提供的在项目中使用的可重用代码。 可以使用 NuGet 包管理器、包管理器控制台或 .NET CLI 在 Microsoft Visual Studio 项目中安装 NuGet 包…

前端视角下的Go语法学习:创建 Go 项目

今日话题 使用 GoLand 创建 Go 项目 作者&#xff1a; 时间&#xff1a;2024年6月20日 17时16分14秒 主线任务 一、GoLand 创建项目 1、点击 “new Project” 按钮 2、已经有下载过两个 Golang SDK 版本&#xff0c;选择版本创建即可~ 3、如果没有下载过Golang SDK&#…

asp.net老项目运维,出现的问题6之数据库

数据库会有很多张表&#xff0c;表内一般会有自增列&#xff0c;如果想统一管理这个自增数值&#xff0c;可以使用如下方法&#xff0c;放在一个存储过程中&#xff0c;想用的时候调用存储过程即可生成数据库层面的全局唯一值&#xff1a; create procedure [dbo].[P_getSeqID…