0.介绍
(1)YOLO是一个开源的目标检测算法,兼顾准确率和运行速度,本笔记主要用YOLO-V3进行图像 or 摄像头视频或者下载视频的目标检测。
(2)检测流程:
- 1)opencv读取视频流或图像;
- 2)创建YOLO-V3网络模型并导入权重文件;
- 3)用模型进行检测并输出检测数值,最后绘制显示在图像上;
(3)YOLO-V3的网络配置文件以及对应的模型权重文件下载:YOLO配置以及权重文件下载链接
注意:FPS表示视频显示帧率,即一秒中图像数量,越大表示视频显示越流畅,下载的模型为YOLOv3-320,下载cfg模型配置文件(加载网络结构)+weights(模型权重文件)两个。
此外由于该模型是在COCO上面下载的,一共有80类,需要导入其类别文件,方面后续绘制出类别名称,类别如下:
1.基础功能实现
(1)用法说明:
1)先加载类别文件,然后构建模型并导入训练好的权重,代码片段如下:
classNames= []
classFile='coco.names'
with open(classFile,'rt') as f:
classNames=f.read().rstrip('\n').split('\n')
modelConfiguration='yolov3.cfg'
modekWeights='yolov3.weights'
net=cv2.dnn.readNetFromDarknet(modelConfiguration,modekWeights)
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)#to use opencv
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)#to use cpu
2)对输入网络的数据进行预处理,比如裁剪到网络支持的尺寸等
#blobFromImage主要是用来对图片进行预处理:分别是影像,缩放系数、输入图片的尺寸,图片整体减去的平均值,crop
blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size, mean, swapRB=True,crop=False,ddepth = CV_32F )
3)将预处理好的数据喂入网络并从网络输出层得到结果,但是由于YOLO-V3是输出有三层,因此如下为得到输出三层的名称,然后提取出对应的结果步骤:
outputNames=[layerNames[i-1] for i in net.getUnconnectedOutLayers()]
outputs=net.forward(outputNames) #三层的输出结果,shape分别是:
outputs[0].shape=(300,85)outputs[1].shape=(1200,85),outputs[2].shape=(4800,85),
其中每一行85个数,前四个数表示x,y,w,h,检测置信度,最后80表示80个类别每个类别的得分,遍历提取即可。
4) 非极大值抑制用于过滤掉同一个物体出现了不同大小的检测框
(2)完整代码:
import cv2
import numpy as np
cap=cv2.VideoCapture('object.mp4')# 可以设置为0,默认打开摄像头
classNames= []
classFile='coco.names'
with open(classFile,'rt') as f:
classNames=f.read().rstrip('\n').split('\n')
modelConfiguration='yolov3.cfg'
modekWeights='yolov3.weights'
net=cv2.dnn.readNetFromDarknet(modelConfiguration,modekWeights)
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)#to use opencv
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)#to use cpu
def findObjects(outputs,img):
hT,wT,cT=img.shape
bbox=[]
classIds=[]
confs=[]
for output in outputs:#3层结果
for det in output:#每层检测结果
scores=det[5:]
classId=np.argmax(scores)
conf=scores[classId]
if conf>0.5:
w,h=int(det[2]*wT),int(det[3]*hT)
x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)#注意减去
bbox.append([x,y,w,h])
classIds.append(classId)
confs.append(float(conf))
indices=cv2.dnn.NMSBoxes(bbox,confs,0.5,0.4)
for i in indices:
# print(i)
box=bbox[i]
x,y,w,h=box
label=classNames[classIds[i]]
confidence=confs[i]
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,255),2)
cv2.putText(img,f'{label} {confidence}',(x,y-10),cv2.FONT_HERSHEY_SIMPLEX,0.5,(255,0,255),2)
while True:
success,img=cap.read()
# blobFromImage主要是用来对图片进行预处理:分别是影像,缩放系数、输入图片的尺寸,图片整体减去的平均值,crop
blob=cv2.dnn.blobFromImage(img,1/255,(320,320),[0,0,0],1,crop=False)
net.setInput(blob)
layerNames=net.getLayerNames()
# print(type(layerNames))
# print(layerNames[0])
# print(type(net.getUnconnectedOutLayers()))#获取输出层的索引
outputNames=[layerNames[i-1] for i in net.getUnconnectedOutLayers()]
# print(outputNames)
outputs=net.forward(outputNames)
# print(outputs[0].shape)#第一个表示检测的盒子数,85表示一堆值,如x,y,w,h,confidence,80表示类别数
# print(outputs[1].shape)
# print(outputs[2].shape)
# print(outputs[0][0])
findObjects(outputs,img)
cv2.imshow('Video',img)
if cv2.waitKey(1) & 0xFF==ord('q'):
break
(3)效果预览:
2.工程应用
2.1 封装类
2.2 只检测指定类别的物体
(1)说明
(2)完整代码
import cv2
import numpy as np
cap=cv2.VideoCapture('object.mp4')# 可以设置为0,默认打开摄像头
classNames= []
classFile='coco.names'
with open(classFile,'rt') as f:
classNames=f.read().rstrip('\n').split('\n')
modelConfiguration='yolov3.cfg'
modekWeights='yolov3.weights'
net=cv2.dnn.readNetFromDarknet(modelConfiguration,modekWeights)
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)#to use opencv
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)#to use cpu
# detectLabels为指定只检测的物体名称列表
def findObjects(outputs,img,detectLabels=classNames):
hT,wT,cT=img.shape
bbox=[]
classIds=[]
confs=[]
for output in outputs:#3层结果
for det in output:#每层检测结果
scores=det[5:]
classId=np.argmax(scores)
conf=scores[classId]
if conf>0.5:
w,h=int(det[2]*wT),int(det[3]*hT)
x,y=int((det[0]*wT)-w/2),int((det[1]*hT)-h/2)#注意减去
bbox.append([x,y,w,h])
classIds.append(classId)
confs.append(float(conf))
indices=cv2.dnn.NMSBoxes(bbox,confs,0.5,0.4)
for i in indices:
# print(i)
box=bbox[i]
x,y,w,h=box
label=classNames[classIds[i]]
confidence=confs[i]
if label in detectLabels:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,255),2)
cv2.putText(img,f'{label} {confidence}',(x,y-10),cv2.FONT_HERSHEY_SIMPLEX,0.5,(255,0,255),2)
while True:
success,img=cap.read()
# blobFromImage主要是用来对图片进行预处理:分别是影像,缩放系数、输入图片的尺寸,图片整体减去的平均值,crop
blob=cv2.dnn.blobFromImage(img,1/255,(320,320),[0,0,0],1,crop=False)
net.setInput(blob)
layerNames=net.getLayerNames()
outputNames=[layerNames[i-1] for i in net.getUnconnectedOutLayers()]
# print(outputNames)
outputs=net.forward(outputNames)
findObjects(outputs,img,['person'])
cv2.imshow('Video',img)
if cv2.waitKey(1) & 0xFF==ord('q'):
break
(3)效果预览(只检测行人)
未完待续!!!
3.参考
(1)B站视频-08-YOLO-V3实时目标检测视频教程
(2)gitee代码仓库
(3)教程源地址cv zone(1)(2)均来自此正式教程。