日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

【opencv】(13) 案例:停车场空余车位检测,附python完整代码

發(fā)布時(shí)間:2023/11/27 生活经验 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【opencv】(13) 案例:停车场空余车位检测,附python完整代码 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

各位同學(xué)好,今天和大家分享一下如何使用Opencv完成停車場的車位檢測,及空余車位計(jì)數(shù),先放張圖看效果。

紅框代表該車位有車,綠框代表該車位空余,左上角記錄有幾個(gè)空余車位,黃色數(shù)字代表該車位內(nèi)的像素個(gè)數(shù),用于判斷車位上是否有車。

? ?

從圖中可以看到,由于視頻拍攝角度的問題,車位不是橫平豎直的,并且車位在屏幕上的大小和角度也是不相同的。需要用到旋轉(zhuǎn)矩形的操作,并調(diào)整單個(gè)矩形框使其能夠用于所有車位。


1. 處理旋轉(zhuǎn)矩形

首先,由于車位是矩形框經(jīng)過一定角度旋轉(zhuǎn)之后得到的,因此在先定義一個(gè)處理旋轉(zhuǎn)矩形的函數(shù),把它其他py文件放在同路徑的目錄內(nèi),這里命名為rotaParking.py

假設(shè)對圖片上任意點(diǎn)(x,y),繞一個(gè)坐標(biāo)點(diǎn)(rx0,ry0)順時(shí)針旋轉(zhuǎn)a角度后的新的坐標(biāo)設(shè)為(x0, y0),有公式:

x0 = (x - rx0) *?cos(a) - (y - ry0) * sin(a) + rx0?

y0 = (x - rx0) * sin(a) + (y - ry0) * cos(a) + ry0?

根據(jù)此公式,創(chuàng)建函數(shù)recRota完成旋轉(zhuǎn)矩形操作,后續(xù)在車位處理的py文件中直接調(diào)用它。返回值是img繪制旋轉(zhuǎn)矩形圖之后的圖像,以及angle是旋轉(zhuǎn)后的矩形的四個(gè)角的坐標(biāo)構(gòu)成的列表

# 矩形框順時(shí)針旋轉(zhuǎn)
import cv2
import math# 傳入旋轉(zhuǎn)的參考點(diǎn)坐標(biāo),矩形框左上角坐標(biāo)(x,y),框的寬w和高h(yuǎn),旋轉(zhuǎn)角度a
def angleRota(center_x, center_y, x, y, w, h, a):# 角度轉(zhuǎn)弧度a = (math.pi/180)*a# 旋轉(zhuǎn)前左上角坐標(biāo)x1, y1 = x, y# 右上角坐標(biāo)x2, y2 = x+w, y# 右下角坐標(biāo)x3, y3 = x+w, y+h# 左下角坐標(biāo)x4, y4 = x, y+h# 旋轉(zhuǎn)后的左上角坐標(biāo),像素坐標(biāo)是整數(shù)px1 = int((x1 - center_x) * math.cos(a) - (y1 - center_y) * math.sin(a) + center_x)  py1 = int((x1 - center_x) * math.sin(a) + (y1 - center_y) * math.cos(a) + center_y)# 右上角坐標(biāo)px2 = int((x2 - center_x) * math.cos(a) - (y2 - center_y) * math.sin(a) + center_x)py2 = int((x2 - center_x) * math.sin(a) + (y2 - center_y) * math.cos(a) + center_y)# 右下角坐標(biāo)px3 = int((x3 - center_x) * math.cos(a) - (y3 - center_y) * math.sin(a) + center_x)  py3 = int((x3 - center_x) * math.sin(a) + (y3 - center_y) * math.cos(a) + center_y)# 左下角坐標(biāo)px4 = int((x4 - center_x) * math.cos(a) - (y4 - center_y) * math.sin(a) + center_x)  py4 = int((x4 - center_x) * math.sin(a) + (y4 - center_y) * math.cos(a) + center_y)# 保存每一個(gè)角的坐標(biāo)pt1 = (px1, py1)pt2 = (px2, py2)pt3 = (px3, py3)pt4 = (px4, py4)# 存儲每個(gè)角的坐標(biāo)angle = [pt1, pt2, pt3, pt4]# 返回調(diào)整后的坐標(biāo)return angle# 繪制旋轉(zhuǎn)后的矩形框
def drawLine(img, angle, color, thickness):# 分別繪制四條邊cv2.line(img, angle[0], angle[1], color, thickness)cv2.line(img, angle[1], angle[2], color, thickness)cv2.line(img, angle[2], angle[3], color, thickness)cv2.line(img, angle[3], angle[0], color, thickness)# 返回繪制好旋轉(zhuǎn)矩形的圖像return img# 矩形旋轉(zhuǎn)
def recRota(img, center_x, center_y, x1, y1, w, h, rota, draw=True):'''img: 原圖像(center_X, center_y): 旋轉(zhuǎn)參考點(diǎn)的坐標(biāo)(x1, y1): 矩形框左上角坐標(biāo)w: 矩形框的寬h: 矩形框的高rota: 順時(shí)針的旋轉(zhuǎn)角度,如:30°'''color = (255,255,0)  # 繪制停車線的線條顏色thickness = 2  # 停車線線條寬度#(1)計(jì)算旋轉(zhuǎn)一定角度后的四個(gè)角的坐標(biāo)angle = angleRota(x1, y1, x1, y1, w, h, rota)#(2)繪制旋轉(zhuǎn)后的矩形if draw == True:img = drawLine(img, angle, color, thickness)# 返回繪制后的圖像,以及矩形框的四個(gè)角的坐標(biāo)return img, angleelse:return angle

