做者|PRATEEK JOSHI 編譯|Flin 來源|analyticsvidhyapython
概述
-
你對智慧城市的想法感到興奮嗎?若是是的話,你會喜歡這個關於創建你本身的車輛檢測系統的教程的算法
-
在深刻實現部分以前,咱們將首先了解如何檢測視頻中的移動目標app
-
咱們將使用OpenCV和Python構建自動車輛檢測器框架
介紹
我喜歡智慧城市的理念。自動智能能源系統、電網、一鍵接入端口的想法等等。這是一個使人着迷的概念!老實說,這是一個數據科學家的夢想,我很高興世界上不少城市都在朝着更智能的方向發展。機器學習
智能城市的核心組成部分之一是自動交通管理。這不由讓我思考——我能用個人數據科學知識來創建一個車輛檢測模型,在智能交通管理中發揮做用嗎?ide
想一想看,若是你能在紅綠燈攝像頭中集成車輛檢測系統,你能夠輕鬆地同時跟蹤許多有用的東西:函數
- 白天交通路口有多少輛車?
- 何時交通堵塞?
- 什麼樣的車輛(重型車輛、汽車等)正在經過交叉路口?
- 有沒有辦法優化交通,並經過不一樣的街道進行分配?
還有不少例子就不一一列舉。應用程序是無止境的!學習
咱們人類能夠很容易地在一瞬間從複雜的場景中檢測和識別出物體。然而,將這種思惟過程轉化爲機器的思惟,須要咱們學習使用計算機視覺算法進行目標檢測。優化
所以在本文中,咱們將創建一個自動車輛檢測器和計數器模型。如下視頻是你能夠期待的體驗:ui
注意:還不懂深度學習和計算機視覺的新概念?如下是兩門熱門課程,可開啓你的深度學習之旅:
- 深度學習基礎(https://courses.analyticsvidhya.com/courses/fundamentals-of-deep-learning?utm_source=blog&utm_medium=vehicle-detection-opencv-python)
- 利用深度學習的計算機視覺(https://courses.analyticsvidhya.com/courses/computer-vision-using-deep-learning-version2?utm_source=blog&utm_medium=vehicle-detection-opencv-python)
目錄
-
視頻中運動目標檢測的思想
-
視頻中目標檢測的真實世界用例
-
視頻目標檢測的基本概念
-
幀差分
-
圖像閾值
-
檢測輪廓
-
圖像膨脹
- 利用OpenCV構建車輛檢測系統
視頻中運動目標檢測的思想
目標檢測是計算機視覺中一個引人入勝的領域。當咱們處理視頻數據時,它達到了一個全新的水平,複雜性上升了一個等級,但也有回報!
咱們可使用目標檢測算法來執行超級有用的高價值任務,如監視、交通管理、打擊犯罪等。下面的GIF圖演示了這個想法:
在目標檢測中,咱們能夠執行許多子任務,例如計算目標數量、查找目標的相對大小或查找目標之間的相對距離。這些子任務都很重要,由於它們有助於解決一些最棘手的現實問題。
若是你但願從頭開始學習目標檢測,我建議你使用如下教程:
-
利用SlimYOLOv3進行實時目標檢測(https://www.analyticsvidhya.com/blog/2019/08/introduction-slimyolov3-real-time-object-detection/?utm_source=blog&utm_medium=vehicle-detection-opencv-python)
讓咱們看看一些使人興奮的現實世界中的目標檢測用例。
視頻中目標檢測的真實世界用例
現在,視頻目標檢測正被普遍應用於各個行業。使用案例從視頻監控到體育廣播,再到機器人導航。
好消息是,在將來的視頻目標檢測和跟蹤用例中,可能性是無窮的。這裏我列出了一些有趣的應用程序:
- 人羣計數(https://www.analyticsvidhya.com/blog/2019/02/building-crowd-counting-model-python/)
- 車牌檢測與識別
- 運動中的球跟蹤(https://www.analyticsvidhya.com/blog/2020/03/ball-tracking-cricket-computer-vision/)
- 機器人學
- 交通管理(咱們將在本文中看到這個想法)
視頻目標檢測的基本概念
在開始構建視頻檢測系統以前,你應該知道一些關鍵概念。一旦你熟悉了這些基本概念,就能夠爲你選擇的任何用例構建本身的檢測系統。
那麼,你但願如何檢測視頻中的移動目標?
咱們的目標是捕捉運動物體的座標並在視頻中突出顯示該物體。請考慮下面視頻中的這一幀:
咱們但願咱們的模型可以檢測視頻中的運動目標,如上圖所示。檢測到移動的汽車,並在汽車周圍建立一個邊界框。
解決這個問題有多種方法。你能夠爲目標檢測訓練一個深度學習模型,也能夠選擇一個預先訓練好的模型並根據你的數據對其進行微調。然而,這些方法都是有監督的學習方法,須要標記數據來訓練目標檢測模型。
在本文中,咱們將重點討論視頻中無監督的目標檢測方法,即不使用任何標記數據的目標檢測。咱們將使用幀差分技術。讓咱們瞭解它是如何工做的!
幀差分
視頻是一組按正確順序堆疊在一塊兒的幀。因此,當咱們看到一個物體在視頻中移動時,這意味着這個物體在每個連續的幀上都處於不一樣的位置。
若是咱們假設除了該目標以外,在一對連續的幀中沒有其餘物體移動,那麼第一幀與第二幀的像素差將突出顯示移動目標的像素。如今,咱們獲得了移動物體的像素和座標。這就是幀差分法的工做原理。
舉個例子。考慮視頻中的如下兩個幀:
你能看出這兩幀的區別嗎?
握筆的手的位置從第1幀變爲第2幀。其他的物體根本沒有移動。因此,正如我前面提到的,爲了定位移動目標,咱們將執行幀差分。結果以下:
你能夠看到高亮或白色區域,這是手最初出現的地方。除此以外,記事本的邊緣也會突出顯示一點。這多是因爲手的移動改變了光照。建議不要對靜止物體進行沒必要要的檢測。所以,咱們須要對幀執行某些圖像預處理步驟。
圖像閾值
在這種方法中,灰度圖像的像素值根據閾值被指定爲表示黑白顏色的兩個值之一。所以,若是一個像素的值大於一個閾值,它被賦予一個值,不然它被賦予另外一個值。
在本例中,咱們將對上一步驟中幀差分的輸出圖像應用圖像閾值:
你能夠看到,不須要的高亮區域的大部分已經消失了。高亮顯示的「記事本」邊緣再也不可見。合成的圖像也能夠稱爲二值圖像,由於其中只有兩種顏色。在下一個步驟中,咱們將看到如何捕獲這些高亮區域。
檢測輪廓
輪廓用於識別圖像中具備相同顏色或強度的區域的形狀。輪廓就是目標區域周圍的邊界。所以,若是咱們在閾值步驟後對圖像應用輪廓檢測,咱們將獲得如下結果:
白色區域被淺灰色的邊界所包圍,這些邊界就是輪廓。咱們很容易獲得這些輪廓的座標。這意味着咱們能夠獲得高亮區域的位置。
請注意,有多個高亮顯示區域,每一個區域由輪廓包圍。在咱們的例子中,具備最大面積的輪廓是咱們指望的區域。所以,輪廓最好儘量少。
在上圖中,仍然有一些沒必要要的白色區域碎片。還有改進的餘地。咱們的想法是合併附近的白色區域以得到更少的輪廓,爲此,咱們可使用另外一種稱爲圖像膨脹的技術。
圖像膨脹
這是對圖像的卷積操做,其中核心(矩陣)傳遞到整個圖像上。爲了給你直覺,右邊的圖像是左邊圖像的放大版本:
因此,讓咱們對咱們的圖像進行圖像膨脹,而後咱們將再次找到輪廓:
事實證實,許多支離破碎的區域已經相互融合。如今咱們能夠再次在這張圖片中找到輪廓:
在這裏,咱們只有四個候選輪廓,從中咱們能夠選擇一個有最大面積的輪廓。也能夠在原始幀上繪製這些輪廓,以查看輪廓圍繞移動目標的狀況:
用OpenCV和Python構建車輛檢測系統
咱們準備創建咱們的車輛檢測系統!在這個實現中,咱們將大量使用計算機視覺庫OpenCV(4.0.0版)(https://www.analyticsvidhya.com/blog/2019/03/opencv-functions-computer-vision-python/?utm_source=blog&utm_medium=vehicle-detection-opencv-python) 。咱們先導入所需的庫和模塊。
導入庫
import os import re import cv2 # opencv library import numpy as np from os.path import isfile, join import matplotlib.pyplot as plt
導入視頻幀
請今後連接下載原始視頻的幀。
https://drive.google.com/file/d/1P0yiO5KlnU8dGgB_L68KB_hjIvUec55f/view
將框架保存在工做目錄中名爲「frames」的文件夾中。從該文件夾中,咱們將導入幀並將其保存在列表中:
# get file names of the frames col_frames = os.listdir('frames/') # sort file names col_frames.sort(key=lambda f: int(re.sub('\D', '', f))) # empty list to store the frames col_images=[] for i in col_frames: # read the frames img = cv2.imread('frames/'+i) # append the frames to the list col_images.append(img)
數據探索
讓咱們顯示兩個連續的幀:
# plot 13th frame i = 13 for frame in [i, i+1]: plt.imshow(cv2.cvtColor(col_images[frame], cv2.COLOR_BGR2RGB)) plt.title("frame: "+str(frame)) plt.show()
很難在這兩個框架中找到區別,不是嗎?如前所述,獲取兩個連續幀的像素值的差值將有助於咱們觀察移動目標。那麼,讓咱們在上面兩個幀上使用該技術:
# convert the frames to grayscale grayA = cv2.cvtColor(col_images[i], cv2.COLOR_BGR2GRAY) grayB = cv2.cvtColor(col_images[i+1], cv2.COLOR_BGR2GRAY) # plot the image after frame differencing plt.imshow(cv2.absdiff(grayB, grayA), cmap = 'gray') plt.show()
如今咱們能夠清楚地看到第13幀和第14幀中的移動目標。其餘沒有移動的東西都被減去了。
圖像預處理
讓咱們看看對上面的圖像應用閾值後會發生什麼:
diff_image = cv2.absdiff(grayB, grayA) # perform image thresholding ret, thresh = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY) # plot image after thresholding plt.imshow(thresh, cmap = 'gray') plt.show()
如今,移動物體(車輛)看起來更像咱們指望看到的那樣了,大部分噪音(不但願出現的白色區域)都消失了。可是,突出顯示的區域有點零碎。所以,咱們能夠對該圖像應用圖像膨脹:
# apply image dilation kernel = np.ones((3,3),np.uint8) dilated = cv2.dilate(thresh,kernel,iterations = 1) # plot dilated image plt.imshow(dilated, cmap = 'gray') plt.show()
移動的物體有更多的實心高亮區域。但願幀中每一個目標的輪廓數不超過3。
可是,咱們不會使用整個框架來檢測移動的車輛。咱們將首先選擇一個區域,若是車輛進入該區域,則僅檢測到該區域。
那麼,讓我向你展現咱們將會使用的區域:
# plot vehicle detection zone plt.imshow(dilated) cv2.line(dilated, (0, 80),(256,80),(100, 0, 0)) plt.show()
水平線y = 80如下的區域是咱們的車輛檢測區域。咱們將只檢測在這個區域發生的任何移動。你還能夠建立本身的檢測區。
如今讓咱們在上述幀的檢測區域中找到輪廓:
# find contours contours, hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
上面的代碼查找整個圖像中的全部輪廓,並將它們保存在變量"contours"中。因爲咱們只須要找到檢測區域中存在的輪廓,咱們將對發現的輪廓進行兩次檢查。
第一個檢查是輪廓左上角的y座標是否應大於等於80(我這裏包括另外一個檢查,x座標小於等於200)。另外一個檢查是輪廓的面積應該大於等於25。在cv2.courtoArea()函數的幫助下,你能夠找到輪廓區域。
valid_cntrs = [] for i,cntr in enumerate(contours): x,y,w,h = cv2.boundingRect(cntr) if (x <= 200) & (y >= 80) & (cv2.contourArea(cntr) >= 25): valid_cntrs.append(cntr) # count of discovered contours len(valid_cntrs)
接下來,讓咱們繪製輪廓和原始幀:
dmy = col_images[13].copy() cv2.drawContours(dmy, valid_cntrs, -1, (127,200,0), 2) cv2.line(dmy, (0, 80),(256,80),(100, 255, 255)) plt.imshow(dmy) plt.show()
太酷了!只有位於檢測區域內的車輛輪廓可見。這就是咱們在整個畫面中檢測車輛的方法
視頻中的車輛檢測
如今是時候對全部幀應用相同的圖像變換和預處理操做,並找到所需的輪廓。重申一下,咱們將遵循如下步驟:
-
對每對連續幀應用幀差分
-
對上一步的輸出圖像應用圖像閾值
-
對上一步的輸出圖像進行圖像放大
-
在上一步的輸出圖像中查找輪廓
-
檢測區域出現的候選輪廓
-
保存幀與最終輪廓
# kernel for image dilation kernel = np.ones((4,4),np.uint8) # font style font = cv2.FONT_HERSHEY_SIMPLEX # directory to save the ouput frames pathIn = "contour_frames_3/" for i in range(len(col_images)-1): # frame differencing grayA = cv2.cvtColor(col_images[i], cv2.COLOR_BGR2GRAY) grayB = cv2.cvtColor(col_images[i+1], cv2.COLOR_BGR2GRAY) diff_image = cv2.absdiff(grayB, grayA) # image thresholding ret, thresh = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY) # image dilation dilated = cv2.dilate(thresh,kernel,iterations = 1) # find contours contours, hierarchy = cv2.findContours(dilated.copy(), cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) # shortlist contours appearing in the detection zone valid_cntrs = [] for cntr in contours: x,y,w,h = cv2.boundingRect(cntr) if (x <= 200) & (y >= 80) & (cv2.contourArea(cntr) >= 25): if (y >= 90) & (cv2.contourArea(cntr) < 40): break valid_cntrs.append(cntr) # add contours to original frames dmy = col_images[i].copy() cv2.drawContours(dmy, valid_cntrs, -1, (127,200,0), 2) cv2.putText(dmy, "vehicles detected: " + str(len(valid_cntrs)), (55, 15), font, 0.6, (0, 180, 0), 2) cv2.line(dmy, (0, 80),(256,80),(100, 255, 255)) cv2.imwrite(pathIn+str(i)+'.png',dmy)
準備視頻
在這裏,咱們爲全部幀中的全部移動車輛添加了輪廓。如今是時候堆疊幀並建立視頻了:
# specify video name pathOut = 'vehicle_detection_v3.mp4' # specify frames per second fps = 14.0
接下來,咱們將閱讀列表中的最後一幀:
frame_array = [] files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))] files.sort(key=lambda f: int(re.sub('\D', '', f)))
for i in range(len(files)): filename=pathIn + files[i] #read frames img = cv2.imread(filename) height, width, layers = img.shape size = (width,height) #inserting the frames into an image array frame_array.append(img)
最後,咱們將使用如下代碼製做目標檢測視頻:
out = cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'DIVX'), fps, size) for i in range(len(frame_array)): # writing to a image array out.write(frame_array[i]) out.release()
恭喜你學會了車輛目標檢測!
尾註
在本教程中,咱們學習瞭如何使用幀差分技術在視頻中執行移動目標檢測。咱們還討論了目標檢測和圖像處理的一些概念。而後咱們用OpenCV創建了本身的運動目標檢測系統。
我確信,使用在本文中學習的技術和方法,你將構建本身版本的目標檢測系統。
原文連接:https://www.analyticsvidhya.com/blog/2020/04/vehicle-detection-opencv-python/
歡迎關注磐創AI博客站: http://panchuang.net/
sklearn機器學習中文官方文檔: http://sklearn123.com/
歡迎關注磐創博客資源彙總站: http://docs.panchuang.net/