前言
一直都对opencv很感兴趣,觉得它的能力真的很强大。而且yolo更是如雷贯耳早就想想学习一下了,刚好今天好了一个这类的视频,就顺便学习一下。
参考:
python与C++
枫333
一、前期准备
下载yolov3相关文件:下载链接
olov3.weights 文件包含了预训练的网络权重;
olov3.weights下载
yolov3.cfg 文件包含 了网络配置;
yolov3.cfg下载
coco.names 文件包含了 COCO 数据集中的 80 个不同类别名.
coco.names下载
注意:要把这三个文件放在程序文件相同目录下,不然需要改动这三个文件的导入地址。
二、使用步骤
1.引入库
import cv2
import numpy as np
安装cv库:
pip install opencv-python -i https://pypi.tuna.tsinghua.edu.cn/simple
2.初始化配置
coco.names 包含了模型训练时的物体类别名. 首先读取该文件.
网络包含两部分:
yolov3.weights - 预训练的模型权重
yolov3.cfg - 网络配置文件
设置 DNN 后端为 OpenCV ,目标设置为 CPU. 也可以设置为 cv.dnn.DNN_TARGET_OPENCL 以在 GPU 上运行.注意当前 OpenCV 版本只支持 Intel 的 GPUs 测试。
# 获取摄像头或视频地址
cap = cv2.VideoCapture(r"./data/test.mp4")
# coco.names文件存储着80种已经训练好的识别类型名称,并且这些类别名称正好与yolo所训练的80种类别一一对应
classesFile = r"coco.names"
# 存储类型名称列表
classNames = []
with open(classesFile, "rt") as f:
# 依照行读取数据
classNames = f.read().splitlines()
# 显示所有类型名称
print(classNames)
# 配置yolov3
modelConfiguration = "yolov3.cfg" # 配置文件
modelWeights = "yolov3.weights" # 配置权重文件
net = cv2.dnn.readNetFromDarknet(modelConfiguration, modelWeights) # 将配置文件加入到dnn网络中
net.setPreferableBackend(cv2.dnn.DNN_BACKEND_OPENCV) # 将DNN后端设置成opencv
net.setPreferableTarget(cv2.dnn.DNN_TARGET_CPU) # 将DNN前端设置成cpu驱动
3.设置网络
神经网络的输入图片需要以 blob 的特定格式组织.
当读取了一帧图片后,其需要经过 blobFromImage 函数的处理,以转换为网络的 input blob. 在该处理过程中,图片像素值被采用 1/255 的因子缩放到 [0, 1] 范围;且在不裁剪的情况下,将图片尺寸调整为 (416, 416).
注:并未进行任何减均值操作,因此,函数的均值参数采用的是 [0, 0, 0]。设置网络的输入图片的默认尺寸 :inpWidth 和 inpHeight. 这里均设置为 416,也可以设置为 320 以得到更快的速度,设置为 608 以得到更好的精度.
输入图处理后输出的 blob,被作为网络输入,进行前向计算,以得到输出的预测边界框列表. 网络输出的预测框再进行后处理,以过滤低置信度的边界框.
OpenCV 的 Net 类的 forward 函数需要知道网络的最终输出层.
由于要对整个网络进行运行,因此,需要确认网络的最后一层.采用 getUnconnectedOutLayers() 函数来获取无连接的输出层的名字,这些层一般都是网络的输出层.
while True:
# 读取数据
success, frame = cap.read()
# DNN网络的输入图像需要采用称为 blob 的特定格式
blob = cv2.dnn.blobFromImage(frame, 1 / 255, (inpWidth, inpHeight), [0, 0, 0], True, False)
# 将输出的blob作为传入网络的输入
net.setInput(blob)
# 获取输入层的名称
layerNames = net.getLayerNames()
# 获得输入层的最后一层,以此遍历整个网络
outputNames = [layerNames[i - 1] for i in net<