Python中使用Opencv開(kāi)發(fā)停車(chē)位計(jì)數(shù)器功能
在這個(gè)項(xiàng)目中,我們將創(chuàng)建一個(gè)停車(chē)位計(jì)數(shù)器。我們會(huì)發(fā)現(xiàn)總共有多少輛車(chē),以及有多少停車(chē)位是空的。關(guān)于本教程最好的一點(diǎn)是,我們將使用基本的圖像處理技術(shù)來(lái)解決這個(gè)問(wèn)題,沒(méi)有使用機(jī)器學(xué)習(xí)、深度學(xué)習(xí)進(jìn)行訓(xùn)練來(lái)識(shí)別。
1. 環(huán)境安裝
1.1 安裝并激活虛擬環(huán)境
python -m venv venv
cd venv\Scripts .\activate.bat
1.2 python包安裝
pip install opencv-python
2. 繪制停車(chē)位矩形框
2.1 導(dǎo)入停車(chē)場(chǎng)圖片
import cv2 import pickle img=cv2.imread('carParkImg.png') cv2.imshow("image",img)
2.2 繪制矩形框 定位停車(chē)位
import cv2 import pickle img=cv2.imread('carParkImg.png') cv2.rectangle(img,(50,192),(157,240),(255,0,255),2) #坐標(biāo)位置可以多次嘗試確定 cv2.imshow("image",img) cv2.waitKey(0)
可以看出,每個(gè)停車(chē)位的估計(jì)寬、高為:
width=107 # 157-102 height = 48 # 240 - 192
2.3 鼠標(biāo)添加、刪除停車(chē)位
import cv2 import pickle img=cv2.imread('carParkImg.png') width,height = 107,48 posList = [] # 鼠標(biāo)點(diǎn)擊的坐標(biāo)集合 def mouseClick(events,x,y,flags,params): if events == cv2.EVENT_LBUTTONDOWN: posList.append((x,y)) while True: img = cv2.imread("carParkImg.png") cv2.imshow("images",img) for pos in posList: cv2.rectangle(img,pos,(pos[0]+width,pos[1]+height),(255,0,255),2) #坐標(biāo)位置可以多次嘗試確定 cv2.imshow("image",img) cv2.setMouseCallback("images",mouseClick) if cv2.waitKey(10) & 0xFF== ord('q'): break
通過(guò)鼠標(biāo)點(diǎn)擊在任何位置添加矩形框,但當(dāng)矩形框位置出錯(cuò)時(shí),無(wú)法進(jìn)行刪除。因此通過(guò)添加鼠標(biāo)右鍵的事件,刪除錯(cuò)誤的矩形框。
def mouseClick(events,x,y,flags,params): if events == cv2.EVENT_LBUTTONDOWN: posList.append((x,y)) if events == cv2.EVENT_RBUTTONDOWN: for i,pos in enumerate(posList): x1,y1=pos if x1 < x < x1 +width and y1 < y <y1 +height: posList.pop(i)
通過(guò)pickle.dump()保持保存鼠標(biāo)點(diǎn)擊的位置信息。
with open('CarParkPos','wb') as f: pickle.dump(posList,f)
通過(guò)pickle.load()加載保存好的位置信息,即在原有的停車(chē)位添加或刪除停車(chē)位,而不是每一幀畫(huà)面重新繪制。
with open('CarParkPos','wb') as f: posList = pickle.load(f)
完整代碼如下:
import cv2 import pickle img=cv2.imread('carParkImg.png') width,height = 107,48 try: with open('CarParkPos','rb') as f: posList = pickle.load(f) except: posList = [] # posList = [] # 鼠標(biāo)點(diǎn)擊的坐標(biāo)集合 def mouseClick(events,x,y,flags,params): if events == cv2.EVENT_LBUTTONDOWN: posList.append((x,y)) if events == cv2.EVENT_RBUTTONDOWN: for i,pos in enumerate(posList): x1,y1=pos if x1 < x < x1 +width and y1 < y <y1 +height: posList.pop(i) with open('CarParkPos','wb') as f: pickle.dump(posList,f) while True: img = cv2.imread("carParkImg.png") for pos in posList: cv2.rectangle(img,pos,(pos[0]+width,pos[1]+height),(255,0,255),2) #坐標(biāo)位置可以多次嘗試確定 cv2.imshow("image",img) cv2.setMouseCallback("image",mouseClick) if cv2.waitKey(10) & 0xFF== ord('q'): break
3. 停車(chē)位視頻分析
3. 1 停車(chē)監(jiān)控視頻
import cv2 import pickle import cvzone import numpy as np # Video feed cap = cv2.VideoCapture('carPark.mp4') while True: success,img= cap.read() cv2.imshow("Image",img) if cv2.waitKey(10) & 0xFF== ord('q'): break
視頻時(shí)間比較短,為了讓視頻循環(huán)播放,添加如下代碼:
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT): cap.set(cv2.CAP_PROP_POS_FRAMES,0)
- cv2.CAP_PROP_POS_FRAMES :視頻播放當(dāng)前幀
- cv2.CAP_PROP_FRAME_COUNT :視頻總幀數(shù)
即:當(dāng)前視頻播放到結(jié)尾時(shí),重新播放
3. 2 截取停車(chē)位
截取停車(chē)位,回來(lái)對(duì)每個(gè)停車(chē)位進(jìn)行圖像處理,從而分析該停車(chē)位是否被占用
def checkParkingSpace(): for pos in posList: x,y = pos imgCrop=img[y:y+height,x:x+width] cv2.imshow(str(x*y),imgCrop)
3. 3 圖像處理
對(duì)圖像二值化、高斯模糊處理
imgGray =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) imgBlur =cv2.GaussianBlur(imgGray,(3,3),1)
利用自適應(yīng)二值化對(duì)圖像進(jìn)行處理
imgThreshold=cv2.adaptiveThreshold(imgBlur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,25,16)
cv2.adaptiveThreshold 參數(shù)的選擇可以通過(guò)TrackBar拖到滾動(dòng)條,直到選擇合適的數(shù)值。
可以看出停車(chē)位上有車(chē)輛時(shí)白色像素點(diǎn)比較多,停車(chē)位沒(méi)有車(chē)輛時(shí),白色像素點(diǎn)很少甚至沒(méi)有,因此我們可以基于白色像素點(diǎn)數(shù)量來(lái)確定該車(chē)為是否被占用。同時(shí)可以看到當(dāng)停車(chē)位為空時(shí)存在一些椒鹽噪聲,通過(guò)medianBlur來(lái)處理椒鹽噪聲
imgMedian = cv2.medianBlur(imgThreshold,5)
可以看出椒鹽噪聲少了一部分。
使用dilate(膨脹)增強(qiáng)白色像素值,便于更好區(qū)分每個(gè)停車(chē)位是否被占用
kernel=np.ones((3,3),np.uint8); imgDilate=cv2.dilate(imgMedian,kernel,iterations=1)
可以看出白色的輪廓比之前加厚了
3. 4 判斷停車(chē)位是否被占用
截取每個(gè)停車(chē)位,經(jīng)過(guò)處理后的圖像,統(tǒng)計(jì)白色像素的數(shù)量
修改checkParkingSpace
函數(shù),將處理好的圖像傳入函數(shù)
def checkParkingSpace(imgProc): for pos in posList: x,y = pos imgCrop=imgProc[y:y+height,x:x+width] count=cv2.countNonZero(imgCrop) cvzone.putTextRect(img,str(count),(x,y+height-3,scale =1.5,thickness=2,offset=0)
對(duì)比可以看出,占有車(chē)位的數(shù)值比較大1000-2000,空車(chē)位的200-500,數(shù)值的差距比較大。
畫(huà)出所有停車(chē)位,對(duì)比找出合適的閾值,區(qū)分停車(chē)位為空還是被占用了。
可以看出停車(chē)位為空時(shí),值為0-600,而停車(chē)位被占用,值為:960-2300,因此我們?cè)O(shè)定閾值為750。所以低于750此時(shí)停車(chē)位沒(méi)有車(chē),高于950則停車(chē)位有車(chē)。
加上文字描述
代碼
import cv2 import pickle import cvzone import numpy as np # Video feed cap = cv2.VideoCapture('carPark.mp4') with open('CarParkPos','rb') as f: posList = pickle.load(f) width,height=107,48 def checkParkingSpace(imgProc): spaceCounter=0 for pos in posList: x,y = pos imgCrop=imgProc[y:y+height,x:x+width] count=cv2.countNonZero(imgCrop) if count < 950: color = (0,255,0) thickness = 5 spaceCounter +=1 else: color = (0,0,255) thickness = 2 cv2.rectangle(img,pos,(pos[0]+width,pos[1]+height),color,thickness=thickness) cvzone.putTextRect(img,str(count),(x,y+height-5),scale =1.5,thickness=2,offset=0,colorR=color) cvzone.putTextRect(img,f'Free{spaceCounter}/{len(posList)}',(100,50),scale =3,thickness=5,offset=20,colorR=(0,200,0)) while True: if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT): cap.set(cv2.CAP_PROP_POS_FRAMES,0) success,img= cap.read() imgGray =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) imgBlur =cv2.GaussianBlur(imgGray,(3,3),1) imgThreshold=cv2.adaptiveThreshold(imgBlur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV,25,16) imgMedian = cv2.medianBlur(imgThreshold,5) kernel=np.ones((3,3),np.uint8); imgDilate=cv2.dilate(imgMedian,kernel,iterations=1) checkParkingSpace(imgDilate) # for pos in posList: # cv2.rectangle(img,pos,(pos[0]+width,pos[1]+height),(255,0,255),2) cv2.imshow("Image",img) # cv2.imshow("imgBlur",imgBlur) # cv2.imshow("imgThreshold",imgThreshold) # cv2.imshow("imgMedian",imgMedian) # cv2.imshow("imgDilate",imgDilate) if cv2.waitKey(10) & 0xFF== ord('q'): break
最終效果如下:
源碼鏈接:https://github.com/yuanxinshui/Opencv-project/tree/main/39%20Parking%20Space%20Counter
到此這篇關(guān)于Python中使用Opencv開(kāi)發(fā)停車(chē)位計(jì)數(shù)器的文章就介紹到這了,更多相關(guān)python Opencv停車(chē)位計(jì)數(shù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python?OpenCV超詳細(xì)講解調(diào)整大小與圖像操作的實(shí)現(xiàn)
- Python?OpenCV超詳細(xì)講解讀取圖像視頻和網(wǎng)絡(luò)攝像頭
- 關(guān)于python3?opencv?圖像二值化的問(wèn)題(cv2.adaptiveThreshold函數(shù))
- Python?OpenCV實(shí)現(xiàn)圖形檢測(cè)示例詳解
- Python?OpenCV實(shí)現(xiàn)3種濾鏡效果實(shí)例
- python?OpenCV?圖像通道數(shù)判斷
- 巧妙使用python?opencv庫(kù)玩轉(zhuǎn)視頻幀率
- python+opencv實(shí)現(xiàn)堆疊圖片
- python?使用OpenCV進(jìn)行曝光融合
相關(guān)文章
python實(shí)現(xiàn)數(shù)組平移K位問(wèn)題
這篇文章主要介紹了python實(shí)現(xiàn)數(shù)組平移K位問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02python調(diào)用pymssql包操作SqlServer數(shù)據(jù)庫(kù)的實(shí)現(xiàn)
本文主要介紹了python調(diào)用pymssql包操作SqlServer數(shù)據(jù)庫(kù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06Python-OpenCV深度學(xué)習(xí)入門(mén)示例詳解
深度學(xué)習(xí)已經(jīng)成為機(jī)器學(xué)習(xí)中最受歡迎和發(fā)展最快的領(lǐng)域。深度學(xué)習(xí)的常見(jiàn)應(yīng)用包括語(yǔ)音識(shí)別、圖像識(shí)別、自然語(yǔ)言處理、推薦系統(tǒng)等等。本文將通過(guò)一些示例代碼,帶你詳細(xì)了解深入學(xué)習(xí)2021-12-12python調(diào)用OpenCV實(shí)現(xiàn)人臉識(shí)別功能
這篇文章主要為大家詳細(xì)介紹了python調(diào)用OpenCV實(shí)現(xiàn)人臉識(shí)別功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-05-05新年快樂(lè)! python實(shí)現(xiàn)絢爛的煙花綻放效果
這篇文章主要為大家詳細(xì)介紹了python利用可視化技巧實(shí)現(xiàn)煙花綻放效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01Python線(xiàn)性點(diǎn)運(yùn)算數(shù)字圖像處理示例詳解
這篇文章主要為大家介紹了數(shù)字圖像處理基本運(yùn)算如何用Python詳細(xì)點(diǎn)運(yùn)算來(lái)處理數(shù)字圖像有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09Python進(jìn)程池log死鎖問(wèn)題分析及解決
最近線(xiàn)上運(yùn)行的一個(gè)python任務(wù)負(fù)責(zé)處理一批數(shù)據(jù),為提高處理效率,使用了python進(jìn)程池,并會(huì)打印log,本文給大家分析了Python進(jìn)程池log死鎖問(wèn)題以及解決方法,需要的朋友可以參考下2024-01-01Python socket如何實(shí)現(xiàn)服務(wù)端和客戶(hù)端數(shù)據(jù)傳輸(TCP)
這篇文章主要介紹了Python socket如何實(shí)現(xiàn)服務(wù)端和客戶(hù)端數(shù)據(jù)傳輸(TCP),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05