人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

總覽

  • 對智慧城市的想法感到興奮嗎?您會喜歡本教程的內容,以構建自己的車輛檢測系統
  • 在深入研究實現部分之前,我們將首先了解如何檢測視頻中的移動對象。
  • 我們將使用OpenCV和Python來構建自動車輛檢測器

介紹

我喜歡智慧城市的想法。關於自動化智能能源系統,電網,一鍵式訪問端口的想法–這是一個令人著迷的概念!老實說,對於數據科學家來說,這是一個夢想,我很高興世界各地的許多城市都在朝著變得更加智能化的方向邁進。

智慧城市的核心組件之一是自動交通管理。這讓我開始思考–我是否可以使用數據科學知識來構建可以在智能交通管理中發揮作用的車輛檢測模型?

考慮一下–如果您可以將車輛檢測系統集成到交通信號燈攝像頭中,則可以輕鬆地同時跟蹤許多有用的東西:

  • 白天在交通路口有多少輛車?
  • 流量什麼時間建立?
  • 什麼樣的車輛在交叉路口行駛(重型車輛,小汽車等)?
  • 有沒有一種方法可以優化交通量並通過其他街道進行分配?

我們人類可以輕鬆地從複雜場景中瞬間檢測和識別物體。但是,將思維過程轉化為機器,需要我們學習使用計算機視覺算法進行對象檢測的技術。

因此,在本文中,我們將構建一個自動車輛檢測器和計數器模型。

目錄

  1. 檢測視頻中的運動對象的想法
  2. 視頻中對象檢測的實際用例
  3. 您應該瞭解的有關視頻對象檢測的基本概念
    幀差異
    圖像閾值
    輪廓發現
    圖像擴張
  4. 使用OpenCV構建車輛檢測系統

檢測視頻中的運動對象的想法

對象檢測是計算機視覺中一個引人入勝的領域。當我們處理視頻數據時,它達到了一個全新的水平。複雜性提高了一個等級,但是獎勵也是如此!

我們可以使用對象檢測算法執行超有用的高價值任務,例如監視,交通管理,打擊犯罪等。

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

我們可以在對象檢測中執行許多子任務,例如計算對象數,找到對象的相對大小或找到對象之間的相對距離。所有這些子任務都很重要,因為它們有助於解決一些最棘手的現實問題。

視頻中對象檢測的實際用例

如今,視頻對象檢測已廣泛應用於各個行業。用例範圍從視頻監視到體育廣播再到機器人導航。

這是個好消息–涉及視頻對象檢測和跟蹤的未來用例時,可能性無窮無盡。在這裡,我列出了一些有趣的應用程序:

  1. 人群計數
  2. 車牌識別與識別
  3. 運動中的球追蹤
  4. 機器人技術
  5. 流量管理(我們將在本文中看到的一個想法)

您應該瞭解的有關視頻對象檢測的基本概念

在開始構建視頻檢測系統之前,您應該瞭解一些關鍵概念。一旦熟悉了這些基本概念,就可以針對您選擇的任何用例構建自己的檢測系統。

那麼,您想如何檢測視頻中的運動物體?

我們的目標是捕獲運動對象的座標並在視頻中突出顯示該對象。考慮以下視頻中的這一幀:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

我們希望我們的模型能夠檢測視頻中的運動對象,如上圖所示。檢測到正在行駛的汽車,並在汽車周圍創建一個邊界框。

有多種技術可以解決此問題。您可以訓練用於對象檢測的深度學習模型,也可以選擇一個預先訓練的模型並在數據上進行微調。但是,這些是有監督的學習方法,它們需要標記的數據來訓練對象檢測模型。

在本文中,我們將重點介紹視頻中對象檢測的無監督方式,即不使用任何標記數據的對象檢測。我們將使用幀差分技術讓我們瞭解它是如何工作的!


幀差異