2. 處理單幀圖像,劃分車位

這里用到鼠標(biāo)響應(yīng) cv2.setMouseCallback() 可以在圖像上用鼠標(biāo)操作,觸發(fā)一些事件。

鼠標(biāo)響應(yīng): setMousecallback(winname, onMouse, userdata=0)

參數(shù):

winname: 窗口的名字

onMouse: 鼠標(biāo)響應(yīng)函數(shù),回調(diào)函數(shù)。指定窗口里每次鼠標(biāo)時(shí)間發(fā)生的時(shí)候,被調(diào)用的函數(shù)指針。

userdate:傳給回調(diào)函數(shù)的參數(shù)?

回調(diào)函數(shù):?onMouse(int event, x,?y,? flags,?param)

event:CV_EVENT_*?變量之一

x和y: 鼠標(biāo)指針在圖像坐標(biāo)系的坐標(biāo)(像素坐標(biāo))

flags:CV_EVENT_FLAG的組合

param: 是用戶定義的傳遞到setMouseCallback函數(shù)調(diào)用的參數(shù)

常用事件event變量:

cv2_EVENT_MOUSEMOVE 0    # 滑動 
cv2_EVENT_LBUTTONDOWN 1  # 左鍵點(diǎn)擊 
cv2_EVENT_RBUTTONDOWN 2  # 右鍵點(diǎn)擊 
cv2_EVENT_MBUTTONDOWN 3  # 中間點(diǎn)擊 
cv2_EVENT_LBUTTONUP 4    # 左鍵釋放 
cv2_EVENT_RBUTTONUP 5    # 右鍵釋放 
cv2_EVENT_MBUTTONUP 6    # 中間釋放 
cv2_EVENT_LBUTTONDBLCLK 7   # 左鍵雙擊 
cv2_EVENT_RBUTTONDBLCLK 8   # 右鍵雙擊 
cv2_EVENT_MBUTTONDBLCLK 9   # 中間釋放
cv2_EVENT_FLAG_LBUTTON 1    # 左鍵拖拽  
cv2_EVENT_FLAG_RBUTTON 2    # 右鍵拖拽  
cv2_EVENT_FLAG_MBUTTON 4    # 中間拖拽 
。。。。。。。。。。。。。。。。。。。

