?????????本章將實現(xiàn)了一個簡單的車輛速度估計和車流量統(tǒng)計的GUI應(yīng)用,它使用了Haar級聯(lián)檢測器和相關(guān)跟蹤器來檢測和跟蹤視頻中的車輛,并通過圖像處理和數(shù)學(xué)計算來估計車輛的速度。
? ? ? ? 1.首先,該代碼需要cv2:用于圖像處理和計算機視覺任務(wù);dlib:用于對象跟蹤和檢測;time:用于計算幀率和時間間隔;threading:用于處理多線程操作;math:用于數(shù)學(xué)計算等。
? ? ? ? 2.然后,定義了全局變量video_path和highest_speed,用于存儲選擇的視頻文件路徑和最高時速度。
? ? ? ? 3.接下來,通過carCascade = cv2.CascadeClassifier('myhaar.xml')導(dǎo)入車輛檢測器模型。然后定義了全局變量video和一些常量,如視頻的寬度和高度。
carCascade = cv2.CascadeClassifier('myhaar.xml')
video = None
WIDTH = 1280
HEIGHT = 720
? ? ? ? 3.實現(xiàn)estimateSpeed(location1, location2, fps)函數(shù)用于估計車輛速度,根據(jù)兩個位置點的像素距離、像素每米比例和幀率來計算車輛的速度。
def estimateSpeed(location1, location2, fps):
d_pixels = math.sqrt(math.pow(location2[0] - location1[0], 2) + math.pow(location2[1] - location1[1], 2))
ppm = 8.8
d_meters = d_pixels / ppm
if fps == 0.0:
fps = 18
speed = d_meters * fps * 3.6
return speed
????????代碼中:location1和location2是表示車輛位置的參數(shù)。它們是包含兩個元素的元組或列表,分別表示車輛在圖像中的坐標(biāo)(x,y)。fps是幀率(Frames Per Second),表示視頻播放的幀速率。d_pixels是計算兩個位置之間像素距離的變量。通過使用兩個位置的x和y坐標(biāo)差值計算歐氏距離。ppm是每像素米數(shù)(Pixels Per Meter)的值。它表示圖像中的像素距離與實際距離之間的比例關(guān)系。在這里,假設(shè)每個像素代表8.8厘米。d_meters是將像素距離轉(zhuǎn)換為米的值。通過將像素距離除以ppm得到。如果幀率fps為0.0(未提供或無效值),將其設(shè)置為默認值18。speed是估計的速度,以千米/小時為單位。通過將距離(以米為單位)乘以幀率(以秒為單位)再乘以3.6(將小時轉(zhuǎn)換為秒)計算得到。返回估計的速度。
????????綜上所述,該函數(shù)根據(jù)兩個位置之間的像素距離、幀率和像素到米的比例關(guān)系,估計車輛的速度(以千米/小時為單位)。?
? ? ? ? 4.實現(xiàn)track_multiple_objects()函數(shù)是實現(xiàn)多目標(biāo)跟蹤的核心部分。它使用Haar級聯(lián)檢測器來檢測圖像中的車輛,并使用dlib的相關(guān)跟蹤器來跟蹤每個車輛。函數(shù)使用一個無限循環(huán),從視頻中讀取幀,然后進行車輛檢測和跟蹤。在每一幀中,函數(shù)更新已跟蹤車輛的位置和質(zhì)量,并計算車輛的速度。還更新了最高時速度和實時車流量的標(biāo)簽,并顯示跟蹤結(jié)果的圖像。
def track_multiple_objects():
rectangleColor = (0, 255, 0)
frameCounter = 0
currentCarID = 0
fps = 0
carTracker = {}
carLocation1 = {}
carLocation2 = {}
speed = [None] * 1000
def update_highest_speed(speed):
global highest_speed
highest_speed = max(highest_speed, speed)
speed_label.config(text="最高時速度:{} km/hr".format(highest_speed))
def update_video_frame(image):
image = Image.fromarray(image)
image = image.resize((640, 480))
photo = ImageTk.PhotoImage(image)
video_label.config(image=photo)
video_label.image = photo
# 其他代碼...
total_cars = 0 # 車輛總數(shù)
prev_total_cars = 0 # 上一幀的車輛總數(shù)
while True:
start_time = time.time()
rc, image = video.read()
if not rc:
break
image = cv2.resize(image, (WIDTH, HEIGHT))
resultImage = image.copy()
frameCounter = frameCounter + 1
carIDtoDelete = []
# 更新已跟蹤車輛的位置和質(zhì)量
for carID in carTracker.keys():
trackingQuality = carTracker[carID].update(image)
if trackingQuality < 7:
carIDtoDelete.append(carID)
for carID in carIDtoDelete:
carTracker.pop(carID, None)
carLocation1.pop(carID, None)
carLocation2.pop(carID, None)
if not (frameCounter % 10):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cars = carCascade.detectMultiScale(gray, 1.1, 13, 18, (24, 24))
for (_x, _y, _w, _h) in cars:
x = int(_x)
y = int(_y)
w = int(_w)
h = int(_h)
x_bar = x + 0.5 * w
y_bar = y + 0.5 * h
matchCarID = None
for carID in carTracker.keys():
trackedPosition = carTracker[carID].get_position()
t_x = int(trackedPosition.left())
t_y = int(trackedPosition.top())
t_w = int(trackedPosition.width())
t_h = int(trackedPosition.height())
t_x_bar = t_x + 0.5 * t_w
t_y_bar = t_y + 0.5 * t_h
if (
(t_x <= x_bar <= (t_x + t_w))
and (t_y <= y_bar <= (t_y + t_h))
and (x <= t_x_bar <= (x + w))
and (y <= t_y_bar <= (y + h))
):
matchCarID = carID
if matchCarID is None:
tracker = dlib.correlation_tracker()
tracker.start_track(image, dlib.rectangle(x, y, x + w, y + h))
carTracker[currentCarID] = tracker
carLocation1[currentCarID] = [x, y, w, h]
currentCarID = currentCarID + 1
for carID in carTracker.keys():
trackedPosition = carTracker[carID].get_position()
t_x = int(trackedPosition.left())
t_y = int(trackedPosition.top())
t_w = int(trackedPosition.width())
t_h = int(trackedPosition.height())
cv2.rectangle(resultImage, (t_x, t_y), (t_x + t_w, t_y + t_h), rectangleColor, 4)
carLocation2[carID] = [t_x, t_y, t_w, t_h]
end_time = time.time()
if not (end_time == start_time):
fps = 1.0 / (end_time - start_time)
for i in carLocation1.keys():
if frameCounter % 1 == 0:
[x1, y1, w1, h1] = carLocation1[i]
[x2, y2, w2, h2] = carLocation2[i]
carLocation1[i] = [x2, y2, w2, h2]
if [x1, y1, w1, h1] != [x2, y2, w2, h2]:
if speed[i] is None or speed[i] == 0:
speed[i] = estimateSpeed([x1, y1, w1, h1], [x2, y2, w2, h2], fps)
if speed[i] != 0 and speed[i] < 150:
update_highest_speed(speed[i])
cv2.putText(resultImage,str(int(speed[i])) + " km/hr", (int(x1 + w1 / 2), int(y1 - 10)),cv2.FONT_HERSHEY_SIMPLEX, 0.75,(0, 255, 0),2,)
# 更新車流量
prev_total_cars = total_cars
total_cars = len(carTracker)
# 更新實時車流量標(biāo)簽
traffic_label.config(text="實時車流量:{}".format(total_cars))
update_video_frame(resultImage)
video.release()
? ? ? ? 該代碼中首先,定義了一些變量和數(shù)據(jù)結(jié)構(gòu)用于跟蹤車輛。rectangleColor是繪制車輛邊界框的顏色,frameCounter用于計算幀數(shù),currentCarID表示當(dāng)前車輛的ID,fps表示幀率。carTracker是一個字典,用于存儲每輛車的追蹤器對象。carLocation1和carLocation2分別是字典,用于存儲每輛車的當(dāng)前和上一幀的位置信息。speed是一個列表,用于存儲每輛車的速度。update_highest_speed()是一個內(nèi)部函數(shù),用于更新最高速度的顯示。update_video_frame()是一個內(nèi)部函數(shù),用于更新視頻幀的顯示。total_cars和prev_total_cars是用于計算車流量的變量。進入主循環(huán),首先讀取視頻的一幀圖像。如果無法讀取到圖像,就退出循環(huán)。對讀取到的圖像進行預(yù)處理,包括調(diào)整圖像大小和創(chuàng)建一個副本。增加幀計數(shù)器的值。創(chuàng)建一個空列表carIDtoDelete,用于存儲需要刪除的車輛的ID。遍歷已跟蹤的車輛,更新其位置信息和質(zhì)量。如果某輛車的跟蹤質(zhì)量低于閾值(7),則將其ID添加到carIDtoDelete列表中。遍歷carIDtoDelete列表,從carTracker、carLocation1和carLocation2中刪除對應(yīng)的車輛。每隔10幀,檢測圖像中的車輛。使用級聯(lián)分類器(carCascade)對灰度圖像進行目標(biāo)檢測,并返回檢測到的車輛的邊界框。遍歷檢測到的車輛邊界框,與已跟蹤的車輛進行匹配。如果找到匹配的車輛,更新該車輛的追蹤器對象,位置信息和ID。如果沒有找到匹配的車輛,創(chuàng)建一個新的追蹤器對象,將其添加到carTracker中,并更新位置信息和ID。遍歷carTracker中的每輛車,獲取其位置信息,并在結(jié)果圖像上繪制車輛邊界框。根據(jù)每輛車的位置信息和幀率,估計車輛的速度,并將其存儲在speed列表中。如果速度不為0且小于150,更新最高速度。在結(jié)果圖像上顯示每輛車的速
? ? ? ? 5.實現(xiàn)open_file()函數(shù)用于打開文件對話框并選擇視頻文件。選擇視頻文件后,將啟動一個新線程來處理視頻。
def open_file():
global video_path, video
file_types = [("視頻文件", "*.mp4;*.avi;*.mkv")] # 允許上傳的視頻文件類型
video_path = filedialog.askopenfilename(title="選擇視頻文件", filetypes=file_types)
if video_path:
video = cv2.VideoCapture(video_path)
t = threading.Thread(target=process_video)
t.start()
? ? ? ?6. 實現(xiàn)process_video()函數(shù)在新線程中執(zhí)行,它首先通過cv2.VideoCapture打開選擇的視頻文件,然后調(diào)用track_multiple_objects()函數(shù)對視頻進行處理。
? ? ? ? 7.實現(xiàn)update_highest_speed(speed)函數(shù)用于更新最高時速度的全局變量,并更新顯示最高時速度的標(biāo)簽。
? ? ? ? 8.實現(xiàn)update_video_frame(image)函數(shù)用于更新顯示視頻幀的標(biāo)簽,它將圖像轉(zhuǎn)換為Tkinter可用的格式并進行適當(dāng)?shù)恼{(diào)整。
? ? ? ? 9.最后,代碼創(chuàng)建了一個Tkinter窗口,并在窗口中添加了按鈕、車流量標(biāo)簽、最高時速度標(biāo)簽和視頻顯示標(biāo)簽。通過window.mainloop()來啟動GUI窗口的事件循環(huán),使應(yīng)用保持運行狀態(tài)。實現(xiàn)的界面如下所示:
點擊選擇視頻視頻按鈕,我們可以選擇任意格式的視頻進行檢測:
?選擇視頻后的輸出界面如下:
車流量檢測和速度估計
?整個代碼下載鏈接:
https://download.csdn.net/download/weixin_40651515/87882938
運行環(huán)境依賴包:文章來源:http://www.zghlxwxcb.cn/news/detail-760100.html
opencv-python==4.1.0.25
numpy==1.17.2
dlib==19.8.1
future==0.17.1
Pillow==8.4.0文章來源地址http://www.zghlxwxcb.cn/news/detail-760100.html
到了這里,關(guān)于手把手教你實現(xiàn)—基于OpenCV的車流量統(tǒng)計和車速檢測代碼的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!