視頻是一組按正確順序堆疊在一起的幀。因此,當我們看到一個對象在視頻中移動時,這意味著該對象在每個連續的幀中都位於不同的位置。

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

如果我們假設除了那個物體,沒有其他物體在一對連續的幀中移動,那麼第一幀與第二幀的像素差異將突出顯示移動物體的像素。現在,我們將獲得運動對象的像素和座標。大致來說,這就是幀差異方法的工作方式。

讓我們舉個例子。考慮視頻中的以下兩個幀:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

您能發現兩個框架之間的差異嗎?

是的–是握筆的手的位置從第1幀更改為第2幀。其餘對象完全沒有移動。因此,正如我前面提到的,要定位運動對象,我們將執行幀差分。結果將如下所示:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

您可以看到最初出現手的突出顯示區域或白色區域。除此之外,記事本還沿其邊緣突出了一點。這可能是由於手的運動引起的照明變化。建議擺脫對靜止物體的不必要檢測。因此,我們需要在幀上執行某些圖像預處理步驟。

圖像閾值

在該方法中,基於閾值為灰度圖像的像素值分配代表黑色和白色的兩個值之一。因此,如果像素的值大於閾值,則為其分配一個值,否則為其分配另一個值。

在我們的情況下,我們將在上一步中對差異幀的輸出圖像應用圖像閾值處理:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

您會看到不需要的突出顯示區域的大部分已消失。記事本的突出顯示的邊緣不再可見。生成的圖像也可以稱為二進制圖像,因為其中只有兩種顏色。在下一步中,我們將看到如何捕獲這些突出顯示的區域。

尋找輪廓

輪廓用於識別圖像中具有相同顏色或強度的區域的形狀。輪廓就像是感興趣區域周圍的邊界。因此,如果在閾值化步驟之後在圖像上應用輪廓,則會得到以下結果:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

白色區域被灰色邊界包圍,僅是輪廓。我們可以輕鬆獲得這些輪廓的座標。這意味著我們可以獲取突出顯示區域的位置。

請注意,存在多個突出顯示的區域,每個區域都被輪廓包圍。在我們的情況下,具有最大面積的輪廓是所需區域。因此,最好具有儘可能少的輪廓。

在上圖中,白色區域仍然存在一些不必要的碎片。仍有改進的餘地。想法是合併附近的白色區域以減少輪廓,為此,我們可以使用另一種稱為圖像擴張的技術。

圖像擴張

這是對圖像的卷積運算,其中內核(矩陣)在整個圖像上傳遞。只是為了給您直觀感,右邊的圖像是左邊圖像的放大版:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

因此,讓我們對圖像進行圖像放大,然後再次找到輪廓:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

事實證明,很多碎片區域相互融合。現在,我們可以再次在該圖像中找到輪廓:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

在這裡,我們只有四個候選輪廓,可以從中選擇面積最大的輪廓。您還可以在原始框架上繪製這些輪廓,以查看輪廓圍繞移動對象的程度:

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

使用OpenCV和Python構建車輛檢測系統

我們都準備建立我們的車輛檢測系統!在此實現中,我們將大量使用計算機視覺庫OpenCV(版本4.0.0)。首先,導入所需的庫和模塊。

導入庫

import osimport reimport cv2 # opencv libraryimport numpy as npfrom os.path import isfile, joinimport matplotlib.pyplot as plt

導入視頻幀

請從此鏈接下載原始視頻的幀。

將框架保存在工作目錄內名為“ frames”的文件夾中。從該文件夾中,我們將導入框架並將其保留在列表中:

# get file names of the framescol_frames = os.listdir('frames/') # sort file namescol_frames.sort(key=lambda f: int(re.sub('\\D', '', f))) # empty list to store the framescol_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 framei = 13 for frame in [i, i+1]: plt.imshow(cv2.cvtColor(col_images[frame], cv2.COLOR_BGR2RGB)) plt.title("frame: "+str(frame)) plt.show()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

