图片合成视频并通过yolov8目标识别
前言
在笔者的第一篇 YOLO 笔记文章中,提到 YOLO 网络相对于二阶段网络的一个显著优势是可以进行实时的目标识别,因此非常适合用于监控等需要对视频进行实时目标识别的场景。在这篇笔记中,笔者将介绍如何将图片合成为视频,以及如何调用 YOLOv8 对视频中的物体进行目标识别的代码。通过这篇文章,读者可以学习到图像处理和目标识别的具体实现方法,并将其应用到实际项目中。
代码
import os
import cv2
def img_video_merge(img_dir, video_path, frame_rate, repeat=5, frame_skip=1):
# 获取所有图像文件,过滤掉非图像文件
file_list = sorted([f for f in os.listdir(img_dir) if f.lower().endswith(('.png', '.jpg', '.jpeg'))])
# 检查目录中是否有图像文件
if not file_list:
print("No image files found in the directory.")
return
# 跳帧处理:每隔frame_skip张图片读取一次
file_list = file_list[::frame_skip]
# 读取第一张图像以获取帧大小
cv_src = cv2.imread(os.path.join(img_dir, file_list[0]))
# 检查图像是否读取成功
if cv_src is None:
print(f"Failed to read the first image: {file_list[0]}")
return
# 创建输出视频的目录
os.makedirs(os.path.dirname(video_path), exist_ok=True)
# 使用H.264编解码器
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
# 获取图像的高度和宽度
height, width, channels = cv_src.shape
# 帧速率和帧大小
frame_size = (width, height)
# 创建VideoWriter对象
out = cv2.VideoWriter(video_path, fourcc, frame_rate, frame_size)
# 检查VideoWriter对象是否打开成功
if not out.isOpened():
print(f"Failed to open VideoWriter with path: {video_path}")
return
for file in file_list:
img_path = os.path.join(img_dir, file)
cv_dst = cv2.imread(img_path)
if cv_dst is None:
print(f"Failed to read image: {file}")
continue
# 将同一帧写入多次以增加显示时间
for _ in range(repeat):
out.write(cv_dst)
# 释放VideoWriter对象
out.release()
print(f"Video saved to {video_path}")
def process_video(video_path, yolov8):
# 打开视频文件,创建视频捕获对象cap。
cap = cv2.VideoCapture(video_path)
# 检查视频文件是否成功打开。
if not cap.isOpened():
print(f"Error: Could not open video {video_path}")
return
# 循环读取视频帧,只要视频文件还未读完并且打开状态良好。
while cap.isOpened():
# 读取下一帧,ret 表示读取成功与否,frame 是读取的帧图像。
ret, frame = cap.read()
# 是否到达视频末尾
if not ret:
break
# 再进行目标识别
yolov8(frame)
# 绘制识别结果
result_frame = yolov8.draw_detections(frame)
# 显示处理后的帧图像。
cv2.imshow('Processed Frame', result_frame)
# 等待 1 毫秒并检查是否有按键按下,如果按下的是 q 键,则跳出循环。
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放视频捕获对象,关闭视频文件。
cap.release()
# 关闭所有 OpenCV 窗口。
cv2.destroyAllWindows()
# 主函数
if __name__ == '__main__':
# 初始化模型
yolov8 = YOLODet('object.onnx', conf_thres=0.3, iou_thres=0.5)
imgs_dir = r'./images'
video_path = r'./video.mp4'
frame_rate = 25 # 设置较高的帧速率,例如25帧每秒
repeat = 5 # 每帧重复写入5次
frame_skip = 5 # 设置跳帧,每隔5帧取一帧
#生成视频
img_video_merge(imgs_dir, video_path, frame_rate, repeat, frame_skip)
# 处理视频
process_video(video_path, yolov8)
解析
这段代码主要分为两个部分:一个是将图像序列合成视频的函数img_video_merge,另一个是处理视频进行目标识别的函数process_video。以下是详细的分析:
1. img_video_merge 函数
功能:将指定目录中的图像文件合成为一个视频文件。
参数:
- img_dir:存放图像的目录路径。
- video_path:输出视频文件的路径。
- frame_rate:视频的帧速率(每秒显示的帧数)。
- repeat:每帧在视频中重复写入的次数,默认值为5。
- frame_skip:每隔frame_skip张图片读取一次,默认值为1。
实现步骤:
- 获取目录中所有图像文件,并过滤掉非图像文件(根据文件扩展名)。
- 检查目录中是否存在图像文件,如果没有,输出提示并返回。
- 跳帧处理,按照指定的frame_skip值进行筛选。
- 读取第一张图像以获取帧的大小(高度和宽度)。
- 创建输出视频的目录(如果不存在)。
- 使用H.264编解码器(mp4v)创建VideoWriter对象。
- 检查VideoWriter对象是否成功打开,如果失败,输出提示并返回。
- 依次读取每张图像,并将其写入视频,每帧重复写入repeat次。 释放VideoWriter对象,保存视频文件并输出提示。
2. process_video 函数
功能:处理视频进行目标识别,并显示处理后的帧。
参数:
- video_path:要处理的视频文件路径。
- yolov8:YOLOv8目标检测模型对象。
实现步骤:
- 打开视频文件,创建视频捕获对象cap。
- 检查视频文件是否成功打开,如果失败,输出提示并返回。
- 循环读取视频帧,直到视频结束或出现错误。
- 读取下一帧,并检查是否到达视频末尾。
- 使用YOLOv8模型进行目标识别,并绘制识别结果。
- 显示处理后的帧图像。 检查是否有按键按下,如果按下的是q键,则跳出循环。
- 释放视频捕获对象,关闭所有OpenCV窗口。
3. 主函数
**功能:**初始化模型并调用图像合成视频和视频处理函数。
步骤:
- 初始化YOLOv8目标检测模型。
- 设置图像目录路径和视频输出路径。
- 设置帧速率、重复次数和跳帧参数。
- 调用img_video_merge函数生成视频。
- 调用process_video函数处理生成的视频。
结语
在本文中,我们详细探讨了如何利用Python和OpenCV将图像序列合成视频,并在视频中进行目标识别。这个过程不仅涉及了图像处理与视频编解码技术,还展示了如何集成YOLOv8目标检测模型来实现实时视频处理。无论是在科研项目中,还是在实际应用中,这种技术都能大大提高我们的工作效率和项目质量。希望本文的内容能够为读者提供有益的参考,帮助大家更好地理解并应用这些技术。
如果您有任何疑问或建议,欢迎在评论区留言。感谢您的阅读与支持!