在本案例中,如果鼠標(biāo)左鍵單機(jī)圖像,那么就以鼠標(biāo)所在位置坐標(biāo)作為矩形框的左上角坐標(biāo),每點(diǎn)一個(gè)就生成一個(gè)矩形框,將坐標(biāo)保存在 posList 中。如果畫錯了,那么就右鍵點(diǎn)擊需要刪除的矩形框,如果鼠標(biāo)位置在遍歷后的某個(gè)矩形框內(nèi)部,那么就在posList中刪除該矩形框的左上角坐標(biāo),并在下一幀圖上不顯示該矩形框

將每一次點(diǎn)擊后更新好了的posList坐標(biāo)信息保存在txt文件中,這樣在下一次打開文件時(shí)就不需要重復(fù)標(biāo)定矩形框。在讀取坐標(biāo)信息時(shí)使用tryexcept方法,如果這是第一次標(biāo)定,沒有生成過txt文件,那么try方法拋出異常,執(zhí)行except的方法

在這一幀中標(biāo)定的坐標(biāo),會在在下一幀中繪制,遍歷poList,以pos鼠標(biāo)所在坐標(biāo)為旋轉(zhuǎn)參考點(diǎn)坐標(biāo),繪制旋轉(zhuǎn)矩形框。

import cv2
import pickle  # 將對象以文件的形式存放在磁盤上
from rotaParking import recRota  # 導(dǎo)入自定義的旋轉(zhuǎn)矩形框函數(shù)#(1)讀入圖片
filepath = 'C:\\GameDownload\\Deep Learning\\parking_car.jpg'
filename = 'parking_position.txt'  # 保存的車位坐標(biāo)# 只需要確定一個(gè)停車位的大小,就可以將這個(gè)矩形框用于所有車位
w, h = 90, 160  # 矩形框的寬和高# 運(yùn)行時(shí)讀取保存的車位坐標(biāo),保留前一次畫好了的車位線
try:with open(filename, 'rb') as file_object:posList = pickle.load(file_object)# 第一次運(yùn)行時(shí)沒有寫過文件,那就執(zhí)行下面的,生成一個(gè)列表保存坐標(biāo)
except:# 創(chuàng)建一個(gè)列表接收觸發(fā)鼠標(biāo)事件后的坐標(biāo)信息posList = []#(2)創(chuàng)建一個(gè)回調(diào)函數(shù),當(dāng)鼠標(biāo)事件觸發(fā)時(shí),該函數(shù)執(zhí)行
# cv2.setMouseCallback的參數(shù),在圖像上點(diǎn)擊鼠標(biāo)會發(fā)生什么
def onMouse(events, x, y, flag, params):# 如果在圖像上點(diǎn)擊鼠標(biāo)左鍵,那么就將鼠標(biāo)位置的(x,y)坐標(biāo)保存起來if events == cv2.EVENT_LBUTTONDOWN:# 接收鼠標(biāo)所在位置為xy坐標(biāo)posList.append((x,y))# 如果右鍵點(diǎn)擊就將這個(gè)坐標(biāo)從posList中刪除if events == cv2.EVENT_RBUTTONDOWN:# 如果當(dāng)前的坐標(biāo)點(diǎn)在某一個(gè)檢測框中就刪除這個(gè)檢測框for index, pos in enumerate(posList):# x和y代表鼠標(biāo)當(dāng)前所在位置if pos[0]<x<pos[0]+w and pos[1]<y<pos[1]+h:# 將這個(gè)pos坐標(biāo)移除posList.pop(index)#(3)確認(rèn)車位線后,把車位線坐標(biāo)保存下來,保存在一個(gè)文本中with open(filename, 'wb') as file_object: # 將列表轉(zhuǎn)換字符串寫入pickle.dump(posList, file_object)#(4)繪制停車線矩形框
while True:# 像視頻一樣不斷播放這一幀img = cv2.imread(filepath)# 遍歷鼠標(biāo)點(diǎn)擊的所有坐標(biāo),該坐標(biāo)就是矩形框的左上角xy坐標(biāo)for pos in posList:# 繪制旋轉(zhuǎn)后的矩形,傳入原圖,旋轉(zhuǎn)參考點(diǎn)坐標(biāo),矩形框左上角坐標(biāo),框的寬w和高h(yuǎn),逆時(shí)針轉(zhuǎn)4°img, angle = recRota(img, pos[0], pos[1], pos[0], pos[1], w, h, -4)    # 顯示圖像cv2.imshow('img', img)# 鼠標(biāo)點(diǎn)擊圖像,參數(shù):窗口名必須和上面的名稱相同;傳入函數(shù),如果點(diǎn)擊鼠標(biāo)會發(fā)生什么cv2.setMouseCallback('img', onMouse)# '0'圖像不會自動消失key = cv2.waitKey(0)  # 按任意鍵關(guān)閉圖像窗口cv2.destroyAllWindows()

