目录
什么是物体检测?
对象检测如何工作?
什么是 YOLO 对象检测?
YOLO物体检测算法概述
非最大抑制
用 OpenCV 实现 YOLO
使用 YOLO 进行自定义对象检测
什么是物体检测?
对象检测是一种计算机视觉技术,其中软件系统可以从给定的图像或视频中检测、定位和跟踪对象。对象检测的特殊属性是它识别对象的类别(人、桌子、椅子等)及其在给定图像中的位置特定坐标。通过在对象周围绘制一个边界框来指出该位置。边界框可能会或可能不会准确定位对象的位置。在图像内定位对象的能力决定了用于检测的算法的性能。人脸检测是对象检测的示例之一。
这些对象检测算法可能是预先训练的,也可能是从头开始训练的。在大多数用例中,我们使用来自预训练模型的预训练权重,然后根据我们的要求和不同的用例对其进行微调。
对象检测如何工作?
在本节中,我们将简要介绍对象检测任务中采用的不同方法。对象检测有两种方法,它们是:
- 二次检测。
- 单次检测。
让我们首先了解一下两次检测方法。顾名思义,此方法涉及两个阶段。一个是区域提议,然后在第二阶段,对这些区域进行分类并细化位置预测。
Faster-RCNN 变体是二次模型的流行选择。在区域提议阶段,我们使用 ResNet50 等网络作为特征提取器。我们通过删除该网络的最后一层来做到这一点,并仅使用其余层从图像中提取特征。这通常是一种更好的方法,因为网络已经过训练并且可以从图像中提取特征。接下来,一个小的全连接网络在特征层上滑动,以预测与类别无关的框建议,相对于在空间、比例和纵横比上平铺的锚网格。
在第二阶段,这些框提议用于从已经在第一阶段计算的中间特征图中裁剪特征。建议的框被馈送到特征提取器的其余部分,其中预测和回归头被添加到网络顶部。最后,在输出中,我们得到每个提议框的类和特定于类的框细化。
相反,Single-shot 检测跳过了区域提议阶段并立即产生最终的定位和内容预测。YOLO 是这种方法的一个流行示例,我们将在接下来的部分中讨论它的工作原理。
必须注意的是,两次检测模型实现了更好的性能,但单次检测处于性能和速度/资源的最佳位置,这使得它更适合于检测实时提要中的对象或对象跟踪等预测速度较快的任务更为重要。
什么是 YOLO 对象检测?
如前所述,代表“You only look once”的 YOLO 是 Joseph Redmon 在 2016 年 5 月推出的单镜头检测算法。虽然该算法的名称可能听起来很奇怪,但它完美地描述了该算法,因为它在算法的一次运行中预测整个图像的类别和边界框。
与当时的其他单次检测器相比,YOLO 在速度和准确性方面的表现出奇地好。在物体检测方面,它并不是最准确的算法,但可以肯定的是,它以其令人印象深刻的速度弥补了这一点,因此在速度和准确性之间取得了很好的平衡。
YOLO物体检测算法概述
YOLO 网络将输入图像分割成 S×S 单元格的网格。如果地面实况框的中心落入一个单元格,则该单元格负责检测该对象的存在。
每个网格单元预测 B 个边界框及其对象性分数以及它们的类预测,如下所示:
- B 个边界框的坐标 -YOLO 预测每个边界框 (bx,by,bw,bh) 相对于相应网格单元的 4 个坐标。这里 bx, by 是对象中点相对于该网格的 x 和 y 坐标。bh 的值是边界框的高度与相应网格单元格的高度之比,bw 是边界框的宽度与网格单元格的宽度之比。
- Objectness score (P0) – 表示单元格包含对象的概率。客观性分数通过一个 sigmoid 函数被视为一个概率值范围在 0 和 1 之间。
- 类预测——如果边界框包含一个对象,网络预测 K 个类的概率。其中 K 是问题中的类总数。
预测的边界框可能如下所示(置信度得分越高,绘制的框越胖):
最后,边界框的置信度得分和类别预测组合成一个最终得分,告诉我们这个边界框包含特定类型的对象的概率。例如,左边的大胖黄色框很确定它包含对象“狗”:
事实证明,大多数这些框的置信度得分都非常低,因此我们只保留最终得分高于某个阈值的框。此外,非极大值抑制 (NMS) 旨在解决同一图像的多次检测问题。在下一节中,我们将简要介绍一下。那么最终的预测是:
需要注意的是,在 v3 之前,YOLO 使用 softmax 函数来计算类分数。在 v3 中,作者决定改用 sigmoid。原因是 Softmax 假设每个盒子都只有一个类别,而事实并非如此。换句话说,如果一个对象属于一个类,那么就可以保证它不能属于另一个类。虽然这个假设对于某些数据集是正确的,但当我们有像 Women 和 Person 这样的类时它可能不起作用。多标签方法更准确地对数据进行建模。这就是作者避免使用 Softmax 激活的原因。
非最大抑制
Non-maximum Suppression 或 NMS 使用非常重要的功能,称为“Intersection over Union”或 IoU。这是我们计算 IoU 的方法。
两个重叠框的 IoU
我们使用它的两个角(左上角和右下角)定义一个框:(x1,y1,x2,y2)而不是中点和高度/宽度。接下来,我们还需要找到两个框相交的坐标( xi1, yi1, xi2, yi2 ),其中:
xi1 = maximum of the x1 coordinates of the two boxes
yi1 = maximum of the y1 coordinates of the two boxes
xi2 = minimum of the x2 coordinates of the two boxes
yi2 = minimum of the y2 coordinates of the two boxes
请注意,要计算矩形(或盒子)的面积,我们可以将其高度(y2 – y1)乘以宽度(x2 – x1)。
所以要计算IoU,首先通过这个公式计算相交面积
area_intersection =(xi2 - xi1)*(yi2 - yi1)
接下来,计算并集面积
union _area = (area of box 1 + area of box 2) - area_intersection
Therefore IoU=area_intersection/union_area
现在,要实现非最大抑制,步骤是:
- 选择得分最高的框。
- 计算它与所有其他框的重叠,并删除重叠超过某个阈值的框,我们称之为 iou_threshold。
- 回到第1步,迭代直到没有比当前选中的框得分更低的框
这些步骤将删除与所选框有很大重叠的所有框。只剩下最好的盒子。
应用 NMS 前后
用 OpenCV 实现 YOLO
YOLO 算法有多种实现方式,其中最受欢迎的可能是暗网。但是这里我们将使用 OpenCV 来实现 YOLO 算法,因为它非常简单。要开始使用,您需要在您的命令提示符中使用此命令在您的 PC 上安装 OpenCV。
pip install opencv-python
要通过 OpenCV 使用 YOLO,我们需要三个文件,即 -'yoloV3.weights'、'yoloV3.cfg' 和 “coco.names”(包含训练该模型的所有标签名称)。单击它们o 下载文件,然后将其保存在一个文件夹中。现在在此文件夹中打开一个 python 脚本并开始编码:
首先,我们将使用函数“cv2.dnn.ReadNet()”加载模型。该函数将网络加载到内存中,并根据指定的文件名自动检测配置和框架。
import cv2
import numpy as np
# Load Yolo
print("LOADING YOLO")
net = cv2.dnn.readNet("yolov3.weights", "yolov31.cfg")
#save all the names in file o the list classes
classes = []
with open("coco.names", "r") as f:
classes = [line.strip() for line in f.readlines()]
#get layers of the network
layer_names = net.getLayerNames()
#Determine the output layer names from the YOLO model
output_layers = [layer_names[i[0] - 1] for i in net.getUnconnectedOutLayers()]
print("YOLO LOADED")
现在加载模型后,我们可以使用它来检测图像中的对象,或者您甚至可以将其用于需要具有良好处理速度的 PC 的实时对象检测。
这是检测图像中对象的代码
# Capture frame-by-frame
img = cv2.imread("test_img.jpg")
# img = cv2.resize(img, None, fx=0.4, fy=0.4)
height, width, channels = img.shape
# USing blob function of opencv to preprocess image
blob = cv2.dnn.blobFromImage(img, 1 / 255.0, (416, 416),
swapRB=True, crop=False)
#Detecting objects
net.setInput(blob)
outs = net.forward(output_layers)
# Showing informations on the screen
class_ids = []
confidences = []
boxes = []
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
# Object detected
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# Rectangle coordinates
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
#We use NMS function in opencv to perform Non-maximum Suppression
#we give it score threshold and nms threshold as arguments.
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
colors = np.random.uniform(0, 255, size=(len(classes), 3))
for i in range(len(boxes)):
if i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
color = colors[class_ids[i]]
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, label, (x, y -5),cv2.FONT_HERSHEY_SIMPLEX,
1/2, color, 2)
cv2.imshow("Image",img)
cv2.waitKey(0)
输出:
这是使用网络摄像头实时检测对象的代码
video_capture = cv2.VideoCapture(0)
while True:
# Capture frame-by-frame
re,img = video_capture.read()
img = cv2.resize(img, None, fx=0.4, fy=0.4)
height, width, channels = img.shape
# USing blob function of opencv to preprocess image
blob = cv2.dnn.blobFromImage(img, 1 / 255.0, (416, 416),
swapRB=True, crop=False)
#Detecting objects
net.setInput(blob)
outs = net.forward(output_layers)
# Showing informations on the screen
class_ids = []
confidences = []
boxes = []
for out in outs:
for detection in out:
scores = detection[5:]
class_id = np.argmax(scores)
confidence = scores[class_id]
if confidence > 0.5:
# Object detected
center_x = int(detection[0] * width)
center_y = int(detection[1] * height)
w = int(detection[2] * width)
h = int(detection[3] * height)
# Rectangle coordinates
x = int(center_x - w / 2)
y = int(center_y - h / 2)
boxes.append([x, y, w, h])
confidences.append(float(confidence))
class_ids.append(class_id)
#We use NMS function in opencv to perform Non-maximum Suppression
#we give it score threshold and nms threshold as arguments.
indexes = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.4)
font = cv2.FONT_HERSHEY_PLAIN
colors = np.random.uniform(0, 255, size=(len(classes), 3))
for i in range(len(boxes)):
if i in indexes:
x, y, w, h = boxes[i]
label = str(classes[class_ids[i]])
color = colors[class_ids[i]]
cv2.rectangle(img, (x, y), (x + w, y + h), color, 2)
cv2.putText(img, label, (x, y + 30), font, 2, color, 3)
cv2.imshow("Image",cv2.resize(img, (800,600)))
if cv2.waitKey(1) & 0xFF == ord('q'):
break
video_capture.release()
cv2.destroyAllWindows()
使用 TensorFlow 对象检测 API进行实时对象检测
使用 YOLO 进行自定义对象检测
在本节中,我们将了解如何创建自己的自定义 YOLO 对象检测模型,该模型可以根据我们的偏好检测对象。在这里,我将展示如何使用 YOLO 检测一种称为亚历山大鹦鹉的特定鸟类。请注意,此模型只能检测鹦鹉,但我们可以训练它检测多个对象。
我们需要的第一件事是鹦鹉的图像。我们可以从互联网上手动下载它们,但这真的很慢而且很累。或者,您可以使用 GitHub 上免费提供的工具。这是您可以使用的一个,您可以从同一个 GitHub 页面找到使用它的说明。您需要下载至少 300 张图片才能获得不错的结果。
接下来,我们需要用图像中鹦鹉的位置手动标记每张图像。我们可以为此使用工具 labelImg ,它可以使我们的工作变得非常容易,但仍然需要时间,因为我们必须手动执行此操作。请记住更改设置并将其保留给 YOLO,正如我将在下面的视频中指出的那样。在继续之前,请确保您的所有图像都在同一个文件夹中,并且该文件夹仅包含我们想要的图像。
现在压缩包含所有图像的文件夹以及包含对象位置的 .txt 文件,并将它们上传到您的谷歌驱动器。另外,在驱动器中创建一个名为 yolov3 的文件夹,并将 zip 文件放在该文件夹中。
接下来,通过您的帐户打开此Colab Notebook并运行所有单元格。请务必根据您的文件更改所有路径,或者您可以像我一样将数据的 zip 文件夹的名称更改为“徽标”,然后您不需要更改任何内容。
您可能需要大约 5-6 小时才能看到平均损失达到 0.1,然后您可以停止训练但中断单元格。您将在 google 驱动器的 yolov3 文件夹中看到新的权重文件。
现在你需要做的就是修改上面的代码,你就有了你的自定义对象检测器。只需将权重替换为我们在训练后获得的新权重,然后将一项即“Alexandrine parrot”放入类列表中。
输入