基本步骤
- 文件路径和基本参数设置
文件:类别名文件(如data_coco.names),配置文件(如cfg_yolov3.cfg)和权重文件(如yolov3.weights)
基本参数设置:非极大抑制阈值,图片高宽
读入模型:readNetFrom… - 套路
(1)blob=cv2.dnn.blobFromImage
(2)net.setInput(blob)
(3)outInfo =net.getUnconnectedOutLayersNames()
获取网络输出层信息(所有输出层的名字)
Net类中的forward函数需要一个结束层,它应该在网络中运行到该层。因此我们通过getUnconnectedOutLayersNames来识别网络的最后一层从而运行整个网络
(4)layerOutputs =net.forward
(outInfo)设定并前向传播 - 对图像框进行处理
遍历 - 后处理
通过cv.dnn.NMSBoxes获得检测框的索引
很好的【参考文档】:基于opencv的yolo物体检测
part1. api
OpenCV4.0 DNN(二) ——Net篇
1)blobFromImage
blobFromImage主要是用来对图片进行预处理。包含两个主要过程:
- 整体像素值减去平均值(mean)
- 通过缩放系数(scalefactor)对图片像素值进行缩放
blobFromImage(InputArray image,
double scalefactor=1.0,
const Size& size = Size(),
const Scalar& mean = Scalar(),
bool swapRB = false,
bool crop = false,
int ddepth = CV_32F)
image
:这个就是我们将要输入神经网络进行处理或者分类的图片。
mean
:需要将图片整体减去的平均值,如果我们需要对RGB图片的三个通道分别减去不同的值,那么可以使用3组平均值,如果只使用一组,那么就默认对三个通道减去一样的值。减去平均值(mean):为了消除同一场景下不同光照的图片,对我们最终的分类或者神经网络的影响,我们常常对图片的R、G、B通道的像素求一个平均值,然后将每个像素值减去我们的平均值,这样就可以得到像素之间的相对值,就可以排除光照的影响。
scalefactor
:当我们将图片减去平均值之后,还可以对剩下的像素值进行一定的尺度缩放,它的默认值是1,如果希望减去平均像素之后的值,全部缩小一半,那么可以将scalefactor设为1/2。
size
:这个参数是我们神经网络在训练的时候要求输入的图片尺寸。
swapRB
:OpenCV中认为我们的图片通道顺序是BGR,但是我平均值假设的顺序是RGB,所以如果需要交换R和G,那么就要使swapRB=true
2)setInput
void cv::dnn::Net::setInput (
InputArray blob,
const String & name = "",
double scalefactor = 1.0,
const Scalar & mean = Scalar() )
3)getUnconnectedOutLayersNames
outInfo = net.getUnconnectedOutLayersNames()
print(outInfo)
输出结果是:
('yolo_82', 'yolo_94', 'yolo_106')
4)forward
layerOutputs = net.forward(outInfo)
print(layerOutputs)
输出结果是
结果上是4+1+80
4:前四个维度分别是xywh
1:然后是一个维度的置信度
80:每一个类别的概率
part2. 例子
# import the necessary packages
import numpy as np
import argparse
import time
import cv2
import os
#检测图片路径
image_path='D:\computervision\deep_learning_model\yolov5-6.2\data\images/bus.jpg'
#文件存储路径
yolo='D:/computervision/deep_learning_model/model/rm/yolo/yolo-coco'
confidence_t=0.5
threshold=0.3
# 加载训练 YOLO 模型的 COCO 类标签
#labelsPath = os.path.sep.join([yolo, "coco.names"])
labelsPath ="D:\computervision\deep_learning_model\model/rm\yolo\yolo-coco\data_coco.names"
LABELS = open(labelsPath).read().strip().split("\n")
# 初始化一个颜色列表来表示每个类标签
np.random.seed(42)
COLORS = np.random.randint(0, 255, size=(len(LABELS), 3),
dtype="uint8")
# YOLO 对象检测
print("[INFO] loading YOLO from disk...")
config_path = 'D:\computervision\deep_learning_model\model/rm\yolo\yolo-coco\cfg_yolov3.cfg'
weights_path = 'D:\computervision\deep_learning_model\model/rm\yolo\yolo-coco\yolov3.weights'
net = cv2.dnn.readNetFromDarknet(config_path, weights_path)
# 加载我们的输入图像并获取其空间维度
image = cv2.imread(image_path)
(H, W) = image.shape[:2]
# 从输入图像构建一个blob,然后执行一个前向传播
# 通过 YOLO 对象检测器,输出边界框和相关概率
blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416),
swapRB=True, crop=False)
net.setInput(blob)
start = time.time()
# 获取网络输出层信息(所有输出层的名字),设定并前向传播
outInfo = net.getUnconnectedOutLayersNames()
# 得到各个输出层的、各个检测框等信息,是二维结构。
layerOutputs = net.forward(outInfo)
# 分别初始化检测到的边界框、置信度和类 ID 的列表
boxes = []
confidences = []
classIDs = []
# 循环输出
for output in layerOutputs:
# 遍历每个检测结果
for detection in output:
# 提取物体检测的类ID和置信度(即概率)
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
# 过滤精度低的结果
if confidence > confidence_t:
# 延展边界框坐标,计算 YOLO 边界框的中心 (x, y) 坐标,然后是框的宽度和高度
box = detection[0:4] * np.array([W, H, W, H])
(centerX, centerY, width, height) = box.astype("int")
# 使用中心 (x, y) 坐标导出边界框的上角和左角
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
# 更新边界框坐标、置信度和类 ID 列表
boxes.append([x, y, int(width), int(height)])
confidences.append(float(confidence))
classIDs.append(classID)
# 使用非极大值抑制来抑制弱的、重叠的边界框
idxs = cv2.dnn.NMSBoxes(boxes, confidences, confidence_t,
threshold)
# 确保至少存在一个检测
if len(idxs) > 0:
# 遍历我们保存的索引
for i in idxs.flatten():
# 提取边界框坐标
(x, y) = (boxes[i][0], boxes[i][1])
(w, h) = (boxes[i][2], boxes[i][3])
# 在图像上绘制一个边界框矩形和标签
color = [int(c) for c in COLORS[classIDs[i]]]
cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)
text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])
cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX,
0.5, color, 2)
# show the output image
cv2.imshow("Image", image)
cv2.waitKey(0)