繪制后的單幀圖像如下


3. 處理視頻,分割出所有車位

在對單幀圖像處理時(shí),我們已經(jīng)將所有的車位分割出來,并記錄下左上角坐標(biāo)。接下來對視頻圖像處理時(shí)只需直接導(dǎo)入左上角坐標(biāo)點(diǎn)的txt文件

從上圖可以看到,每個(gè)車位框是傾斜的,如果要分割出每個(gè)車位,必須使用切片方法,但切片出來的圖像是橫平豎直的。因此針對每一個(gè)車位框,都以該框的左上角為旋轉(zhuǎn)參考,旋轉(zhuǎn)整張幀圖像,將車位框擺正之后再切片

圖像旋轉(zhuǎn)方法:

獲得旋轉(zhuǎn)變化矩陣: M = cv2.getRotationMatrix2D(center, angle, scale)

center: 圖像旋轉(zhuǎn)的參考點(diǎn)坐標(biāo)

angle: 旋轉(zhuǎn)角度(°),正數(shù)代表逆時(shí)針,負(fù)數(shù)代表順時(shí)針

scale: 旋轉(zhuǎn)后的圖像是原來縮放后的多少倍

M: 計(jì)算得到的旋轉(zhuǎn)矩陣

旋轉(zhuǎn)變化: dst =?cv2.warpAffine(src, M, dsize, flags, borderMode, borderValue)

src: 需要變化的圖像

M:?旋轉(zhuǎn)變換矩陣

dsize: 輸出圖像的大小

flags: 插值方法的組合(int 類型)

borderMode: 邊界像素模式(int 類型)

borderValue: 邊界填充值,默認(rèn)情況下,它為0,也就是邊界填充默認(rèn)是黑色。

flags 插值方式如下:

cv2.INTER_LINEAR	# 線性插值(默認(rèn))
cv2.INTER_NEAREST	# 最近鄰插值
cv2.INTER_AREA	    # 區(qū)域插值
cv2.INTER_CUBIC	    # 三次樣條插值
cv2.INTER_LANCZOS4	# Lanczos插值

將每個(gè)檢測框擺正之后就可以使用切片方法 rota_img[pos[1]:pos[1]+h, pos[0]:pos[0]+w],橫平豎直地分割出每個(gè)車位。pos[1]中存放y坐標(biāo),pos[0]中存放x坐標(biāo)。切片時(shí)先指定高再指定寬。?

為了避免切割出來的每個(gè)車位有繪圖的痕跡,因此在繪圖之前將原圖像復(fù)制一份imgCopy = img.copy(),在復(fù)制的圖像上繪制矩形框,這樣就不會在分割后的車位圖像上出現(xiàn)繪圖痕跡。

處理視頻的代碼如下:

# 處理視頻圖像
import cv2
import pickle
from rotaParking import recRota  # 導(dǎo)入自定義的旋轉(zhuǎn)矩形框函數(shù)
from rotaParking import drawLine  # 導(dǎo)入繪制旋轉(zhuǎn)矩形線條函數(shù)#(1)讀取視頻
filepath = 'C:\\GameDownload\\Deep Learning\\parking.mp4'
cap = cv2.VideoCapture(filepath) #(2)導(dǎo)入先前記錄下來的車位矩形框的左上角坐標(biāo)
filename = 'parking_position.txt'  # 保存的車位坐標(biāo)
with open(filename, 'rb') as f:posList = pickle.load(f)#(3)處理每一幀圖像
while True:# 返回圖像是否讀取成功,以及讀取的幀圖像imgsuccess, img = cap.read()# 為了使裁剪后的單個(gè)車位里面沒有繪制的邊框,需要在畫車位框之前,把原圖像復(fù)制一份imgCopy = img.copy()# 獲得整每幀圖片的寬和高img_w, img_h = img.shape[:2]  #shape是(w,h,c)# 由于這個(gè)視頻比較短,就循環(huán)播放這個(gè)視頻if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):# 如果當(dāng)前幀==總幀數(shù),那就重置當(dāng)前幀為0cap.set(cv2.CAP_PROP_POS_FRAMES, 0)#(4)繪制停車線矩形框w, h = 90, 160  # 矩形框的寬和高# 遍歷所有的矩形框坐標(biāo)for pos in posList:# 得到旋轉(zhuǎn)后的矩形的四個(gè)角坐標(biāo),傳入原圖,旋轉(zhuǎn)參考點(diǎn)坐標(biāo),矩形框左上角坐標(biāo),框的寬w和高h(yuǎn),逆時(shí)針轉(zhuǎn)4°angle = recRota(img, pos[0], pos[1], pos[0], pos[1], w, h, -4, draw=False) # 裁剪的車位不繪制車位圖  #(5)裁剪所有的車位框,由于我們的矩形是傾斜的,先要把矩形轉(zhuǎn)正之后再裁剪# 變換矩陣,以每個(gè)矩形框的左上坐標(biāo)為參考點(diǎn),順時(shí)針尋轉(zhuǎn)4°,旋轉(zhuǎn)后的圖像大小不變r(jià)ota_params = cv2.getRotationMatrix2D(angle[0], angle=-4, scale=1) # 旋轉(zhuǎn)整張幀圖片,輸入img圖像,變換矩陣,指定輸出圖像大小rota_img = cv2.warpAffine(img, rota_params, (img_w, img_h))# 裁剪擺正了的矩形框,先指定高h(yuǎn),再指定寬wimgCrop = rota_img[pos[1]:pos[1]+h, pos[0]:pos[0]+w]# 顯示裁剪出的圖像cv2.imshow(f'imgCrop:{pos[0],pos[1]}', imgCrop)#(6)繪制所有車位的矩形框# 在復(fù)制后的圖像上繪制車位框imgCopy = drawLine(imgCopy, angle, (255,255,0), 3)#(7)顯示圖像,輸入窗口名及圖像數(shù)據(jù)cv2.imshow('img', imgCopy)    if cv2.waitKey(10) & 0xFF==27:  #每幀滯留20毫秒后消失,ESC鍵退出break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

分割出每一個(gè)車位的圖像


4. 檢測車位上是否有車

檢測思路是:如果車位上沒有車,那么二值圖中白點(diǎn)很少,如果有車,車身的白點(diǎn)很多,因此通過計(jì)算每個(gè)車位框內(nèi)的像素個(gè)數(shù)來確定該車位內(nèi)是否有車

(1)先將讀入的圖像變成灰度圖cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

(2)對灰度圖濾波操作,消除噪聲,采用高斯濾波cv2.GaussianBlur(img, ksize, 標(biāo)準(zhǔn)差x, 標(biāo)準(zhǔn)差y)ksize卷積核大小,滑窗寬度高度為奇數(shù);標(biāo)準(zhǔn)差x代表沿x方向的卷積核的標(biāo)準(zhǔn)差;標(biāo)準(zhǔn)差y代表沿y方向的卷積核的標(biāo)準(zhǔn)差,不設(shè)置的話則和x軸的標(biāo)準(zhǔn)差一致。

(3)對濾波后的灰度圖轉(zhuǎn)換為二值圖,采用自適應(yīng)閾值方法:

cv2.adaptiveThreshold(src, maxValue, adaptiveMethod, thresholdType, blockSize, C)

src:?灰度化的圖片

maxValue:?當(dāng)圖像像素超過了閾值或低于閾值(由type決定),所賦予的值

adaptiveMethod:?自適應(yīng)方法。有2種,

