使用Pytorch进行Faster R-CNN目标检测

 

在这篇文章中,我们将通过使用pytorch进行faster R-CNN目标检测。我们将学习目标检测从R-CNN到 fast R-CNN到 faster R-CNN的演变过程。

1、图像分类VS目标检测

图像分类用于将类标签分配给输入图像。例如,给定猫的输入图像,图像分类算法的输出是标签“猫”。 在目标检测中,我们不仅对输入图像中的对象感兴趣,而且对它们的位置也感兴趣。 下图说明了图像分类和目标检测的区别。

1.1.图像分类与目标检测:使用哪一个?

通常,图像分类用于处理只包含一个对象的图像。可能有多个类(例如。猫、狗等),但是通常,图像中只有一个类的实例。 在输入图像中有多个对象的大多数应用程序中,我们需要找到对象的位置,然后对它们进行分类。在这种情况下,我们使用目标检测算法。 目标检测比图像分类在速度上慢数百倍,因此,在应用中,如果对象在图像中的位置并不重要,那我们最好还是使用图像分类。

2.目标检测

我们可以把目标检测分成两步

1、查找包含对象的包围框,使每个包围框只有一个对象。

2、对每个包围框中的图像进行分类,并为其确定一个标签。

在接下来的几节中,我们将介绍faster R-CNN目标检测是如何一步步发展出来的。

2.1滑动窗口法

大多数经典的用于目标检测的计算机视觉技术,如HAAR(哈尔)级联和HOG(方向梯度统计直方图)+SVM,都使用滑动窗口方法来检测目标。 在这种方法中,滑动窗口在图像上移动,滑动窗口中的所有像素都被裁剪出来并发送到图像分类器。 如果图像分类器识别到已知对象,则存储边界框和类标签。否则,窗口继续滑动并将被评估。 滑动窗口方法非常浪费计算资源,因为为了检测输入图像中的对象,需要在图像中的每个像素上评估不同尺度和纵横比的滑动窗口。 因此,只有当我们检测具有固定纵横比的单个对象类时,才使用滑动窗口。例如,OpenCV中基于HOG + SVM或HAAR的人脸检测器使用滑动窗口方法。在人脸检测器中,复杂性是可控的,因为只有方形包围框在不同的尺度上被检测。

2.2.R-CNN目标检测器

基于卷积神经网络(CNN)的图像分类器在2012年赢得ImageNet大规模视觉识别挑战(ILSVRC)后变得流行起来。 由于每个目标检测器的核心都有一个图像分类器,基于CNN的目标检测器的发明变得不可避免。

有两个问题需要解决

1、与传统的HOG + SVM或HAAR级联等技术相比,基于CNN的图像分类器非常耗费计算资源。

2、计算机视觉社区越来越雄心勃勃。人们想要建立一个多类目标检测器,除了不同的尺度外,还可以处理不同的纵横比。

因此,基于滑动窗口的目标检测方法被淘汰了。它太费资源了。

研究人员开始研究一种新的思路,即训练一种机器学习模型,该模型可以提出包含对象的包围框的位置。这些包围框被称为区域提案或目标提案。

区域提案仅仅是一个列表,元素是包含对象的包围框,而这些包围框包含对象的概率也不是太高,只是具有一定概率。它不知道也不在乎边界框中包含了哪种对象。

区域提案算法在不同的位置、尺度和纵横比上输出包含几百个包围框的列表。这些包围框中的大多数不包含任何对象。 为什么区域提案仍然有用? 在区域提案算法提出的几百个边界框中使用图像分类器,比在滑动窗口方法提出的几十万个甚至数百万个边界框中使用图像分类器要高效的多。 使用区域提案的第一种方法之一是RossGirschick等人,称为R-CNN(具有CNN特征的区域的简称)。

他们使用一种名为选择搜索的算法来检测出2000个区域提案,并在这些2000个包围框上运行了一个基于CNN + SVM的图像分类器。 当时R-CNN的准确性是最先进的,但速度仍然很慢(GPU上的每张图像18-20秒)

 2.3 fast R-CNN目标探测器

在R-CNN中,每个边界框由图像分类器独立分类,有2000个区域提案,图像分类器计算了每个区域提案的特征图。这个过程很耗时。 在Ross Girshick的后续工作中,他提出了一种称为快速R-CNN的方法,它显著地加快了目标检测的速度。 其想法是为整个图像计算一个单一的特征图,而不是为2000个区域提案计算2000个特征图。对于每个区域提案,感兴趣区域(ROI)池化层从特征图中提取固定长度的特征向量。然后,每个特征向量被用于两个目的

