基本步骤

  1. 文件路径和基本参数设置
    文件:类别名文件(如data_coco.names),配置文件(如cfg_yolov3.cfg)和权重文件(如yolov3.weights)
    基本参数设置:非极大抑制阈值,图片高宽
    读入模型:readNetFrom…
  2. 套路
    (1)blob=cv2.dnn.blobFromImage (2)net.setInput(blob) (3)outInfo = net.getUnconnectedOutLayersNames()获取网络输出层信息(所有输出层的名字)
    Net类中的forward函数需要一个结束层,它应该在网络中运行到该层。因此我们通过getUnconnectedOutLayersNames来识别网络的最后一层从而运行整个网络
    (4)layerOutputs = net.forward(outInfo)设定并前向传播
  3. 对图像框进行处理
    遍历
  4. 后处理
    通过cv.dnn.NMSBoxes获得检测框的索引

很好的【参考文档】:基于opencv的yolo物体检测

part1. api

OpenCV4.0 DNN(二) ——Net篇

1)blobFromImage

blobFromImage主要是用来对图片进行预处理。包含两个主要过程:

  1. 整体像素值减去平均值(mean)
  2. 通过缩放系数(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)

输出结果是

python 调用yolo模型 python yolov3_python


结果上是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)