OpenCV行人检测
注:本文翻譯自:Pedestrian Detection OpenCV。
你知道OpenCV里面已經內置的行人檢測方法嗎?在OpenCV里面,有一個預先訓練好了的HOG+線性SVM模型,能夠對圖像和視頻中的行人進行檢測。如果你還不熟悉方向梯度直方圖HOG和線性SVM方法,我建議你閱讀方向梯度直方圖和物體檢測這篇文章,在這篇文章中,我對該框架分了6步進行討論。
如果你已經熟悉了這個過程,或者你僅僅只是想看看OpenCV行人檢測的代碼,那么現在就打開一個新文件,并將它命名為detect.py,開始我們的編程之旅吧:
1 # import the necessary packages 2 from __future__ import print_function 3 from imutils.object_detection import non_max_suppression 4 from imutils import paths 5 import numpy as np 6 import argparse 7 import imutils 8 import cv2 9 10 # construct the argument parse and parse the arguments 11 ap = argparse.ArgumentParser() 12 ap.add_argument("-i", "--images", required=True, help="path to images directory") 13 args = vars(ap.parse_args()) 14 15 # initialize the HOG descriptor/person detector 16 hog = cv2.HOGDescriptor() 17 hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())第2-8行導入一些我們必要的包,我們導入print_function確保我們的代碼同時在Python2.7和Python3上兼容,這樣可以使得我們的代碼能夠在OpenCV2.4.X和OPenCV3上都能夠工作,然后,從我的imutils包中我們導入non_max_suppression函數。
如果你還沒有安裝imutils,可以通過pip來安裝:
$ pip install imutils如果你已經安裝了imutils,你需要把它更新到最新版(v0.3.1),在這個版本里面,包含了non_max_suppression函數的實現,以及其它一些微小的更新:
$ pip install --upgrade imutils我已經在我的PyImageSearch博客上在兩次講到過非極大抑制(non-maxima suppression)方法,一次是在Python非極大抑制用于物體檢測,一篇是在用Python實現更快的非極大抑制,無論是哪一種情形,非極大抑制的宗旨都是獲取多個重疊的邊框(bounding box),并且將他們減少至僅有一個邊框。
圖1:左圖有很多檢測錯誤的邊框;右圖采用非極大抑制后,使得我們可以抑制那些重疊的區域,將正確的邊框留下來。
非極大抑制方法可以減少在進行行人檢測過程中的假陽率。
第11-13行處理我們命令行傳入的參數,這里,我們只需要一個切換--images,用它來傳入待檢測行人的圖像目錄。
最后,第16行和17行初始化我們的行人檢測器。首先,我們調用hog = cv2.HOGDescriptor()來初始化方向梯度直方圖描述子,然后,我們調用setSVMDetector來設置支持向量機(Support Vector Machine)使得它成為一個預先訓練好了的行人檢測器。
到了這里,我們的OpenCV行人檢測器已經完全載入了,我們只需要把它應用到一些圖像上:
1 # import the necessary packages 2 from __future__ import print_function 3 from imutils.object_detection import non_max_suppression 4 from imutils import paths 5 import numpy as np 6 import argparse 7 import imutils 8 import cv2 9 10 # construct the argument parse and parse the arguments 11 ap = argparse.ArgumentParser() 12 ap.add_argument("-i", "--images", required=True, help="path to images directory") 13 args = vars(ap.parse_args()) 14 15 # initialize the HOG descriptor/person detector 16 hog = cv2.HOGDescriptor() 17 hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) 18 19 # loop over the image paths 20 for imagePath in paths.list_images(args["images"]): 21 # load the image and resize it to (1) reduce detection time 22 # and (2) improve detection accuracy 23 image = cv2.imread(imagePath) 24 image = imutils.resize(image, width=min(400, image.shape[1])) 25 orig = image.copy() 26 27 # detect people in the image 28 (rects, weights) = hog.detectMultiScale(image, winStride=(4, 4), 29 padding=(8, 8), scale=1.05) 30 31 # draw the original bounding boxes 32 for (x, y, w, h) in rects: 33 cv2.rectangle(orig, (x, y), (x + w, y + h), (0, 0, 255), 2) 34 35 # apply non-maxima suppression to the bounding boxes using a 36 # fairly large overlap threshold to try to maintain overlapping 37 # boxes that are still people 38 rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects]) 39 pick = non_max_suppression(rects, probs=None, overlapThresh=0.65) 40 41 # draw the final bounding boxes 42 for (xA, yA, xB, yB) in pick: 43 cv2.rectangle(image, (xA, yA), (xB, yB), (0, 255, 0), 2) 44 45 # show some information on the number of bounding boxes 46 filename = imagePath[imagePath.rfind("/") + 1:] 47 print("[INFO] {}: {} original boxes, {} after suppression".format( 48 filename, len(rects), len(pick))) 49 50 # show the output images 51 cv2.imshow("Before NMS", orig) 52 cv2.imshow("After NMS", image) 53 cv2.waitKey(0)在第20行我們對我們的--images目錄下的圖像進行循環,這篇博文中使用的例子樣本是從INRIA Person Dataset這個很流行的人物庫上抽取的,更具體的說,是從GRAZ-01子集中抽取出來的,這些圖片存放在源碼目錄下面了。
第23-25行載入磁盤中的圖像,并且將圖像裁剪到最大寬度為400個像素,之所以降低我們的圖像維度(其實就是之所以對我們的圖像尺寸進行裁剪)主要有兩個原因:
真正對圖像中的行人進行檢測的代碼是在第28行和29行,通過調用detectMultiScale的hog描述子方法。這個detectMultiScale方法構造了一個尺度scale=1.05的圖像金字塔,以及一個分別在x方向和y方向步長為(4,4)像素大小的滑窗。
窗口的大小固定在32*128像素大小,這個設置是按照 seminal Dalal和Triggs論文來設置的。detectMultiScale函數會返回一個2-元組的rects,或者是圖像中每一個行人的邊框坐標(x,y),以及由SVM在每一次檢測中返回的weights置信值(我們一般也成為分數,譯者注)。
scale的尺度設置得越大,在圖像金字塔中層的數目就越少,相應的檢測速度就越快,但是尺度太大會導致行人出現漏檢;同樣的,如果scale設置得太小,將會急劇的增加圖像金字塔的層數,這樣不僅耗費計算資源,而且還會急劇地增加檢測過程中出現的假陽數目(也就是不是行人的被檢測成行人)。這表明,scale是在行人檢測過程中它是一個重要的參數,需要對scale進行調參。我會在后面的文章中對detectMultiScale中的每個參數做些調研。
第32行和33行獲取我們的初始邊框,并將它們在圖像上框出來。
不過,你將會看到在一些圖像上有的行人框出來的框,有很多重疊的邊框,如上面1圖所示。
針對這種情況,我們有兩種選擇。一種選擇是檢測一個邊框是否完全包含了另一個邊框(你可以看看OpenV中的一些實現例子)。另外一種選擇是應用非極大抑制方法,通過設置一個閾值來抑制那些重疊的邊框,這就是第38行和39行所干的事。
注意:如果你想了解更多HOG框架和非極大抑制,我推薦你閱讀方向梯度直方圖和物體檢測。在那篇博文中,你可以查看Python非極大抑制用于物體檢測,以及后面更新的Malisiewicz方法。
在應用非極大抑制后,我們在第42行和43行畫出最終的邊框,在第46-48行中我們展示圖像的一些基本信息,以及檢測到的邊框數目,在第51-53行,在屏幕最終顯示我們輸入的圖像。
行人檢測結果
為了看看我們寫的行人檢測腳本的實際效果,我們只需要執行下面命令:
$ python detect.py --images images下圖是一張行人檢測的結果圖:
圖2:檢測效果
上圖我們檢測到了站在警車旁的單個行人。
圖3:在前景和背景中分別檢測到了1個人
上面我們可以看到在前景中的男人被檢測到了,同時背景中推著嬰兒車的女人也檢測到了。
圖4:一個展示為什么用非極大抑制很重要的例子
圖4的例子展示了為什么用非極大抑制很重要。detectMultiScale函數除了將正確的邊框檢測出來外,還把兩個邊框邊框檢測出來了,這兩個錯誤的邊框將圖像中的行人覆蓋了。通過使用非極大抑制,我們可以抑制錯誤的邊框,只留下正確檢測的邊框。
圖5:另一個展示非極大抑制效果的例子
我們再一次可以看到,有很多錯誤的邊框被檢測出來了,通過使用非極大抑制,我們可以抑制錯誤的邊框,只留下正確檢測的邊框。
圖6:在一個購物中心檢測行人
圖6在一個購物中心進行行人檢測,圖中,有兩個人正向攝像頭走進,另外一個人正遠離攝像頭,不管是哪種情形,我們的HOG檢測方法都能夠準確的檢測出行人。在non_maxima_suppression函數中較大的overlapThresh能夠確保那些部分重疊了的邊框不會被抑制。
圖7:在模糊圖片中檢測行人
老實說,我對上面圖片的檢測結果有點兒驚訝,因為一般而言HOG描述子在運動模糊的圖片上檢測效果不是很好,不過在這幅圖像上,我們卻將行人檢測出來了。
圖8:在室外街道上檢測行人
這里有另外一個多個重疊邊框的例子,不過因為我們的overlapThresh設置得比較大,所以這些邊框沒有被抑制,從而能夠將正確的檢測結果留下來。
圖9:檢測一張具有4個成員的家庭的圖片
圖9的例子展示了HOG+SVM行人檢測器的多功能性,我們不僅能夠檢測到成年的男人,也能夠檢測到那三個小孩(注意:該檢測器不能檢測到躲藏在他老爸后面的小孩)。
圖10:對路標標識進行行人檢測
我將圖10放在最后是因為我發覺這非常的有趣,我們可以很清楚的看到這只是一個路標標識,標識表示人行橫道,然而,HOG+SVM檢測器將它們在圖中框出來了,實際上它們卻并不是行人。
總結
在這篇博文中,我們已經學到了怎樣使用OpenCV的庫以及Python來進行行人檢測。
實際上OpenCV庫已經內置了一個預先訓練好了的HOG+線性SVM檢測器的模型,它是基于Dalal和Triggs論文里的方法來自動的實現圖像中行人的檢測。
雖然HOG的方法比Haar counter-part的精度要高,不過它仍需要對detectMultiScale進行合理的設置。在后面的博文中,我會對detectMultiScale中的每一個參數做一個調研,已經怎樣調參的細節,并陳述在精度和性能之間的折中。
不管怎么說,我都希望你喜歡這篇博文!我正打算在后面給出更多的關于物體檢測的教程,如果你希望這些教程出來后能夠獲得及時的通知,你可以考慮訂閱我的博客。
我已經在PyImageSearch Gurus course里面包含了HOG+線性SVM的物體檢測方法,你可以看看。
from:?http://yongyuan.name/blog/pedestrian-detection-opencv.html
總結
以上是生活随笔為你收集整理的OpenCV行人检测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 卷及神经网络CNN for image
- 下一篇: caffe配置中的一些问题