1、将区域分类为其中一个类(例如。狗,猫,背景)。

2、使用边界框回归器提高原始边界框的精度。

2.4 faster R-CNN目标检测器

在 fast R-CNN中,即使对2000个区域提案进行分类的计算是共享的,但生成区域提案的算法部分与执行图像分类的部分不共享任何计算。 在被称为FasterR-CNN的后续工作中,主要的见解是这两个部分-计算区域提案和图像分类-可以使用相同的特征图,从而分担计算负荷。 利用卷积神经网络生成图像特征图,同时用于训练区域提案网络和图像分类器。由于这种共享计算,对象检测的速度有了显著的提高。

3.用PyTorch进行目标检测 [代码部分]

在本节中,我们将学习如何使用Pytorch中的 faster R-CNN目标检测器。我们将使用torchvision中的预训练模型。在PyTorch的所有预先训练的模型都可以在torchvision.models中找到。

3.1.输入和输出

我们将使用预训练模型faster R-CNN ResNet-50,该模型期望输入图像张量的形式[n,c,h,w],要求最小尺寸为800px。

n是图像的数目

c为通道数,对于RGB图像是3

h是图像的高度

w是图像的宽度

模型返回结果

所有预测的包围框组成的二维列表,维度为(N,4),其中N是由模型预测图像中的包围框个数,包围框的形状为[x0,y0,x1,y1],也就是包围框的左上角座标和右下角座标

所有预测类的标签。

每个预测标签的置信度。

3.2.预训模式

下载预训练模型,Resnet50 Faster R-CNN,带有训练好的权重参数。

from PIL import Image
import matplotlib.pyplot as plt
import torch
import torchvision.transforms as T
import torchvision
import torch
import numpy as np
import cv2

# get the pretrained model from torchvision.models
# Note: pretrained=True will get the pretrained weights for the model.
# model.eval() to use the model for inference
model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
model.eval()

定义Pytorch官方文档给出的类名称

COCO_INSTANCE_CATEGORY_NAMES = [
    '__background__', 'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus',
    'train', 'truck', 'boat', 'traffic light', 'fire hydrant', 'N/A', 'stop sign',
    'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow',
    'elephant', 'bear', 'zebra', 'giraffe', 'N/A', 'backpack', 'umbrella', 'N/A', 'N/A',
    'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard', 'sports ball',
    'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket',
    'bottle', 'N/A', 'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl',
    'banana', 'apple', 'sandwich', 'orange', 'broccoli', 'carrot', 'hot dog', 'pizza',
    'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'N/A', 'dining table',
    'N/A', 'N/A', 'toilet', 'N/A', 'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone',
    'microwave', 'oven', 'toaster', 'sink', 'refrigerator', 'N/A', 'book',
    'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush'
]

 我们可以在列表中看到一些N/A,因为在后面的论文中删除了一些类。我们将按照PyTorch给出的列表进行操作。

3.3.模型预测

让我们定义一个函数来获得图像路径,并通过模型得到图像的预测。

def get_prediction(img_path, threshold):
  img = Image.open(img_path) # Load the image
  transform = T.Compose([T.ToTensor()]) # Defing PyTorch Transform
  img = transform(img) # Apply the transform to the image
  pred = model([img]) # Pass the image to the model
  print('pred')
  print(pred)
  pred_class = [COCO_INSTANCE_CATEGORY_NAMES[i] for i in list(pred[0]['labels'].numpy())] # Get the Prediction Score
  print("original pred_class")
  print(pred_class)
  pred_boxes = [[(i[0], i[1]), (i[2], i[3])] for i in list(pred[0]['boxes'].detach().numpy())] # Bounding boxes
  print("original pred_boxes")
  print(pred_boxes)
  pred_score = list(pred[0]['scores'].detach().numpy())
  print("orignal score")
  print(pred_score)
  pred_t = [pred_score.index(x) for x in pred_score if x > threshold][-1] # Get list of index with score greater than threshold.
  pred_boxes = pred_boxes[:pred_t+1]
  pred_class = pred_class[:pred_t+1]
  print(pred_t)
  print(pred_boxes)
  print(pred_class)
  return pred_boxes, pred_class

从图像路径中获取图像

