10.16 計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

本教程我將分享幾個簡單步驟解釋如何使用OpenCV進行Python對象計數。

需要安裝一些軟件:

  • Python 3
  • OpennCV

1.瞭解Opencv從攝像頭獲得視頻的Python腳本

import cv2, time
#1. Create an object.Zero for external camera
video=cv2. VideoCapture(0)
#1. a variable
a=0
while True:
\ta=a+1
\t#3. Create frame object
\tcheck, frame = video.read()
\tprint(check)
\tprint(frame) # Reprsenting image
\t#6. converting to grascale
\tgray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
\t#4. shadow the frame
\tcv2.imshow("Capturing", gray)
\t#5. for press any key to out (milisecond)
\t#cv2.waitKey(0)
\t#7. for playing
\tkey=cv2.waitKey(1)
\t
\tif key==ord('q'):
\t\tbreak
\t
print (a)
#2. Shutdown the camera
video.release()
cv2.destroyAllWindows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

2.加載視頻

現在我們將開始逐步學習這個車輛計數教程。第一步是打開我們將在本教程中使用的視頻錄製。Python示例代碼如下:

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
while(cap.isOpened()):
ret, frame = cap.read() #read a frame
try:
cv2.imshow('Frame',frame)
except:
#if there are no more frames to show...
print('EOF')
break
#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

3. 在視頻窗口中繪圖

這部分非常簡單,因為我們只在視頻上顯示文字或畫線。

使用Python代碼在視頻文件中顯示文本如下:

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
w = cap.get(3) #get width
h = cap.get(4) #get height
mx = int(w/2)
my = int(h/2)
count = 0
while(cap.isOpened()):
ret, frame = cap.read() #read a frame
try:
count = count + 1
text = "Statistika UII " + str(count)
cv2.putText(frame, text ,(mx,my),cv2.FONT_HERSHEY_SIMPLEX
,1,(255,255,255),1,cv2.LINE_AA)
cv2.imshow('Frame',frame)
except:
#if there are no more frames to show...
print('EOF')
break
#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

除了顯示文字,我們還可以繪製線條,圓圈等。OpenCV有許多繪製幾何形狀的方法

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
while(cap.isOpened()):
ret, frame = cap.read() #read a frame
try:
cv2.imshow('Frame',frame)
frame2 = frame
except:
#if there are no more frames to show...
print('EOF')
break

line1 = np.array([[100,100],[300,100],[350,200]], np.int32).reshape((-1,1,2))
line2 = np.array([[400,50],[450,300]], np.int32).reshape((-1,1,2))
frame2 = cv2.polylines(frame2,[line1],False,(255,0,0),thickness=2)
frame2 = cv2.polylines(frame2,[line2],False,(0,0,255),thickness=1)

cv2.imshow('Frame 2',frame2)

#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

4.背景分離

此方法通過區分背景和對象(前景)的移動來分離對象。該方法非常廣泛地用於進入或離房間計數,交通信息系統中車輛統計,訪客數量等。

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows = True) #Create the background substractor
while(cap.isOpened()):
ret, frame = cap.read() #read a frame

fgmask = fgbg.apply(frame) #Use the substractor

try:
cv2.imshow('Frame',frame)
cv2.imshow('Background Substraction',fgmask)
except:
#if there are no more frames to show...
print('EOF')
break

#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

在圖像中,黑色的圖像為背景,而白色的圖像是檢測的對象。

5.形態轉換

圖像處理中的形態學,即數學形態學(mathematical Morphology),是圖像處理中應用最為廣泛的技術之一,主要用於從圖像中提取對錶達和描繪區域形狀有意義的圖像分量,使後續的識別工作能夠抓住目標對象最為本質〈最具區分能力-most discriminative)的形狀特徵,如邊界和連通區域等。同時像細化、像素化和修剪毛刺等技術也常應用於圖像的預處理和後處理中,成為圖像增強技術的有力補充。

經常使用的形態學操作:包括腐蝕、膨脹, 以及開、閉運算。

