初始化一个视频写入对象,目的是将图像帧序列保存为视频文件。使用了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_width
,frame_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()
来关闭视频写入对象并完成文件写入。
完整代码:
python
import cv2
import datetime
fourcc = 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
子句来捕获所有异常,但不做任何处理。这种做法通常不推荐,因为它会掩盖潜在的问题。更好的做法是指定具体的异常类型或至少记录异常信息以便调试。
完整代码:
python
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 = None
frame = 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 = False
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))
except:
pass