使用PyTorch变换将图像转换为图像张量

通过在模型传递图像以得到预测结果

得到类、包围框座标,但只选择预测分数>阈值的结果。

函数处理过程中的阶段结果都被打印出来用于分析实验结果

 3.4.目标检测流程 

接下来,我们将定义一个函数来获取图像路径并获得输出图像。

def object_detection_api(img_path, threshold=0.5, rect_th=3, text_size=3, text_th=3):
 
  boxes, pred_cls = get_prediction(img_path, threshold) # Get predictions
  img = cv2.imread(img_path) # Read image with cv2
  img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # Convert to RGB
  for i in range(len(boxes)):
    cv2.rectangle(img, boxes[i][0], boxes[i][1],color=(0, 255, 0), thickness=rect_th) # Draw Rectangle with the coordinates
    cv2.putText(img,pred_cls[i], boxes[i][0],  cv2.FONT_HERSHEY_SIMPLEX, text_size, (0,255,0),thickness=text_th) # Write the prediction class
  plt.figure(figsize=(20,30)) # display the output image
  plt.imshow(img)
  plt.xticks([])
  plt.yticks([])
  plt.show()

用get_prediction函数进行预测

对于每个预测, 使用opencv 绘制包围框并添加标签文本

最终图像显示

3.5.推理

现在,让我们使用以上代码来检测一些图像中的目标。预训练模型在CPU中需要大约8秒的推理,在NVIDIA GTX1080 Ti GPU中需要0.15秒。本例中使用cpu进行推理。

示例1:

在当前目录下载图片:

wget https://www.wsha.org/wp-content/uploads/banner-diverse-group-of-people-2.jpg -O people.jpg

运行python代码:

object_detection_api('./people.jpg', threshold=0.8)

最终图片:

处理过程的打印信息如下,可见,模型输出为一个字典,共包含3个元素,分别是boxes,labels和scores。而且已经按照scores的得分进行排序。所以阈值的选择变的很关键,阈值过高会遗漏目标,过低则会增加误报。

pred
[{'boxes': tensor([[0.0000e+00, 3.1965e+02, 4.4152e+02, 1.3233e+03],
        [7.6530e+02, 3.5194e+02, 1.1937e+03, 1.3123e+03],
        [1.1569e+03, 3.9462e+02, 1.5692e+03, 1.3222e+03],
        [1.5193e+03, 4.2957e+02, 1.9924e+03, 1.3306e+03],
        [3.6411e+02, 3.8761e+02, 7.7179e+02, 1.3062e+03],
        [6.1343e+02, 2.6801e+02, 9.1222e+02, 1.2417e+03],
        [1.4390e+03, 3.3610e+02, 1.6700e+03, 7.9422e+02],
        [1.7240e+03, 2.8933e+02, 1.9978e+03, 8.8992e+02],
        [1.1548e+03, 1.8348e+02, 1.4562e+03, 7.0534e+02],
        [1.6003e+03, 1.9746e+02, 1.7637e+03, 6.3541e+02],
        [8.8223e+02, 1.9024e+02, 1.2439e+03, 7.4672e+02],
        [5.4620e+02, 2.4167e+02, 7.1724e+02, 5.4152e+02],
        [2.3673e+02, 1.0112e+02, 4.8953e+02, 6.6732e+02],
        [8.3154e+02, 2.0397e+02, 1.1441e+03, 6.0038e+02],
        [2.1523e+02, 1.5433e+02, 4.8707e+02, 1.1148e+03],
        [1.1424e+03, 1.9198e+02, 1.5366e+03, 9.7392e+02],
        [0.0000e+00, 6.2382e+02, 1.6149e+02, 1.2446e+03],
        [1.5768e+03, 2.0830e+02, 1.8524e+03, 7.4405e+02],
        [2.5804e+02, 3.3354e+02, 6.2200e+02, 1.3077e+03],
        [8.9626e+02, 3.5898e+02, 1.3640e+03, 1.3158e+03],
        [1.0498e+03, 1.0657e+03, 1.0759e+03, 1.1004e+03],
        [5.3046e+00, 4.1446e+02, 2.1460e+02, 1.3151e+03],
        [1.5564e+03, 2.1095e+02, 1.9997e+03, 9.6501e+02],
        [4.5241e+01, 9.1016e+02, 1.5961e+02, 1.0559e+03],
        [1.4584e+03, 3.3478e+02, 1.7331e+03, 1.2968e+03],
        [1.8249e+03, 2.9717e+02, 2.0000e+03, 1.2894e+03],
        [1.0173e+03, 2.9484e+02, 1.2510e+03, 7.7417e+02],
        [1.7593e+02, 5.9531e+02, 3.9948e+02, 9.5223e+02],
        [9.5730e+02, 1.7660e+02, 1.6549e+03, 7.6932e+02],
        [8.1830e+00, 1.1709e+03, 1.5495e+02, 1.3270e+03],
        [1.4883e+03, 2.6912e+02, 1.7646e+03, 7.7534e+02],
        [5.5098e+01, 9.1188e+02, 8.6513e+01, 9.8316e+02],
        [3.7265e+02, 7.5000e+02, 4.7406e+02, 1.3200e+03],
        [0.0000e+00, 5.6960e+02, 1.6152e+02, 8.6986e+02],
        [1.0386e+03, 1.0430e+03, 1.0768e+03, 1.0974e+03],
        [1.2317e+03, 3.0593e+02, 1.6184e+03, 8.5238e+02],
        [3.6448e-01, 8.9336e+02, 8.7396e+01, 9.7809e+02],
        [1.1957e+00, 7.1775e+02, 1.5803e+02, 1.1761e+03],
        [6.7784e+01, 1.7359e+02, 4.4879e+02, 7.4864e+02]],
       grad_fn=<StackBackward>), 'labels': tensor([ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1, 31,  1,
         1,  1, 85,  1,  1,  3,  1,  1,  1, 32,  1,  1,  1, 14,  1, 31, 85,  1,
         3, 28,  1]), 'scores': tensor([0.9986, 0.9983, 0.9982, 0.9971, 0.9964, 0.9874, 0.9854, 0.9853, 0.9773,
        0.9734, 0.9606, 0.8864, 0.8327, 0.7735, 0.3906, 0.3572, 0.3154, 0.2906,
        0.2022, 0.1946, 0.1904, 0.1621, 0.1552, 0.1310, 0.1213, 0.1161, 0.1100,
        0.1049, 0.0986, 0.0899, 0.0815, 0.0799, 0.0691, 0.0663, 0.0660, 0.0652,
        0.0590, 0.0584, 0.0550], grad_fn=<IndexBackward>)}]
