YOLOv3算法,由Joseph Redmon、Santosh Divvala、Ross Girshick和Ali Farhadi提出,是一种用于实时目标检测的高效卷积神经网络(CNN)。与传统的目标检测方法不同,YOLOv3算法只需对输入图像进行一次前向传播即可完成预测,因此得名“You Only Look Once”。这种算法因其高准确率和实时性而广受欢迎,适用于需要快速响应的场景。
在以往的目标检测系统中,通常会使用定位器或分类器来执行检测过程,然后将模型应用于图像的不同尺度和位置。而YOLO算法则采用全新的方法,它将整个图像作为一个整体输入到单一的神经网络中,然后该网络将图像划分为多个区域,并为每个区域生成边界框以及预测概率。这些生成的边界框会根据预测概率进行加权。
YOLOv3的架构包含24个卷积层和2个全连接层。前20个卷积层后接平均池化层和全连接层,这部分是在使用ImageNet数据集上进行预训练的,ImageNet是一个包含1000类分类的数据集。预训练时使用的图像分辨率为224x224x3。这些层包括3x3的卷积层和1x1的降维层。对于目标检测,最后添加了4个卷积层和2个全连接层来训练网络。由于目标检测需要更精确的细节,因此数据集的分辨率增加到448x448。最终层预测类别概率和边界框。除了最终层使用线性激活函数外,所有其他卷积层都使用leaky ReLU激活函数。输入图像的尺寸为448x448,输出为检测到的对象的类别预测,包含在边界框内。
要实现YOLOv3,首先需要下载预训练的权重和配置文件。可以从以下链接下载YOLOv3-320和YOLOv3-tiny的权重和配置文件:
https://pjreddie.com/darknet/yolo/
接下来,安装OpenCV版本3.4.2.16:
pip install opencv-python==3.4.2.16
下载coco.names文件,并将其放置在项目目录中。
以下是使用预训练权重实现YOLOv3的步骤。首先定义输入,这里使用摄像头实时输入。设置检测置信度阈值和非最大抑制阈值:
import cv2
import numpy as np
cap = cv2.VideoCapture(0)
whT = 320
confThreshold = 0.5
nmsThreshold = 0.3
然后读取coco.names文件中的类别:
classesFile = 'coco.names'
classNames = []
with open(classesFile,'rt') as f:
classNames = f.read().rstrip('n').split('n')
初始化权重和配置文件,这里选择了yolov3-tiny,也可以选择yolov3-320。使用OpenCV的darknet模块读取模型配置文件和模型权重文件:
modelConfiguration = 'yolov3.cfg'
modelWeights = 'yolov3.weights'
net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights)
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_DEFAULT)
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU)
def findObjects(outputs,img):
hT, wT, cT = img.shape
bbox = []
classIds = []
confs = []
for output in outputs:
for det in output:
scores = det[5:]
classId = np.argmax(scores)
confidence = scores[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))
indices = cv2.dnn.NMSBoxes(bbox, confs,confThreshold,nmsThreshold)
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,0,255),2)
cv2.putText(img,f'{classNames[classIds[i]].upper()} {int(confs[i]*100)}%',(x,y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.6,(255,0,255),2)
while True:
success, img = cap.read()
blob = cv2.dnn.blobFromImage(img, 1/255,(whT,whT),[0,0,0],crop=False)
net.setInput(blob)
layerNames = net.getLayerNames()
outputNames = [layerNames[i[0]-1] for i in net.getUnconnectedOutLayers()]
outputs = net.forward(outputNames)
findObjects(outputs,img)
cv2.imshow('Image', img)
cv2.waitKey(1)