今天說說使用深度學(xué)習(xí)進(jìn)行目標(biāo)檢測(cè)的文章努溃,第一部分講講Single shot detector(SSD)和MobileNet泽本。這二者相結(jié)合蠢琳,可以用來實(shí)現(xiàn)更快速的,實(shí)時(shí)的目標(biāo)檢測(cè)笋敞,尤其是在資源有限的設(shè)備上(包括Raspberry Pi, smartphones等等)碱蒙。
這里就說說如何使用OpenCV中的dnn模塊,用來導(dǎo)入一個(gè)實(shí)現(xiàn)訓(xùn)練好的目標(biāo)檢測(cè)網(wǎng)絡(luò)夯巷。使我們可以把圖像傳送到深度網(wǎng)絡(luò)中赛惩,然后得到圖中每個(gè)物體的包圍框(x,y)坐標(biāo)。最后趁餐,我們使用MobileNet SSDs來檢驗(yàn)這些圖像喷兼。
使用Single Shot Detectors進(jìn)行目標(biāo)檢測(cè)
當(dāng)提到用深度學(xué)習(xí)進(jìn)行目標(biāo)檢測(cè)時(shí),主要有下面三種方法:
Faster R-CNNs
You Only Look Once(YOLO)
Single Shot Detectors(SSDs)
Faster R-CNNs是最常聽說的基于深度學(xué)習(xí)的神經(jīng)網(wǎng)絡(luò)了后雷。然而季惯,這種方法在技術(shù)上是很難懂的(尤其是對(duì)于深度學(xué)習(xí)新手),也難以實(shí)現(xiàn)臀突,訓(xùn)練起來也是很困難勉抓。
此外,即使是使用了“Faster”的方法實(shí)現(xiàn)R-CNNs(這里R表示候選區(qū)域Region Proposal)候学,算法依然是比較慢的藕筋,大約是7FPS。
如果我們追求速度梳码,我們可以轉(zhuǎn)向YOLO隐圾,因?yàn)樗浅5目欤赥ianXGPU上可以達(dá)到40-90 FPS掰茶,最快的版本可能達(dá)到155 FPS暇藏。但YOLO的問題在于它的精度還有待提高。
SSDs最初是由谷歌開發(fā)的濒蒋,可以說是以上兩者之間的平衡盐碱。相對(duì)于Faster R-CNNs,它的算法更加直接沪伙。相對(duì)于YOLO瓮顽,又更加準(zhǔn)確。
MobileNets:高效(深度)神經(jīng)網(wǎng)路
如上圖:
(左)標(biāo)準(zhǔn)的卷積層焰坪,包含batchnorm和ReLU。
(右)將卷基層分為depthwise 和pointwise 層聘惦,然后再加上batchnorm和ReLU(圖片和標(biāo)題出自Liu et al.)
當(dāng)搭建目標(biāo)檢測(cè)網(wǎng)絡(luò)時(shí)某饰,我們一般使用現(xiàn)有的網(wǎng)絡(luò)架構(gòu)儒恋,例如VGG 或者ResNet,然后在目標(biāo)檢測(cè)過程中使用它們黔漂。問題是诫尽,這些網(wǎng)絡(luò)結(jié)構(gòu)可能非常大,大約會(huì)有200-500MB炬守。
這類網(wǎng)絡(luò)架構(gòu)不適用于資源有限的設(shè)備牧嫉,因?yàn)橐驗(yàn)樗麄兊囊?guī)模太大計(jì)算結(jié)果太多。作為替代的選擇减途,我們使用MobileNets,另一個(gè)谷歌研究員的文章作品酣藻,我們稱之為“MobileNets”。因?yàn)檫@就是為了資源有限的設(shè)備(比如說手機(jī))而設(shè)計(jì)的鳍置。MobileNets與傳統(tǒng)CNNs不同之處在于可分離卷積(depthwiseseparable convolution)辽剧。
depthwise separable convolution的概念一般是指把卷積分解成兩部分:
1.一個(gè)3x3的denthwise卷積(深度卷積)
2.接著一個(gè)1x1的pointwise卷積(點(diǎn)卷積)
這使我們可以減少網(wǎng)絡(luò)中的參數(shù),降低計(jì)算量
這里有個(gè)問題就是損失了精度——MobileNets并不像其他的網(wǎng)絡(luò)那樣精度高税产。
但是他們更加的節(jié)省資源怕轿。
結(jié)合MobileNets和SSDs進(jìn)行更快更高效的深度學(xué)習(xí)目標(biāo)檢測(cè)
如果我們把MobileNets和SSDs框架結(jié)合起來,我們可以實(shí)現(xiàn)更快速辟拷,更高效的基于深度學(xué)習(xí)的目標(biāo)檢測(cè)撞羽。這里使用的模型是original tensorflow impetension的Caffe版本,是由chuanqi305訓(xùn)練的衫冻。
MobileNets SSDs最初是在COCO dataset 上訓(xùn)練的诀紊,然后在PASCAL VOC進(jìn)行調(diào)試并得到了72.7%的平均準(zhǔn)確率∮鸾埽可以檢測(cè)20種物體(1種是背景類的)渡紫,包括飛機(jī)、單車考赛、鳥惕澎、船、瓶子颜骤、公交車唧喉、汽車、貓忍抽、椅子八孝、奶牛、餐桌鸠项、狗干跛、馬、摩托車祟绊、人楼入、盆栽哥捕、羊、沙發(fā)嘉熊、火車遥赚、和電視機(jī)。
基于深度學(xué)習(xí)的OpenCV目標(biāo)檢測(cè)
下面說說使用OpenCV搭建深度學(xué)習(xí)目標(biāo)檢測(cè)器阐肤。
首先新建一個(gè)文件凫佛,命名為“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())
我們要做的第一件事是導(dǎo)入這個(gè)例子中需要的包——cv2中包含的dnn模塊孕惜,前提是使用的是OpenCV3.3版本愧薛。
然后傳入?yún)?shù):
--image : 輸入圖像的路徑
--prototxt: Caffe模型的路徑
--model:預(yù)訓(xùn)練的模型的路徑
--confidence: 能過濾弱檢測(cè)器的最小的可能性的閾值,默認(rèn)是20%诊赊。
接下來厚满,初始化類的標(biāo)簽和包圍框的顏色:
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))
上面創(chuàng)建了一個(gè)叫“CLASSES”的列表,接下來是顏色列表碧磅,用于存放對(duì)應(yīng)的包圍框的顏色碘箍。接下來導(dǎo)入模型:
# load our serialized model from disk
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
上面這段代碼,主要是導(dǎo)入模型并打印了相關(guān)的信息鲸郊。
接下來丰榴,我們導(dǎo)入待測(cè)的圖片并準(zhǔn)備blob,以便傳輸?shù)皆诰W(wǎng)絡(luò)中秆撮。
# 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)
注意上面的注釋塊四濒,我們導(dǎo)入了圖片,提取了高度和寬度职辨,計(jì)算了300x300的像素blob
現(xiàn)在我們準(zhǔn)備關(guān)鍵的工作——把這個(gè)blob傳入神經(jīng)網(wǎng)絡(luò)盗蟆。
# pass the blob through the network and obtain the detections and
# predictions
print("[INFO] computing object detections...")
net.setInput(blob)
detections = net.forward()
這里我們?cè)O(shè)置了神經(jīng)網(wǎng)絡(luò)的輸入,并且計(jì)算輸入的前向傳播舒裤,并將結(jié)果存儲(chǔ)為“detections”計(jì)算前向傳播和相關(guān)檢測(cè)將花費(fèi)一點(diǎn)時(shí)間喳资,具體取決于模型和輸入的尺寸,但是在這個(gè)例子里腾供,大部分CPU都能進(jìn)行快速的完成仆邓。
我們?cè)凇癲etections”中進(jìn)行循環(huán),檢測(cè)圖像中什么位置有什么樣的目標(biāo):
# 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的循環(huán)開始伴鳖,記得單張圖片中可能出現(xiàn)多個(gè)目標(biāo)节值。我們還對(duì)每次檢測(cè)應(yīng)用了一個(gè)置信度的檢查機(jī)制。如果置信度足夠高(比如說超過了閾值)榜聂,那么我們將會(huì)在終端上顯示這個(gè)預(yù)測(cè)并且在圖像上繪制彩色的包圍框和文字搞疗,接下來我們逐句分析:
對(duì)detections進(jìn)行循環(huán),首先我們提取confidence值
如果confidence值超過了最小的閾值须肆,我們提取類的標(biāo)簽序號(hào)并且計(jì)算圍繞著被測(cè)物體的包圍框匿乃。
然后脐往,我們提取包圍框的(x,y)坐標(biāo),用于繪制矩形和顯示文字扳埂。
接下來,我們創(chuàng)建一個(gè)文字標(biāo)簽label瘤礁,包含類CLASS的名字和置信度阳懂。
使用該標(biāo)簽,在終端上顯示出來柜思,同時(shí)根據(jù)(x,y)坐標(biāo)繪制一個(gè)彩色的包圍著物體的矩形框岩调。
總的來說,我們希望標(biāo)簽在矩形之上赡盘,如果空間不夠号枕,也可以把他們顯示在矩形框的最上面一根線的下方。
最后陨享,我們?cè)趫D像上疊加彩色的標(biāo)簽文字
接下來的步驟就是顯示結(jié)果:
# show the output image
cv2.imshow("Output", image)
cv2.imwrite("output.jpg",image)
cv2.waitKey(0)
我們?cè)谄聊簧巷@示輸出的圖片葱淳,直到用戶按下一個(gè)任意鍵將其中止。同時(shí)將繪制標(biāo)記后的圖像保存下來抛姑。
OpenCV和深度學(xué)習(xí)目標(biāo)檢測(cè)結(jié)果
要運(yùn)行上面的代碼只要打開終端赞厕,運(yùn)行
$ python deep_learning_object_detection.py \
--prototxt MobileNetSSD_deploy.prototxt.txt \
--model MobileNetSSD_deploy.caffemodel --image images/example_19.jpg
結(jié)果
[INFO] loading model...
[INFO] computing object detections...
[INFO] car: 99.71%
[INFO] car: 98.40%
上圖識(shí)別出一輛汽車的概率是99.99%
換一個(gè)例子:
運(yùn)行
$ python deep_learning_object_detection.py \
--prototxt MobileNetSSD_deploy.prototxt.txt \
--model MobileNetSSD_deploy.caffemodel --image images/example_18.jpg
結(jié)果
[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%
再換一個(gè)例子:
運(yùn)行
$ python deep_learning_object_detection.py \
--prototxt MobileNetSSD_deploy.prototxt.txt \
--model MobileNetSSD_deploy.caffemodel --image images/example_16.jpg
結(jié)果
[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%
總結(jié)
這一篇我們使用了MobileNets + SSDs檢測(cè)器和OpenCV3.3最新的dnn模塊進(jìn)行圖像中的目標(biāo)檢測(cè)。接下來還會(huì)寫如何在視頻流中進(jìn)行目標(biāo)檢測(cè)定硝。
參考:
https://www.pyimagesearch.com/2017/09/11/object-detection-with-deep-learning-and-opencv/