基于深度学习和OpenCV的目标检测(Python)

今天说说使用深度学习进行目标检测的文章,第一部分讲讲Single shot detector(SSD)和MobileNet。这二者相结合,可以用来实现更快速的,实时的目标检测,尤其是在资源有限的设备上(包括Raspberry Pi, smartphones等等)。

这里就说说如何使用OpenCV中的dnn模块,用来导入一个实现训练好的目标检测网络。使我们可以把图像传送到深度网络中,然后得到图中每个物体的包围框(x,y)坐标。最后,我们使用MobileNet SSDs来检验这些图像。

使用Single Shot Detectors进行目标检测

当提到用深度学习进行目标检测时,主要有下面三种方法:

  • Faster R-CNNs

  • You Only Look Once(YOLO)

  • Single Shot Detectors(SSDs)

Faster R-CNNs是最常听说的基于深度学习的神经网络了。然而,这种方法在技术上是很难懂的(尤其是对于深度学习新手),也难以实现,训练起来也是很困难。

此外,即使是使用了“Faster”的方法实现R-CNNs(这里R表示候选区域Region Proposal),算法依然是比较慢的,大约是7FPS。

如果我们追求速度,我们可以转向YOLO,因为它非常的快,在TianXGPU上可以达到40-90 FPS,最快的版本可能达到155 FPS。但YOLO的问题在于它的精度还有待提高。

SSDs最初是由谷歌开发的,可以说是以上两者之间的平衡。相对于Faster R-CNNs,它的算法更加直接。相对于YOLO,又更加准确。

MobileNets:高效(深度)神经网路
20170425202801182.png

如上图:
(左)标准的卷积层,包含batchnorm和ReLU。
(右)将卷基层分为depthwise 和pointwise 层,然后再加上batchnorm和ReLU(图片和标题出自Liu et al.)

当搭建目标检测网络时,我们一般使用现有的网络架构,例如VGG 或者ResNet,然后在目标检测过程中使用它们。问题是,这些网络结构可能非常大,大约会有200-500MB。

这类网络架构不适用于资源有限的设备,因为因为他们的规模太大计算结果太多。作为替代的选择,我们使用MobileNets,另一个谷歌研究员的文章作品,我们称之为“MobileNets”。因为这就是为了资源有限的设备(比如说手机)而设计的。MobileNets与传统CNNs不同之处在于可分离卷积(depthwiseseparable convolution)。

depthwise separable convolution的概念一般是指把卷积分解成两部分:

1.一个3x3的denthwise卷积(深度卷积)

2.接着一个1x1的pointwise卷积(点卷积)

这使我们可以减少网络中的参数,降低计算量

这里有个问题就是损失了精度——MobileNets并不像其他的网络那样精度高。

但是他们更加的节省资源。

结合MobileNets和SSDs进行更快更高效的深度学习目标检测

如果我们把MobileNets和SSDs框架结合起来,我们可以实现更快速,更高效的基于深度学习的目标检测。这里使用的模型是original tensorflow impetension的Caffe版本,是由chuanqi305训练的。

MobileNets SSDs最初是在COCO dataset 上训练的,然后在PASCAL VOC进行调试并得到了72.7%的平均准确率。可以检测20种物体(1种是背景类的),包括飞机、单车、鸟、船、瓶子、公交车、汽车、猫、椅子、奶牛、餐桌、狗、马、摩托车、人、盆栽、羊、沙发、火车、和电视机。

基于深度学习的OpenCV目标检测

下面说说使用OpenCV搭建深度学习目标检测器。

首先新建一个文件,命名为“deep_learning_object_detection.py”,并插入如下代码:

# import the necessary packages
import numpy as np
import argparse
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required=True,
 help="path to input image")
ap.add_argument("-p", "--prototxt", required=True,
 help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,
 help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.4,
 help="minimum probability to filter weak detections")
args = vars(ap.parse_args())

我们要做的第一件事是导入这个例子中需要的包——cv2中包含的dnn模块,前提是使用的是OpenCV3.3版本。

然后传入参数:

  • --image : 输入图像的路径

  • --prototxt: Caffe模型的路径

  • --model:预训练的模型的路径

  • --confidence: 能过滤弱检测器的最小的可能性的阈值,默认是20%。

接下来,初始化类的标签和包围框的颜色:

CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
 "bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
 "dog", "horse", "motorbike", "person", "pottedplant", "sheep",
 "sofa", "train", "tvmonitor"]
COLORS = np.random.uniform(0, 255, size=(len(CLASSES), 3))

上面创建了一个叫“CLASSES”的列表,接下来是颜色列表,用于存放对应的包围框的颜色。接下来导入模型:

# load our serialized model from disk
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])

上面这段代码,主要是导入模型并打印了相关的信息。
接下来,我们导入待测的图片并准备blob,以便传输到在网络中。

# load the input image and construct an input blob for the image
# by resizing to a fixed 300x300 pixels and then normalizing it
# (note: normalization is done via the authors of the MobileNet SSD
# implementation)

image = cv2.imread(args["image"])
(h, w) = image.shape[:2]
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 0.007843, (300, 300), 127.5)

注意上面的注释块,我们导入了图片,提取了高度和宽度,计算了300x300的像素blob

现在我们准备关键的工作——把这个blob传入神经网络。

# pass the blob through the network and obtain the detections and
# predictions
print("[INFO] computing object detections...")
net.setInput(blob)
detections = net.forward()

这里我们设置了神经网络的输入,并且计算输入的前向传播,并将结果存储为“detections”计算前向传播和相关检测将花费一点时间,具体取决于模型和输入的尺寸,但是在这个例子里,大部分CPU都能进行快速的完成。

我们在“detections”中进行循环,检测图像中什么位置有什么样的目标:


# loop over the detections
for i in np.arange(0, detections.shape[2]):
 # extract the confidence (i.e., probability) associated with the
 # prediction
 confidence = detections[0, 0, i, 2]
 # filter out weak detections by ensuring the `confidence` is
 # greater than the minimum confidence
 if confidence > args["confidence"]:
 # extract the index of the class label from the `detections`,
 # then compute the (x, y)-coordinates of the bounding box for
 # the object
 idx = int(detections[0, 0, i, 1])

 box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])

 (startX, startY, endX, endY) = box.astype("int")

 # display the prediction
 label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100)

 print("[INFO] {}".format(label))

 cv2.rectangle(image, (startX, startY), (endX, endY),
 COLORS[idx], 2)

 y = startY - 15 if startY - 15 > 15 else startY + 15

 cv2.putText(image, label, (startX, y),
 cv2.FONT_HERSHEY_SIMPLEX, 0.5, COLORS[idx], 2)

从detectons的循环开始,记得单张图片中可能出现多个目标。我们还对每次检测应用了一个置信度的检查机制。如果置信度足够高(比如说超过了阈值),那么我们将会在终端上显示这个预测并且在图像上绘制彩色的包围框和文字,接下来我们逐句分析:

对detections进行循环,首先我们提取confidence值

如果confidence值超过了最小的阈值,我们提取类的标签序号并且计算围绕着被测物体的包围框。

然后,我们提取包围框的(x,y)坐标,用于绘制矩形和显示文字。

接下来,我们创建一个文字标签label,包含类CLASS的名字和置信度。

使用该标签,在终端上显示出来,同时根据(x,y)坐标绘制一个彩色的包围着物体的矩形框。

总的来说,我们希望标签在矩形之上,如果空间不够,也可以把他们显示在矩形框的最上面一根线的下方。

最后,我们在图像上叠加彩色的标签文字

接下来的步骤就是显示结果:

# show the output image
cv2.imshow("Output", image)
cv2.imwrite("output.jpg",image)
cv2.waitKey(0)

我们在屏幕上显示输出的图片,直到用户按下一个任意键将其中止。同时将绘制标记后的图像保存下来。

OpenCV和深度学习目标检测结果

要运行上面的代码只要打开终端,运行

$ python deep_learning_object_detection.py \
 --prototxt MobileNetSSD_deploy.prototxt.txt \
 --model MobileNetSSD_deploy.caffemodel --image images/example_19.jpg

结果


output-19.jpg
[INFO] loading model...
[INFO] computing object detections...
[INFO] car: 99.71%
[INFO] car: 98.40%

上图识别出一辆汽车的概率是99.99%

换一个例子:

运行


$ python deep_learning_object_detection.py \
 --prototxt MobileNetSSD_deploy.prototxt.txt \
 --model MobileNetSSD_deploy.caffemodel --image images/example_18.jpg

结果


output-18.jpg
[INFO] loading model...
[INFO] computing object detections...
[INFO] chair: 99.96%
[INFO] chair: 99.78%
[INFO] chair: 58.37%
[INFO] diningtable: 99.90%
[INFO] pottedplant: 51.57%

再换一个例子:

运行

$ python deep_learning_object_detection.py \
 --prototxt MobileNetSSD_deploy.prototxt.txt \
 --model MobileNetSSD_deploy.caffemodel --image images/example_16.jpg

结果


output-16.jpg
[INFO] loading model...
[INFO] computing object detections...
[INFO] bicycle: 69.82%
[INFO] bicycle: 66.97%
[INFO] car: 99.99%
[INFO] person: 99.98%
[INFO] person: 51.63%
总结

这一篇我们使用了MobileNets + SSDs检测器和OpenCV3.3最新的dnn模块进行图像中的目标检测。接下来还会写如何在视频流中进行目标检测。

参考:
https://www.pyimagesearch.com/2017/09/11/object-detection-with-deep-learning-and-opencv/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,294评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,493评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,790评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,595评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,718评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,906评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,053评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,797评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,250评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,570评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,711评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,388评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,018评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,796评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,023评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,461评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,595评论 2 350

推荐阅读更多精彩内容