ADAPTIVE_THRESH_MEAN_C: 為局部鄰域塊的平均值,該算法是先求出塊中的均值。

ADAPTIVE_THRESH_GAUSSIAN_C: 為局部鄰域塊的高斯加權(quán)和。該算法是在區(qū)域中(x, y)周圍的像素根據(jù)高斯函數(shù)按照他們離中心點(diǎn)的距離進(jìn)行加權(quán)計(jì)算。

thresholdType: 二值化方法,有兩種

cv2.THRESH_BINARY: 二值法,超過閾值thresh部分取maxval(設(shè)定的最大值),否則取0

cv2.THRESH_BINARY_INV: 超過閾值的部分取0,小于閾值取maxval

blockSize: 分割計(jì)算的區(qū)域大小,取奇數(shù)

C: 常數(shù),每個(gè)區(qū)域計(jì)算出的閾值的基礎(chǔ)上在減去這個(gè)常數(shù)作為這個(gè)區(qū)域的最終閾值,可以為負(fù)數(shù)

(4)消除上的零散白點(diǎn),對二值化之后的圖像使用中值濾波cv2.medianBlur(img, ksize)

,ksize代表濾波模板的尺寸大小,填一個(gè)數(shù)值,必須是大于1的奇數(shù)

(5)由于車位框內(nèi)有車的話白點(diǎn)密集,沒車的話車位內(nèi)一片黑,因此擴(kuò)充白點(diǎn)數(shù)目,為了增大區(qū)別。使用膨脹方法cv2.dilate(img, kernel, iterations),kernel為卷積核大小,iterations為迭代次數(shù)。

下圖中,第一張是二值化之后的圖像,第二張是中值濾波后的,第三張是膨脹操作后的

(6)計(jì)算每個(gè)分割出來的車位框中的白點(diǎn)個(gè)數(shù),countNonZero(),返回灰度值不為0的像素?cái)?shù)量。經(jīng)過分析,如果白點(diǎn)數(shù)量大于3000,那么就表明車位上有車。

空余車位檢測的代碼如下:

