YOLOV3目标检测
YOLO3借鉴了残差网络结构,形成更深的网络层次,以及多尺度检测,提升了mAP及小物体检测效果。如果采用COCO mAP50做评估指标(不是太介意预测框的准确性的话),YOLO3的表现相当惊人,如下图所示,在精确度相当的情况下,YOLOv3的速度是其它模型的3、4倍。
效果
部分代码示例
import numpy as np
import cv2
import time
#(1)加载预训练的COCO数据集
classesFile = 'coco.names' # 指定coco数据集分类名所在路径
classNames = [] # 创建列表,存放coco数据集的分类名称
# 打开数据集名称的文件
with open(classesFile, 'rt') as f: #读取文本文件
classNames = f.read().rstrip('\n').split('\n') # 通过换行符来拆分,再读入
# 加载yolov3结构cfg文件
modelConfiguration = 'yolov3.cfg'
# 加载yolov3网络权重
modelWeights = 'yolov3.weights'
# 确定输入图像的宽和高
wInput, hInput = 320, 320
# 自定义目标检测的最小置信度
confThreshold = 0.5
# 自定义非极大值抑制的参数
nms_threshold = 0.3
#(2)构建网络结构
# 导入darknet53网络,传入cfg文件和网络权重
net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
# 申明使用opencv作为后端
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV)
# 申明使用CPU计算
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
#(3)获取摄像头
videoFile = '行人1.mp4'
cap = cv2.VideoCapture(videoFile) # 0代表电脑自带的摄像头,代表外接摄像头
#(4)定义函数用于检测目标,获取检测框信息,以及分类类别
def findObjects(outputs, img):
# 图像的高度、宽度、通道数
hT, wT, cT = img.shape # 先保存高度,再保存宽度
# 定义一个列表存放检测框的中心点坐标和宽高
bbox = []
# 定义列表存放分类的名称的索引
classIds = []
# 定义列表存放置信度
confs = [] # 如果找到目标了,就将检测框的信息存放起来
# 遍历三个输出层
for output in outputs:
# 遍历输出层的85项信息
for det in output: # det是数组类型
# 在80个分类中找到哪个分类的值是最高的
score = det[5:] # 忽略检测框的x,y,w,h,c
# 找到分类值最大对应的索引号
classId = np.argmax(score)
# 找到分类概率最大值的索引对应的值
confidence = score[classId]
# 如果检测置信度大于规定的阈值,表明检测到了物体
if confidence > confThreshold:
# 记录检测框的宽和高,这里的宽高是归一化之后的比例宽度和高度
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(confidence))
#(5)消除重叠的矩形框,非极大值抑制
indices = cv2.dnn.NMSBoxes(bbox, confs, confThreshold, nms_threshold) # 返回检测框的索引
# 遍历索引绘制矩形框
for i in indices:
# i = i[0]
# 在所有包含目标的矩形框中找到最符合的矩形框
box = bbox[i]
# 提取矩形框的信息
x, y, w, h = box[0], box[1], box[2], box[3]
# 绘制矩形框
cv2.rectangle(img, (x,y), (x+w,y+h), (255,255,0), 2)
# 显示文本
cv2.putText(img, f'{classNames[classIds[i]]}',
(x,y+h+18), cv2.FONT_HERSHEY_COMPLEX, 0.8, (0,255,0), 2)
cv2.putText(img, f'{int(confs[i]*100)}%',
(x,y-8), cv2.FONT_HERSHEY_COMPLEX, 0.8, (0,0,255), 2)
#(5)处理帧图像
while True:
# 接收图片是否导入成功、帧图像
success, img = cap.read()
# 改变图像大小
img = cv2.resize(img, (1280,720))
# 视频较短,循环播放
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
# 如果当前帧==总帧数,那就重置当前帧为0
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
# 释放视频资源
cap.release()
cv2.destroyAllWindows()