original pred_class
['person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'handbag', 'person', 'person', 'person', 'clock', 'person', 'person', 'car', 'person', 'person', 'person', 'tie', 'person', 'person', 'person', 'parking meter', 'person', 'handbag', 'clock', 'person', 'car', 'umbrella', 'person']
original pred_boxes
[[(0.0, 319.6455), (441.5155, 1323.2559)], [(765.3034, 351.93936), (1193.7164, 1312.2843)], [(1156.9446, 394.623), (1569.2057, 1322.1747)], [(1519.3403, 429.56564), (1992.429, 1330.6052)], [(364.10757, 387.61426), (771.79016, 1306.173)], [(613.42804, 268.0113), (912.2196, 1241.745)], [(1439.0381, 336.10446), (1669.9921, 794.2212)], [(1723.9878, 289.32892), (1997.8444, 889.91785)], [(1154.8141, 183.47633), (1456.161, 705.3361)], [(1600.269, 197.45708), (1763.7482, 635.4068)], [(882.2303, 190.24492), (1243.9407, 746.71704)], [(546.1972, 241.6657), (717.2413, 541.52277)], [(236.73463, 101.11602), (489.53278, 667.32404)], [(831.5391, 203.96678), (1144.0723, 600.3847)], [(215.23401, 154.3328), (487.06903, 1114.8004)], [(1142.3718, 191.98454), (1536.619, 973.9194)], [(0.0, 623.81696), (161.48994, 1244.6355)], [(1576.7936, 208.30457), (1852.4454, 744.0468)], [(258.0397, 333.54254), (622.0048, 1307.7097)], [(896.257, 358.9788), (1364.0449, 1315.7703)], [(1049.787, 1065.661), (1075.9006, 1100.3923)], [(5.3046417, 414.46304), (214.60019, 1315.0636)], [(1556.4305, 210.94743), (1999.7416, 965.0133)], [(45.241035, 910.1611), (159.61392, 1055.8945)], [(1458.4309, 334.77945), (1733.1425, 1296.8483)], [(1824.8823, 297.17184), (2000.0, 1289.3732)], [(1017.25616, 294.84235), (1251.0472, 774.17303)], [(175.93126, 595.3143), (399.48138, 952.2279)], [(957.2965, 176.59543), (1654.9402, 769.3168)], [(8.183002, 1170.8748), (154.95354, 1327.0237)], [(1488.3322, 269.119), (1764.643, 775.338)], [(55.097706, 911.8797), (86.512726, 983.1622)], [(372.65338, 750.0016), (474.0599, 1319.9922)], [(0.0, 569.6015), (161.51752, 869.8641)], [(1038.5804, 1042.9966), (1076.7808, 1097.398)], [(1231.6813, 305.93085), (1618.3899, 852.3754)], [(0.3644816, 893.3566), (87.39571, 978.09436)], [(1.1957486, 717.7485), (158.03418, 1176.0779)], [(67.78371, 173.59235), (448.7855, 748.63654)]]
orignal score
[0.9986298, 0.9983411, 0.998161, 0.997095, 0.9964186, 0.98744327, 0.9854257, 0.98530376, 0.97725266, 0.97337264, 0.96058786, 0.88644713, 0.83272547, 0.7734675, 0.39064288, 0.35724017, 0.3154308, 0.29059145, 0.20217809, 0.19457912, 0.19040918, 0.16206688, 0.15520865, 0.13098373, 0.121276304, 0.116065815, 0.11003116, 0.10491751, 0.09857031, 0.089911185, 0.0815428, 0.07988655, 0.06910095, 0.06626528, 0.06596641, 0.0652364, 0.058985297, 0.05841243, 0.054988183]
12
[[(0.0, 319.6455), (441.5155, 1323.2559)], [(765.3034, 351.93936), (1193.7164, 1312.2843)], [(1156.9446, 394.623), (1569.2057, 1322.1747)], [(1519.3403, 429.56564), (1992.429, 1330.6052)], [(364.10757, 387.61426), (771.79016, 1306.173)], [(613.42804, 268.0113), (912.2196, 1241.745)], [(1439.0381, 336.10446), (1669.9921, 794.2212)], [(1723.9878, 289.32892), (1997.8444, 889.91785)], [(1154.8141, 183.47633), (1456.161, 705.3361)], [(1600.269, 197.45708), (1763.7482, 635.4068)], [(882.2303, 190.24492), (1243.9407, 746.71704)], [(546.1972, 241.6657), (717.2413, 541.52277)], [(236.73463, 101.11602), (489.53278, 667.32404)]]
['person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person', 'person']

示例2:

 下载图片:

wget https://hips.hearstapps.com/hmg-prod.s3.amazonaws.com/images/10best-cars-group-cropped-1542126037.jpg -O car.jpg

进行预测:

object_detection_api('./car.jpg', rect_th=6, text_th=5, text_size=5)

最终图像:

示例3:

下载图片:

wget https://cdn.pixabay.com/photo/2013/07/05/01/08/traffic-143391_960_720.jpg -O traffic_scene.jpg

进行预测:

object_detection_api('./traffic_scene.jpg', rect_th=2, text_th=1, text_size=1)

 最终结果:

示例4:

下载图像:

wget https://images.unsplash.com/photo-1458169495136-854e4c39548a -O girl_cars.jpg

 进行预测:

object_detection_api('./girl_cars.jpg', rect_th=15, text_th=7, text_size=5, threshold=0.8)

最终结果:

 

4、模型在CPU和GPU中推理时间对比

import time

def check_inference_time(image_path, gpu=False):
  model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)
  model.eval()
  img = Image.open(image_path)
  transform = T.Compose([T.ToTensor()])
  img = transform(img)
  if gpu:
    model.cuda()
    img = img.cuda()
  else:
    model.cpu()
    img = img.cpu()
  start_time = time.time()
  pred = model([img])
  end_time = time.time()
  return end_time-start_time

cpu_time = sum([check_inference_time('./girl_cars.jpg', gpu=False) for _ in range(10)])/10.0
gpu_time = sum([check_inference_time('./girl_cars.jpg', gpu=True) for _ in range(10)])/10.0


print('\n\nAverage Time take by the model with GPU = {}s\nAverage Time take by the model with CPU = {}s'.format(gpu_time, cpu_time))

输出结果:

Average Time take by the model with GPU = 0.15356571674346925s
Average Time take by the model with CPU = 8.458594107627869s

参考链接:https://www.learnopencv.com/faster-r-cnn-object-detection-with-pytorch/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章