在处理后的视频文件中进行对象检测是一项常见的任务。本文将介绍如何使用TensorFlow和MobileNet模型来实现这一功能。将从读取视频文件开始,然后展示如何过滤检测结果,以便只显示人。
为了进行对象检测,首先创建了一个名为VideoReader
的类(参见video_reader.py
在Part_05
文件夹中)。这个类内部使用了OpenCV的VideoCapture
。与之前从相机读取帧的情况类似,主要区别在于需要将文件路径传递给VideoCapture
的初始化器:
def __init__(self, file_path):
try:
self.video_capture = opencv.VideoCapture(file_path)
except Exception as e:
print(e)
然后,通过调用VideoCapture
类实例的read
方法来读取文件中的连续帧:
def read_next_frame(self):
(capture_status, frame) = self.video_capture.read()
if capture_status:
return frame
else:
return None
要使用VideoReader
类,首先调用初始化器以提供输入视频文件,然后根据需要多次调用read_next_frame
方法来读取帧。当方法到达文件末尾时,它将返回None
。
为了检测人,使用了之前创建的模块,包括Inference
和ImageHelper
类。将在main.py
中引用它们。这些模块的源代码包含在Part_03
文件夹中,并在之前的文章中进行了解释。
为了引用这些模块,在main.py
文件中添加了以下语句,假设主脚本是从Part_05
文件夹执行的:
import sys
sys.path.insert(1, '../Part_03/')
from inference import Inference as model
from image_helper import ImageHelper as imgHelper
因此,可以轻松地访问视频文件帧上的对象检测:
model_file_path = '../Models/01_model.tflite'
labels_file_path = '../Models/02_labels.txt'
ai_model = model(model_file_path, labels_file_path)
video_file_path = '../Videos/01.mp4'
video_reader = videoReader(video_file_path)
frame = video_reader.read_next_frame()
score_threshold = 0.5
results = ai_model.detect_objects(frame, score_threshold)
然而,问题在于检测了模型训练的所有对象。为了只检测人,需要过滤detect_objects
方法返回的结果。为此,使用检测对象的标签。过滤方法可以如下实现:
def detect_people(self, image, threshold):
all_objects = self.detect_objects(image, threshold)
people = filter(lambda r: r['label'] == 'person', all_objects)
return list(people)
将上述方法detect_people
添加到了Inference
类中(参见inference.py
在Part_03
文件夹中)。detect_people
函数内部调用detect_objects
,然后使用内置的Python函数filter
来过滤结果。第一个参数是过滤方法。在这里,使用了一个匿名lambda函数,它返回一个布尔值。当当前检测结果的标签是"person"时为True
,否则为False
。
为了显示检测到的人,使用了image_helper
模块中的静态display_image_with_detected_objects
方法。然而,display_image_with_detected_objects
方法原本是为了在用户按下键之前显示图像。如果将其用于视频序列,用户将需要为每一帧按下键。为了适应视频,通过添加另一个参数delay
来修改该方法。将这个参数的值传递给OpenCV的waitKey
方法,以设置等待超时:
@staticmethod
def display_image_with_detected_objects(image, inference_results, delay=0):
opencv.namedWindow(common.WINDOW_NAME, opencv.WINDOW_GUI_NORMAL)
for i in range(len(inference_results)):
current_result = inference_results[i]
ImageHelper.draw_rectangle_and_label(image, current_result['rectangle'], current_result['label'])
opencv.imshow(common.WINDOW_NAME, image)
opencv.waitKey(delay)
默认情况下,延迟为0,因此该方法仍将适用于期望它等待按键的调用。
所有组件都准备好后,可以将它们整合在一起:
import sys
sys.path.insert(1, '../Part_03/')
from inference import Inference as model
from image_helper import ImageHelper as imgHelper
from video_reader import VideoReader as videoReader
if __name__ == "__main__":
model_file_path = '../Models/01_model.tflite'
labels_file_path = '../Models/02_labels.txt'
ai_model = model(model_file_path, labels_file_path)
video_file_path = '../Videos/01.mp4'
video_reader = videoReader(video_file_path)
score_threshold = 0.4
detect_only_people = False
delay_between_frames = 5
while True:
frame = video_reader.read_next_frame()
if frame is None:
break
if detect_only_people:
results = ai_model.detect_people(frame, score_threshold)
else:
results = ai_model.detect_objects(frame, score_threshold)
imgHelper.display_image_with_detected_objects(frame, results, delay_between_frames)