膨脹: 輸出像素的值是所有輸入像素值中的最大值。在二值圖像中,如果領域中有一個像素值為1,則輸出像素值為1。如下圖

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

腐蝕:輸出像素的值是所有輸入像素值中的最小值,在二值圖像中,若果領域中有一個像素值為0,則輸出像素值為0,看下圖:

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

膨脹和腐蝕的Python實現如下:

import cv2
import numpy as np
img = cv2.imread("carcount.png")
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
kernel = np.ones((3,3),np.uint8)
erosion = cv2.erode(img,kernel,iterations = 1)
dilation = cv2.dilate(img,kernel,iterations = 1)
cv2.imwrite("erode.png",erosion)
cv2.imwrite("dilate.png",dilation)
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

查看侵蝕和擴張的結果如下圖:

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

開運算:先腐蝕再膨脹,可以去掉目標外的孤立點。目標外的孤立點是和目標像素值一樣的點,而非背景像素點,即為1而非0(0表示選取的空洞或背景像素值)。使用腐蝕,背景擴展,該孤立點被腐蝕掉,但是腐蝕會導致目標區域縮小一圈,因此需要再進行膨脹操作,將目標區域擴展回原來大小。所以,要使用開運算去除目標外的孤立點。

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

閉運算:先膨脹再腐蝕,可以去掉目標內的孔。目標內的孔,屬於周圍都是值為1,內部空洞值為0.目的是去除周圍都是1的像素中間的0值。閉運算首先進行膨脹操作,目標區域擴張一圈,將目標區域的0去除,但是目標區域同時也會向外擴張一圈,因此需要使用腐蝕操作,使得圖像中的目標區域恢復到之前的大小。

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

代碼實現如下:

import cv2
import numpy as np
img = cv2.imread("carcount.png")
ret,thresh1 = cv2.threshold(img,200,255,cv2.THRESH_BINARY)
kernel = np.ones((5,5),np.uint8)
opening = cv2.morphologyEx(thresh1, cv2.MORPH_OPEN, kernel)
closing = cv2.morphologyEx(thresh1, cv2.MORPH_CLOSE, kernel)
cv2.imwrite("carcount_closing.png",closing)
cv2.imwrite("carcount_opening.png",opening)
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

6.尋找輪廓

到目前為止,我們已經過濾了視頻流文件,然後我們將檢測移動對象上的輪廓。

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows = True) #Create the background substractor
kernelOp = np.ones((3,3),np.uint8)
kernelCl = np.ones((11,11),np.uint8)
while(cap.isOpened()):
ret, frame = cap.read() #read a frame
fgmask = fgbg.apply(frame) #Use the substractor
try:
ret,imBin= cv2.threshold(fgmask,200,255,cv2.THRESH_BINARY)
#Opening (erode->dilate)
mask = cv2.morphologyEx(imBin, cv2.MORPH_OPEN, kernelOp)
#Closing (dilate -> erode)
mask = cv2.morphologyEx(mask , cv2.MORPH_CLOSE, kernelCl)
except:
#if there are no more frames to show...
print('EOF')
break
_, contours0, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
cv2.drawContours(frame, cnt, -1, (0,255,0), 3, 8)
cv2.imshow('Frame',frame)
#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

7.定義對象

這是一個非常有趣的部分,我們將輪廓分類為車輛對象。此定義以小紅點標記。Python實現如下:

import numpy as np
import cv2
cap = cv2.VideoCapture('traf.mp4') #Open video file
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows = True) #Create the background substractor
kernelOp = np.ones((3,3),np.uint8)
kernelCl = np.ones((11,11),np.uint8)
areaTH = 500
while(cap.isOpened()):
ret, frame = cap.read() #read a frame


