作者|PRATEEK JOSHI
編譯|Flin
來源|analyticsvidhya
概述
-
你對智慧城市的想法感到興奮嗎?如果是的話,你會喜歡這個關于建立你自己的車輛檢測系統的教程的
-
在深入實作部分之前,我們將首先了解如何檢測視頻中的移動目標
-
我們將使用OpenCV和Python構建自動車輛檢測器
介紹
我喜歡智慧城市的理念,自動智能能源系統、電網、一鍵接入埠的想法等等,這是一個令人著迷的概念!老實說,這是一個資料科學家的夢想,我很高興世界上很多城市都在朝著更智能的方向發展,
智能城市的核心組成部分之一是自動交通管理,這不禁讓我思考——我能用我的資料科學知識來建立一個車輛檢測模型,在智能交通管理中發揮作用嗎?
想想看,如果你能在紅綠燈攝像頭中集成車輛檢測系統,你可以輕松地同時跟蹤許多有用的東西:
- 白天交通路口有多少輛車?
- 什么時候交通堵塞?
- 什么樣的車輛(重型車輛、汽車等)正在通過交叉路口?
- 有沒有辦法優化交通,并通過不同的街道進行分配?
還有很多例子就不一一列舉,應用程式是無止境的!
我們人類可以很容易地在一瞬間從復雜的場景中檢測和識別出物體,然而,將這種思維程序轉化為機器的思維,需要我們學習使用計算機視覺演算法進行目標檢測,
因此在本文中,我們將建立一個自動車輛檢測器和計數器模型,以下視頻是你可以期待的體驗:
https://youtu.be/C_iZ2yivskE
注意:還不懂深度學習和計算機視覺的新概念?以下是兩門熱門課程,可開啟你的深度學習之旅:
- 深度學習基礎(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圖演示了這個想法:

在目標檢測中,我們可以執行許多子任務,例如計算目標數量、查找目標的相對大小或查找目標之間的相對距離,這些子任務都很重要,因為它們有助于解決一些最棘手的現實問題,
如果你希望從頭開始學習目標檢測,我建議你使用以下教程:
-
逐步介紹基本的目標檢測演算法(https://www.analyticsvidhya.com/blog/2018/10/a-step-by-step-introduction-to-the-basic-object-detection-algorithms-part-1/?utm_source=blog&utm_medium=vehicle-detection-opencv-python)
-
利用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/tag/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/
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/194809.html
標籤:其他
