YOLO的Python实现以及 OpenCV - 教程
YOLO的Python实现以及OpenCV
Darknet实现YOLO
从头开始开发YOLO模型不容易,故而大家要使用预训练模型在项目里进行目标检测。你可能在https://pjreddie.com里到所有可用的预训练模型。这是Joseph C. Redmon的主页,他是Darknet的维护者。
注意Darknet是C和CUDA开发的开源神经网络框架,它很快,很容易安装,支持CpU 和GpU计算。
在子页 (https://pjreddie.com/darknet/yolo/), 你可以找到 YOLO算法的所有信息。你可以从这个网页下载多个预训练模型的权重。对于每一个模型,你需要二个记录:
- 一个.cfg文件,它包含网络结构.
- 一个.weights文件,它涵盖训练后的权重
为了给你这些材料的内容,.cfg文件包含利用的层的信息等,示例如:
[convolutional]batch_normalize=1filters=64
size=3
stride=1pad=1
activation=leaky
这告诉你有特殊的卷积层。最关键的信息是:
- Network architecture
- Anchor boxes
- Number of classes
- Learning rate and other parameters used
- Batch size
其它文件(.weights)具备预训练权重以进行推断。注意它们不能保存为Keras兼容的格式(如.h5文件),所以它们不能加载到Keras模型,除非你先转换。
有一些非标准的工具可以转换这些文档,因为格式不是固定的( YOLOv2和YOLOv3有些不同)。假如你感兴趣以YOLO v2,你可以使用YAD2K 库(另一个是Darknet 2 Keras),可以在https://github.com/allanzelener/YAD2K里找到。
注意这不能处理YOLOv3 .cfg材料。相信我,我试过。但是如果你满意YOLOv2,你可以用这个目录的代码转换.weight文件到Keras友好的格式。有个目录实现了YOLOv3 的转换,在https://github.com/qqwweee/keras-yolo3。它有些局限,只是它是转换的很好的起点。应用就是但是有便好的办法,使用预训练模型,那就OpenCV,后面我们会看到。
用Darknet检测对象
假如你只是想对图像进行分类,最容易的办法是按darknet网站的指示。大家看一下如何做。如果你应用Linux或MacOS X系统,这些指令有用。在Windows里,你要安装gcc和别的工具。如网站所述,安装只需要几行代码:
git clone https://github.com/pjreddie/darknetcd darknet
make
wget https://pjreddie.com/media/files/yolov3.weights
这里你就可以进行目标检测了:
./darknet detect cfg/yolov3.cfg yolov3.weights table.jpg
注意,权重文件很大,下载时要注意这一点,使用CPU这很慢,MacBook Pro 2018需要18秒来下载。见图7-2。
图7-2. YOLOv3使用darknet进行图像检测
黙认使用0.25通过的阈值。不过你能够运用不同的参数。你必须改变XYZ到你想要的值。
黙认使用0.25的阈值。但是你可能使用不同的参数。你必须改变XYZ到你想要的值。.
这个方法于于目标检测很好,但是很难在python项目里使用。要这样做,你需要在你的代码里使用预训练的模型。有几个方法,最容易的是运用opencv通过库。如果你处理图像,你很可能已经使用过这个库。要是你没有听说过,建议你试一下,因为它是处理图像很有名的库。你能够看官网https://opencv.org.
你可以在网上下载本章的完整代码,然而我们只简单的讨论重要的部分。
你需要安装最新的opencv库。用下面的代码检测版本:
import cv2
print (cv2. version )
我们需要从https://pjreddie.com下载三个记录:
- coco.names
- yolov3.cfg
- yolov3.weights
coco.names包含了预训练模型能分类的标签。yolov3.cfg和yolov3.weights是模型配置参数(前面已讨论过)且我们必须采用权重。为了你方便,yolov3.weights大约240MB容量,你可以下载ZIP 文件自http://toe.lt/r。在代码里我们需要指明文件在哪里。例如,你使用下面的代码:
weightsPath = "yolo-coco/yolov3.weights"configPath = "yolo-coco/yolov3.cfg"
你要改变文件的位置。OpenCV供应了函数来加载权重而不需要转换它们:
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
这很舒服,由于你不应该分析和写加载函数。它返回模型对象供你后面推断。如果你记得本章开始的讨论,你要得到输出层来得到所有需要的信息,像边框和预测分类。我们用下面的代码很容易做到:
ln = net.getLayerNames()
ln = [ln[i[0] - 1] fori in net.getUnconnectedOutLayers()]
getUnconnectedOutLayers()函数返回带用unconnected输出的层, 正是我们想要的。ln这量含有下面的层:
['yolo_82', 'yolo_94', 'yolo_106']
然后我们要改变图像大小到416x416并归一化它:
blob = cv2.dnn.blobFromImage(image, 1/ 255.0, (416, 416),swapRB=True, crop=False)
然后用它作为模型的输入:
net.setInput(blob)
然后我们用forward()函数向前传递给训练模型:
layerOutputs = net.forward(ln)
预测分类就是我们还没有结束,不要休息。我们要提取边框,我们保存在列表里,然后是置信,继而.
我们初始化列表:
boxes = []confidences= []classIDs= []
for output in layerOutputs:for detection in output:
现在分数保存在第5个检测变量的元素里,我们提取分类用np.argmax(scores):
scores = detection[5:]classID = np.argmax(scores)
置信度是预测分类的分值:
confidence = scores[classID]
我们想要预测置信度大于0的。大家选择限度为0.15。预测边框包含于检测变量的前4个里:
box = detection[0:4] * np.array([W, H, W, H])(centerX, centerY, width, height) = box.astype("int")
要是你记得,YOLO预测边框的中心点,所在我们要的提取左上角位置:
x = int(centerX - (width/ 2))y = int(centerY - (height/ 2))
然后我们将发现的值添加到列表
boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID)
然后我们应用non-maxima抑制(上一节讨论过)。OpenCV也提供了函数:
idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.6,0.2)
函数需要下面的参数:
- 边框集合(保存于boxes变量)
- 置信度集合(保存于confidences变量)
- 按分值过滤边框的阈值(前面代码是0.6)
- non-maximum抑制的阈值(前面的代码是0.2)
然我们得到准确的位置:
for i in idxs.flatten():
# extract the bounding box coordinates(x, y)= (boxes[i][0], boxes[i][1])
(w, h) = (boxes[i][2], boxes[i][3])
你可以在图7-3看到结果。
图7-3. YOLOv3用OpenCV获得的结果
这正是它应有的—与图7-2通过一样的结果。另外,大家有预测边框的概率。你能够看到这是多么的容易。你只需要添加几行代码到你的工程。
这正是它应有的—与图7-2通过一样的结果。另外,我们有预测边框的概率。你能够看到这是多么的容易。你只得添加几行代码到你的任务。
记住大家使用预训练模型只能检测数据集里的对象。假如你要用不同的对象,你要微调模型,或重新训练模型。从头训练模型超出了本书的范围。可是下一节我会给你一些提示。