一、概述
本文是使用pycharm,利用opencv的dnn模块实现yolov3的目标检测。本人是初学者,为了记录自己的学习过程和对该项目理解更加深刻才写的,可能有许多不足的地方,欢迎各位大佬批评指正,如果本文章有侵权,请联系我。
二、yolov3模型简单介绍
yolov3是由大佬JosephRedmon和AliFarhadi发明提出来的,它包含了FPN、anchor锚框和darknet-53等优秀的算法。其他具体网络结构与原理本文不赘述,如果想要了解该网络的具体原理可以参考yolov3的论文。地址:https://arxiv.org/pdf/1804.02767
三、准备工作
首先需要到yolo的官网下载weight和cfg。
官网地址为:https://pjreddie.com/darknet/yolo/#google_vignette
然后需要下载coco.names数据集
地址:分享文件:coco.names
链接:https://pan.xunlei.com/s/VO4rrAnkPngJkALRsafKzULeA1#
提取码:brn8
coco所对应标签有
person
bicycle
car
motorbike
aeroplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
sofa
pottedplant
bed
diningtable
toilet
tvmonitor
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush
四、代码以及效果图
前面的准备好了,开始上代码了
"""
author: XiaoShu
date: 2024-08-22
"""
import cv2
import numpy as np
import time
# video = '1.mp4'
# cap = cv2.VideoCapture(video) # 视频识别
cap = cv2.VideoCapture(0) # 调用本地摄像头进行识别
classPath = 'coco.names'
classNames = []
confThreshold = 0.5
nmsThreshold = 0.3
ctime = 0
ftime = 0
with open(classPath, 'rt') as f:
classNames = f.read().rstrip('\n').split('\n')
modelConfiguration = 'yolov3.cfg'
modelWeights = 'yolov3.weights'
# 创建自己的网络,加载DNN模型
net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights) # 读取模型配置和权重模型
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) # 声明opencv是作为后端
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA) # 声明使用cpu
def findObjects(outputs, img):
hT, wT, cT = img.shape # 把图片的高、宽、通道分别赋值到hT, wT, cT
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:
box = bbox[i]
x, y, w, h = box[0], box[1], box[2], box[3]
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
cv2.putText(img, f'{classNames[classIds[i]]} {int(confs[i] * 100)}%',
(x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 0, 255), 2)
# 调用电脑摄像头进行识别或者视频识别, 空格退出
while True:
res, img = cap.read()
"""函数说明:blob = cv2.dnn.blobFromImage(image, scalefactor=1.0, size, mean, swapRB=True,crop=False,ddepth = CV_32F )
输入:
image:需要进行处理的图像。
scalefactor:执行完减均值后,需要缩放图像,默认是1。
size:输出图像的空间尺寸,如size=(200,300)表示高h=300,宽w=200。
mean:要减去的均值,可以是R,G,B均值三元组,或者是一个值,每个通道都减这值。如果执行减均值,通道顺序是R、G、B。 如果,输入图像通道顺序是B、G、R,那么请确保swapRB = True,交换通道。
swapRB:OpenCV认为图像通道顺序是B、G、R,而减均值时顺序是R、G、B,为了解决这个矛盾,设置swapRB=True即可。
crop:图像裁剪,默认为False.当值为True时,先按比例缩放,然后从中心裁剪成size尺寸。
ddepth:输出blob的深度,可选CV_32F or CV_8U。
返回值:
返回一个4通道的blob(blob可以简单理解为一个N维的数组,用于神经网络的输入。
"""
blob = cv2.dnn.blobFromImage(img, 1 / 255, (320, 320), [0, 0, 0], 1, crop=False)
# blob = cv2.dnn.blobFromImage(img, 1 / 255, (320, 320), [0, 0, 0], 1, crop=True)
net.setInput(blob) # blob作为图片输入
layersNames = net.getLayerNames() # 获取网络所有图层的名称
out_layer_names = []
for i in net.getUnconnectedOutLayers():
out_layer_names.append(layersNames[i - 1])
outputs = net.forward(out_layer_names) # 向前预测
findObjects(outputs, img)
ctime = time.time()
fps = 1 / (ctime - ftime)
ftime = ctime
cv2.putText(img, f"FPS:{int(fps)}", (30, 50), cv2.FONT_HERSHEY_DUPLEX, 1, (255, 0, 0), 2)
cv2.imshow('img', img)
if cv2.waitKey(1) == ord(' '):
break
cap.release()
cv2.destroyAllWindows()
# # 图片识别, 空格退出
# img1 = cv2.imread('1.jfif')
# blob = cv2.dnn.blobFromImage(img1, 1 / 255, (320, 320), [0, 0, 0], 1, crop=True)
# net.setInput(blob) # blob作为图片输入
# layersNames = net.getLayerNames() # 获取网络所有图层的名称
# out_layer_names = []
# for i in net.getUnconnectedOutLayers():
# out_layer_names.append(layersNames[i - 1])
# outputs = net.forward(out_layer_names) # 向前预测
# findObjects(outputs, img1)
# cv2.imshow('img', img1)
# if cv2.waitKey(0) == ord(' '):
# exit()
# cv2.destroyAllWindows()
图片检测
视频检测
调用本地摄像头进行识别