# 處理視頻圖像
import cv2
import pickle
import numpy as np
from rotaParking import recRota  # 導(dǎo)入自定義的旋轉(zhuǎn)矩形框函數(shù)
from rotaParking import drawLine  # 導(dǎo)入繪制旋轉(zhuǎn)矩形線條函數(shù)#(1)讀取視頻
filepath = 'C:\\GameDownload\\Deep Learning\\parking.mp4'
cap = cv2.VideoCapture(filepath) # 初始的車位框顏色
color = (255,255,0)#(2)導(dǎo)入先前記錄下來的車位矩形框的左上角坐標(biāo)
filename = 'parking_position.txt'  # 保存的車位坐標(biāo)
with open(filename, 'rb') as f:posList = pickle.load(f)#(3)處理每一幀圖像
while True:# 記錄有幾個(gè)空車位spacePark = 0# 返回圖像是否讀取成功,以及讀取的幀圖像imgsuccess, img = cap.read()# 為了使裁剪后的單個(gè)車位里面沒有繪制的邊框,需要在畫車位框之前,把原圖像復(fù)制一份imgCopy = img.copy()# 獲得整每幀圖片的寬和高img_w, img_h = img.shape[:2]  #shape是(w,h,c)# ==1== 轉(zhuǎn)換灰度圖,通過形態(tài)學(xué)處理來檢測車位內(nèi)有沒有車imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# ==2== 高斯濾波,卷積核3*3,沿x和y方向的卷積核的標(biāo)準(zhǔn)差為1imgGray = cv2.GaussianBlur(imgGray, (3,3), 1)# ==3== 二值圖,自適應(yīng)閾值方法imgThresh = cv2.adaptiveThreshold(imgGray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 101, 20)# ==4== 刪除零散的白點(diǎn),# 如果車位上有車,那么車位上的像素?cái)?shù)量(白點(diǎn))很多,如果沒有車,車位框內(nèi)基本沒什么白點(diǎn)imgMedian = cv2.medianBlur(imgThresh, 5)  # ==5== 擴(kuò)張白色部分,膨脹kernel = np.ones((3,3), np.uint8)  # 設(shè)置卷積核imgDilate = cv2.dilate(imgMedian, kernel, iterations=1) # 迭代次數(shù)為1# 由于這個(gè)視頻比較短,就循環(huán)播放這個(gè)視頻if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):# 如果當(dāng)前幀==總幀數(shù),那就重置當(dāng)前幀為0cap.set(cv2.CAP_PROP_POS_FRAMES, 0)#(4)繪制停車線矩形框w, h = 90, 160  # 矩形框的寬和高# 遍歷所有的矩形框坐標(biāo)for pos in posList:# 得到旋轉(zhuǎn)后的矩形的四個(gè)角坐標(biāo),傳入原圖,旋轉(zhuǎn)參考點(diǎn)坐標(biāo),矩形框左上角坐標(biāo),框的寬w和高h(yuǎn),逆時(shí)針轉(zhuǎn)4°angle = recRota(imgDilate, pos[0], pos[1], pos[0], pos[1], w, h, -4, draw=False) # 裁剪的車位不繪制車位圖  #(5)裁剪所有的車位框,由于我們的矩形是傾斜的,先要把矩形轉(zhuǎn)正之后再裁剪# 變換矩陣,以每個(gè)矩形框的左上坐標(biāo)為參考點(diǎn),順時(shí)針尋轉(zhuǎn)4°,旋轉(zhuǎn)后的圖像大小不變r(jià)ota_params = cv2.getRotationMatrix2D(angle[0], angle=-4, scale=1) # 旋轉(zhuǎn)整張幀圖片,輸入img圖像,變換矩陣,指定輸出圖像大小rota_img = cv2.warpAffine(imgDilate, rota_params, (img_w, img_h))# 裁剪擺正了的矩形框,先指定高h(yuǎn),再指定寬wimgCrop = rota_img[pos[1]:pos[1]+h, pos[0]:pos[0]+w]# 顯示裁剪出的圖像cv2.imshow('imgCrop', imgCrop)#(6)計(jì)算每個(gè)裁剪出的單個(gè)車位有多少個(gè)像素點(diǎn)count = cv2.countNonZero(imgCrop)# 將計(jì)數(shù)顯示在矩形框上cv2.putText(imgCopy, str(count), (pos[0]+5, pos[1]+20), cv2.FONT_HERSHEY_COMPLEX, 0.8, (0,255,255), 2)#(7)確定車位上是否有車if count < 3000:  # 像素?cái)?shù)量小于2500輛就是沒有車color = (0,255,0)  # 沒有車的話車位線就是綠色spacePark += 1  # 每檢測到一個(gè)空車位,數(shù)量就加一 else:color = (0,0,255)  # 有車時(shí)車位線就是紅色#(8)繪制所有車位的矩形框# 在復(fù)制后的圖像上繪制車位框imgCopy = drawLine(imgCopy, angle, color, 3)# 繪制目前還剩余幾個(gè)空車位cv2.rectangle(imgCopy, (0,150), (200,210), (255,255,0), cv2.FILLED)cv2.rectangle(imgCopy, (5,155), (195,205), (255,255,255), 3)cv2.putText(imgCopy, 'FREE: '+str(spacePark), (31,191), cv2.FONT_HERSHEY_COMPLEX, 1, (255,0,255), 3)#(9)顯示圖像,輸入窗口名及圖像數(shù)據(jù)cv2.imshow('img', imgCopy) # 原圖cv2.imshow('imgGray', imgGray) # 高斯濾波后cv2.imshow('imgThresh', imgThresh)  # 二值化后cv2.imshow('imgMedian', imgMedian)  # 模糊后cv2.imshow('imgDilate', imgDilate)  # 膨脹if cv2.waitKey(1) & 0xFF==27:  #每幀滯留20毫秒后消失,ESC鍵退出break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()

最終檢測效果圖如下:

總結(jié)

以上是生活随笔為你收集整理的【opencv】(13) 案例:停车场空余车位检测,附python完整代码的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。