fgmask = fgbg.apply(frame) #Use the substractor
try:
ret,imBin= cv2.threshold(fgmask,200,255,cv2.THRESH_BINARY)
#Opening (erode->dilate)
mask = cv2.morphologyEx(imBin, cv2.MORPH_OPEN, kernelOp)
#Closing (dilate -> erode)
mask = cv2.morphologyEx(mask , cv2.MORPH_CLOSE, kernelCl)
except:
#if there are no more frames to show...
print('EOF')
break
_, contours0, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
cv2.drawContours(frame, cnt, -1, (0,255,0), 3, 8)
area = cv2.contourArea(cnt)
print (area)
if area > areaTH:
#################
# TRACKING #
#################
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)
cv2.circle(frame,(cx,cy), 5, (0,0,255), -1)
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)

cv2.imshow('Frame',frame)

#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows
計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

8.移動方向

您已經知道我們的視頻上有什麼對象,現在您想知道它們往哪裡移動(如:向上/向下)。在第一幀中,您需要將檢測到的ID對象保存初始位置。然後,在下一幀中,要繼續跟蹤對象,必須將幀中對象的輪廓與首次出現時的ID匹配,並保存該對象的座標。然後,在對象跨越視頻的邊界(或一定量的限制)之後,您可以使用存儲的位置來評估它是向上或是向下移動。

import numpy as np
import cv2
import Car
import time
cap = cv2.VideoCapture('peopleCounter.avi') #Open video file
fgbg = cv2.createBackgroundSubtractorMOG2(detectShadows = True) #Create the background substractor
kernelOp = np.ones((3,3),np.uint8)
kernelCl = np.ones((11,11),np.uint8)
#Variables
font = cv2.FONT_HERSHEY_SIMPLEX
cars = []
max_p_age = 5
pid = 1
areaTH = 500
while(cap.isOpened()):
ret, frame = cap.read() #read a frame

fgmask = fgbg.apply(frame) #Use the substractor
try:
ret,imBin= cv2.threshold(fgmask,200,255,cv2.THRESH_BINARY)
#Opening (erode->dilate)
mask = cv2.morphologyEx(imBin, cv2.MORPH_OPEN, kernelOp)
#Closing (dilate -> erode)
mask = cv2.morphologyEx(mask , cv2.MORPH_CLOSE, kernelCl)
except:
#if there are no more frames to show...
print('EOF')
break
_, contours0, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE)
for cnt in contours0:
cv2.drawContours(frame, cnt, -1, (0,255,0), 3, 8)
area = cv2.contourArea(cnt)
if area > areaTH:
#################
# TRACKING #
#################
M = cv2.moments(cnt)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
x,y,w,h = cv2.boundingRect(cnt)

new = True
for i in cars:
if abs(x-i.getX()) <= w and abs(y-i.getY()) <= h:
# the object is close to one that was already detected before
new = False
i.updateCoords(cx,cy) #Update coordinates on the object and resets age
break
if new == True:

p = Car.MyCar(pid,cx,cy, max_p_age)
cars.append(p)
pid += 1
cv2.circle(frame,(cx,cy), 5, (0,0,255), -1)
img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
cv2.drawContours(frame, cnt, -1, (0,255,0), 3)
for i in cars:
if len(i.getTracks()) >= 2:
pts = np.array(i.getTracks(), np.int32)
pts = pts.reshape((-1,1,2))
frame = cv2.polylines(frame,[pts],False,i.getRGB())
if i.getId() == 9:
print (str(i.getX()), ',', str(i.getY()))
cv2.putText(frame, str(i.getId()),(i.getX(),i.getY()),font,0.3,i.getRGB(),1,cv2.LINE_AA)


cv2.imshow('Frame',frame)

#Abort and exit with 'Q' or ESC
k = cv2.waitKey(30) & 0xff
if k == 27:
break
cap.release() #release video file
cv2.destroyAllWindows() #close all openCV windows

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟

9.計數

你之前的部分已經知道如何檢測對象運動的方法。現在,我們必須看到這個列表並確定對象是否在我們的視頻中向上或下降。要做到這一點,首先將創造兩條線,這將顯示什麼時候來評估對象的方向(line_up,line_down)。而且還會有兩行界限,告訴我們什麼時候停止跟蹤物體(up_limit,down_limit)。

計算機視覺:利用OpenCV和Python進行車輛計數詳細步驟


分享到:


相關文章: