根据参考视频里的内容完全可以自己搭建出来,但由于视频是全英文,而且机翻出来的字幕不太准确,所以把步骤和代码注释做成笔记整理了下来,完整工程也附在了文末。
导入的模型库是训练好的,可检测80种物体。
# 初始化模型
net = cv2.dnn.readNet("dnn_model/yolov4-tiny.weights",
"dnn_model/yolov4-tiny.cfg") # 导入模型
model = cv2.dnn_DetectionModel(net)
model.setInputParams(size=(320, 320), scale=1 / 255) # 压缩图片至DNN可处理的尺寸,尺寸越大检测效果越好,但处理速度会变慢
# 物体检测
(class_ids, scores, bboxes) = model.detect(frame)
print("class ids", class_ids) # 分类结果
print("scores", scores) # 准确度
print("bboxes", bboxes) # 识别框的位置信息
# 将识别分类表赋值到classes
classes = []
with open("dnn_model/classes.txt", "r") as file_object: # 只读模式读取文件
for class_name in file_object.readlines(): # 将识别结果赋值到数组
class_name = class_name.strip() # 去掉头尾的空格或换行
classes.append(class_name) # 将class_name加入到classes里
# 在画面上显示识别框和识别结果
for class_id, score, bbox in zip(class_ids, scores, bboxes): # 将多帧数据打包重组成单帧
(x, y, w, h) = bbox # x,y代表识别框左上角位置坐标,w宽度,h高度
class_name = classes[class_id]
# 在画面上画出矩形框框住物体,用文本显示识别结果
cv2.rectangle(frame, (x, y), (x + w, y + h), (128, 42, 42), 3) # 画面,左上角坐标,右下角坐标,RGB颜色,厚度
cv2.putText(frame, class_name, (x, y - 10), cv2.FONT_HERSHEY_PLAIN, 2, (128, 42, 42), 2) # 画面,文本内容,位置,字体,字体大小,RGB颜色,厚度
至此,已经初步完成了物体检测。要想调整处理速度和识别准确度间的关系,可以改变摄像头分辨率或者模型的大小。比如,在初始化摄像头代码中添加一些设置语句。
# 初始化摄像头
cap = cv2.VideoCapture(0)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280)
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
视频里的小哥哥还教了如何增加交互性,最终达到的效果是,通过点击画面上的按钮来控制是否要显示物体检测结果,即是否把物体框出。
可以自己来写代码,或者直接调用人家写好的函数。这里只展示怎么靠自己来设计。
# 定义鼠标响应回调函数
def click_button(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
print(x, y)
# 创建新窗口
cv2.namedWindow("Frame")
cv2.setMouseCallback("Frame", click_button)
这里用 fillPoly 替代 rectangle 可以加快数据处理速度,注意的是使用前要在最前面加一句 import numpy as np
# 在画面上创建按钮
# cv2.rectangle(frame, (20, 20), (210, 70), (0, 0, 200), -1) # 边框厚度为-1表示用颜色填充这个框框
polygon = np.array([[(20, 20), (210, 20), (210, 70), (20, 70)]]) # 通过绘制多边形来创建按钮
cv2.fillPoly(frame, polygon, (0, 0, 200))
cv2.putText(frame, "Person", (30,60), cv2.FONT_HERSHEY_PLAIN, 3, (255, 255, 255), 3)
button_person = False # 用以标志按钮状态
# 定义鼠标响应回调函数
def click_button(event, x, y, flags, params):
global button_person
if event == cv2.EVENT_LBUTTONDOWN:
print(x, y)
polygon = np.array([[(20, 20), (210, 20), (210, 70), (20, 70)]]) # 通过绘制多边形来创建按钮
is_inside = cv2.pointPolygonTest(polygon, (x, y), False)
if is_inside > 0:
print("按钮被点击")
# 改变按钮状态标志位
if button_person:
button_person = False
else:
button_person = True
print("按钮状态为", button_person)
添加条件判断语句,根据按钮的状态标志位决定是否显示识别框和结果
if class_name == "person" and button_person is True:
# 在画面上画出矩形框框住物体,用文本显示识别结果
cv2.rectangle(frame, (x, y), (x + w, y + h), (128, 42, 42), 3) # 画面,左上角坐标,右下角坐标,RGB颜色,厚度
cv2.putText(frame, class_name, (x, y - 10), cv2.FONT_HERSHEY_PLAIN, 2, (128, 42, 42), 2) # 画面,文本内容,位置,字体,字体大小,RGB颜色,厚度
完整工程的链接在这里 link. (没有设置积分要求哦)