很難在這兩個框架中找到任何區別,不是嗎?如前所述,採用兩個連續幀的像素值之差將有助於我們觀察運動物體。因此,讓我們在以上兩個幀上使用該技術:

# convert the frames to grayscalegrayA = cv2.cvtColor(col_images[i], cv2.COLOR_BGR2GRAY)grayB = cv2.cvtColor(col_images[i+1], cv2.COLOR_BGR2GRAY) # plot the image after frame differencingplt.imshow(cv2.absdiff(grayB, grayA), cmap = 'gray')plt.show()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

現在我們可以清楚地看到第13幀和第14幀中的運動對象。其他所有不動的東西都被減去。

圖像預處理

讓我們看看將閾值應用於上圖之後會發生什麼:

diff_image = cv2.absdiff(grayB, grayA) # perform image thresholdingret, thresh = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY) # plot image after thresholdingplt.imshow(thresh, cmap = 'gray')plt.show()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

現在,運動物體(車輛)看起來更有希望,並且大部分噪音(不需要的白色區域)都消失了。但是,突出顯示的區域有些零散。因此,我們可以對該圖像應用圖像膨脹:

# apply image dilationkernel = np.ones((3,3),np.uint8)dilated = cv2.dilate(thresh,kernel,iterations = 1) # plot dilated imageplt.imshow(dilated, cmap = 'gray')plt.show()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

移動的對象具有更堅實的突出顯示區域。希望框架中每個對象的輪廓數量不會超過三個。

但是,我們不會使用整個框架來檢測運動中的車輛。我們將首先選擇一個區域,如果車輛進入該區域,則只會檢測到該區域。

因此,讓我向您展示我們將與之合作的區域:

# plot vehicle detection zoneplt.imshow(dilated)cv2.line(dilated, (0, 80),(256,80),(100, 0, 0))plt.show()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

水平線y = 80以下的區域是我們的車輛檢測區域。我們將僅檢測此區域中發生的任何移動。如果您想嘗試一下該概念,則可以創建自己的檢測區域。

現在,讓我們在上述幀的檢測區域中找到輪廓:

<code># find contours
contours, hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)/<code>

上面的代碼在整個圖像中找到所有輪廓,並將它們保留在變量“ 輪廓”中。由於我們只需要查找檢測區域中存在的輪廓,因此我們將對發現的輪廓進行幾次檢查。

第一個檢查是輪廓的左上角y座標是否應該> = 80(我還要再檢查x座標<= 200)。另一個檢查是輪廓區域應大於等於25。您可以在cv2.contourArea()函數的幫助下找到輪廓區域。

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()

人工智能實戰項目:使用OpenCV和Python構建自己的車輛檢測模型

僅顯示位於檢測區域內的那些車輛的輪廓。這就是我們將如何檢測所有幀中的車輛。

視頻中的車輛檢測

現在是時候在所有幀上應用相同的圖像轉換和預處理操作,並找到所需的輪廓了。重申一下,我們將按照以下步驟操作:

  1. 在每對連續的幀上應用幀差異
  2. 將圖像閾值應用於上一步的輸出圖像
  3. 對上一步的輸出圖像執行圖像放大
  4. 在上一步的輸出圖像中查找輪廓
  5. 輪廓輪廓出現在檢測區域中
  6. 保存幀以及最終輪廓

# kernel for image dilationkernel = np.ones((4,4),np.uint8) # font stylefont = cv2.FONT_HERSHEY_SIMPLEX # directory to save the ouput framespathIn = "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)

視頻準備

在這裡,我們為所有框架中的所有移動車輛添加了輪廓。現在是時候堆疊幀並創建視頻了:

<code>#指定視頻名稱
pathOut ='vehicle_detection_v3.mp4'

#每秒指定幀
fps = 14.0/<code>

接下來,我們將閱讀列表中的最後幾幀:

<code>frame_array = []
files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]/<code>

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()

祝賀您建立了自己的車輛目標檢測!


分享到:


相關文章: