如何使用Python和OpenCV進(jìn)行實時目標(biāo)檢測實例詳解
簡介
這段程序是一個Python腳本,它使用了OpenCV庫和預(yù)訓(xùn)練的YOLOv3模型來實現(xiàn)實時視頻流的目標(biāo)檢測。它首先從攝像頭捕獲視頻流,并使用線程池處理每一幀圖像。在每一幀中,程序都會檢測和識別不同的對象,并用不同的顏色顯示結(jié)果。使用了非極大值抑制技術(shù)刪除重復(fù)的檢測框,并利用了并發(fā)處理技術(shù)以提高性能。最后,他還顯示了每秒處理的幀數(shù)(FPS)。我們可以通過按'q'鍵來結(jié)束程序。這個程序展示了一種有效的使用深度學(xué)習(xí)模型進(jìn)行實時視覺任務(wù)的方法。
代碼介紹
這段代碼是使用OpenCV和Python編寫的,主要用于實時視頻流處理和目標(biāo)檢測。代碼的核心是使用訓(xùn)練好的YOLOv3模型來識別和定位視頻幀中的對象。下面是對整個流程的詳細(xì)解釋:
導(dǎo)入庫:首先,導(dǎo)入所需的庫,包括
cv2
(OpenCV),numpy
(用于科學(xué)計算),time
(時間管理),以及concurrent.futures
(用于并發(fā)執(zhí)行)。初始化參數(shù):設(shè)置檢測參數(shù),包括置信度閾值(用于過濾掉那些置信度低于閾值的檢測結(jié)果),非極大值抑制(NMS)閾值(用于去除重復(fù)的檢測框),以及輸入圖像的寬和高。
加載模型和類別:通過使用
cv2.dnn.readNet
加載預(yù)訓(xùn)練的YOLOv3模型,并從coco.names
文件中加載可以識別的類名列表。顏色列表:為每個可識別的類別創(chuàng)建一個隨機(jī)顏色列表,這用于在檢測到的對象周圍繪制彩色的邊界框。
視頻捕獲:打開攝像頭進(jìn)行視頻流的捕獲。
多線程處理:初始化
ThreadPoolExecutor
以并發(fā)執(zhí)行多個任務(wù)。這里定義了兩個函數(shù)fetch_frame
和process_frame
。fetch_frame
用于從視頻流中獲取一幀圖像,而process_frame
則用于處理圖像并執(zhí)行目標(biāo)檢測。目標(biāo)檢測流程:
- 轉(zhuǎn)換輸入幀:將輸入幀轉(zhuǎn)換為模型所需要的格式(blob),包括縮放、顏色空間轉(zhuǎn)換等。
- 執(zhí)行檢測:調(diào)用神經(jīng)網(wǎng)絡(luò)模型執(zhí)行前向傳播,獲取檢測結(jié)果。
- 過濾結(jié)果:根據(jù)置信度閾值和NMS閾值過濾掉一部分檢測結(jié)果,消除低置信度以及重復(fù)的檢測框。
- 繪制邊界框和類別標(biāo)簽:在原圖上繪制檢測到的對象的邊界框,并顯示類別名稱和置信度。
顯示結(jié)果:在屏幕上實時顯示處理后的視頻幀,并計算顯示FPS(每秒幀數(shù))。
程序退出:等待我們按
q
鍵退出,并在退出前釋放資源,包括攝像頭和窗口。
這段代碼的設(shè)計利用了異步處理技術(shù)(通過ThreadPoolExecutor
)來提高處理視頻流的效率,使得幀的捕獲和處理能夠并行執(zhí)行,從而盡可能提高FPS。
為什么這樣做,主要是我的電腦沒有獨立GPU,所以,呃,只能動點這中方法了,但是說實話并沒有什么實質(zhì)性的提升,難受了。
代碼拆解講解
我們將使用預(yù)訓(xùn)練的 YOLOv3 模型進(jìn)行目標(biāo)檢測,并使用 Python 的 concurrent.futures 庫來并行處理視頻幀的讀取和模型推理,以優(yōu)化程序的執(zhí)行速度。
感謝YOLO,雖然現(xiàn)在已經(jīng)發(fā)展到v8了,但是我們這里使用v3還是足夠了。
1.首先,讓我們導(dǎo)入需要用到的庫:
import cv2 import numpy as np import time from concurrent.futures import ThreadPoolExecutor
2.然后,設(shè)置兩個閾值:conf_threshold 和 nms_threshold,以及圖片的寬度和高度:
conf_threshold = 0.5 nms_threshold = 0.4 Width = 416 Height = 416
3.接下來,我們加載預(yù)訓(xùn)練的 YOLOv3 模型,并加載識別的類名:
net = cv2.dnn.readNet('../needFiles/yolov3.weights', '../needFiles/yolov3.cfg') with open('../needFiles/coco.names', 'r') as f: classes = f.read().strip().split('\n')
4.然后,我們創(chuàng)建一個顏色列表,以在最后的目標(biāo)檢測結(jié)果中為不同的類別繪制不同的顏色:
color_list = np.random.uniform(0, 255, size=(len(classes), 3))
5.下一步,我們定義兩個函數(shù) fetch_frame 和 process_frame
fetch_frame 用于從視頻對象讀取一幀;而 process_frame 則將讀取到的幀輸入到 YOLOv3 模型中,然后處理獲得的輸出結(jié)果,并在幀上繪制物體檢測結(jié)果:
def fetch_frame(cap): ... def process_frame(frame): ...
6.在主循環(huán)中,我們使用 ThreadPoolExecutor 實現(xiàn)了并行處理讀取幀和模型推理的操作。
這樣可以使讀取下一幀的操作和模型推理操作同時進(jìn)行,從而顯著地加快了處理速度:
executor = ThreadPoolExecutor(max_workers=2) frame_future = executor.submit(fetch_frame, cap) while True: ... ret, frame, height, width, channels = frame_future.result() frame_future = executor.submit(fetch_frame, cap) processed_frame = executor.submit(process_frame, frame).result() ...
7.退出程序
在這段代碼的最后,如果你按下 q 鍵退出主循環(huán),視頻讀取對象將會被釋放,所有的窗口也將被銷毀:
if cv2.waitKey(1) & 0xFF == ord('q'): break ... cap.release() cv2.destroyAllWindows()
總體代碼
# 導(dǎo)入必要的庫 import cv2 import numpy as np import time from concurrent.futures import ThreadPoolExecutor # 設(shè)置置信度閾值和非極大值抑制(NMS)閾值 conf_threshold = 0.5 nms_threshold = 0.4 Width = 416 Height = 416 # 加載預(yù)訓(xùn)練的 YOLOv3 模型 net = cv2.dnn.readNet('../needFiles/yolov3.weights', '../needFiles/yolov3.cfg') # 加載可識別的類名 with open('../needFiles/coco.names', 'r') as f: classes = f.read().strip().split('\n') # 為不同的類別創(chuàng)建一個顏色列表 color_list = np.random.uniform(0, 255, size=(len(classes), 3)) # 打開攝像頭進(jìn)行視頻幀的捕獲 cap = cv2.VideoCapture(0) # 初始化一個ThreadPoolExecutor用于多線程處理 executor = ThreadPoolExecutor(max_workers=2) # 定義fetch_frame函數(shù),從視頻流中獲取視頻幀 def fetch_frame(cap): ret, frame = cap.read() # 讀取一幀圖像 height, width, channels = frame.shape # 獲取圖像的尺寸和通道信息 return ret, frame, height, width, channels # 定義process_frame函數(shù),處理每幀圖像并進(jìn)行目標(biāo)檢測 def process_frame(frame): # 將幀轉(zhuǎn)換為模型的輸入格式 blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False) net.setInput(blob) output_layers = net.getUnconnectedOutLayersNames() # 獲取輸出層的名字 layer_outputs = net.forward(output_layers) # 進(jìn)行前向傳播,獲取檢測結(jié)果 boxes = [] # 用于存儲檢測到的邊界框 confidences = [] # 用于存儲邊界框的置信度 class_ids = [] # 用于存儲邊界框的類別ID # 循環(huán)每個輸出層的檢測結(jié)果 for output in layer_outputs: for detection in output: scores = detection[5:] # 獲取類別的得分 class_id = np.argmax(scores) # 獲取得分最高的類別ID confidence = scores[class_id] # 獲取得分最高的置信度 # 過濾低置信度的檢測結(jié)果 if confidence > conf_threshold: center_x = int(detection[0] * width) center_y = int(detection[1] * height) w = int(detection[2] * width) h = int(detection[3] * height) # 計算邊界框的位置和尺寸 x = int(center_x - w / 2) y = int(center_y - h / 2) # 將邊界框的位置、尺寸、置信度和類別ID添加到列表中 boxes.append([x, y, w, h]) confidences.append(float(confidence)) class_ids.append(class_id) # 使用非極大值抑制去除重疊的邊界框 indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold) # 在原圖上繪制邊界框和類別標(biāo)簽 for i in indices.flatten(): box = boxes[i] x = box[0] y = box[1] w = box[2] h = box[3] label = str(classes[class_ids[i]]) color = color_list[class_ids[i]] cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2) cv2.putText(frame, label, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2) return frame # 在進(jìn)入循環(huán)前,先讀取一幀以開始異步處理 frame_future = executor.submit(fetch_frame, cap) # 主循環(huán) while True: start = time.time() # 記錄開始處理的時間點 # 獲取當(dāng)前幀和相應(yīng)信息 ret, frame, height, width, channels = frame_future.result() # 異步讀取下一幀 frame_future = executor.submit(fetch_frame, cap) # 如果當(dāng)前幀讀取成功,則繼續(xù)處理 if ret: # 使用線程池異步處理當(dāng)前幀 processed_frame = executor.submit(process_frame, frame).result() # 計算FPS end = time.time() fps = 1 / (end - start) # 在處理好的幀上顯示FPS cv2.putText(processed_frame, "FPS: " + str(round(fps, 2)), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) # 顯示處理好的幀 cv2.imshow('frame', processed_frame) # 如果我們按下 ‘q' 鍵,退出循環(huán) if cv2.waitKey(1) & 0xFF == ord('q'): break else: break # 如果幀沒有被成功讀取,退出循環(huán) # 釋放視頻捕獲對象和銷毀所有OpenCV窗口 cap.release() cv2.destroyAllWindows()
效果展示
這個效果還是不錯的哈,就是這個硬件性能跟不上,要是有獨顯就好了。
使用GPU說明
當(dāng)然了,為了在大學(xué)時期狠狠的獎勵自己四年游戲,很多同學(xué)應(yīng)該都是購買的游戲本,那么恭喜你,你的硬件非常的完美,那么這里你可以看一下。
如何操作
如果你想利用 GPU 加速你的目標(biāo)檢測代碼,主要更改會集中在如何讓 OpenCV 利用你的 GPU。不幸的是,OpenCV 的 dnn
模塊默認(rèn)使用 CPU 進(jìn)行計算。想要使用 GPU,首要條件是你需要有一個支持 CUDA 的 NVIDIA GPU。
從 OpenCV 4.2 版本開始,dnn
模塊添加了對 CUDA 的支持,但實現(xiàn)這一點需要確保你的 OpenCV 是用 CUDA 支持構(gòu)建的。如果你自己編譯 OpenCV,確保在編譯時啟用了 CUDA 支持。
以下是如何更改你的代碼以利用 CUDA 的基本步驟:
1.在讀取模型時啟用 CUDA:
替換代碼中的 readNet
調(diào)用,使用 readNetFromDarknet
并添加代碼來設(shè)置網(wǎng)絡(luò)的首選后端和目標(biāo)為 CUDA。
# 加載預(yù)訓(xùn)練的 YOLOv3 模型 net = cv2.dnn.readNetFromDarknet('../needFiles/yolov3.cfg', '../needFiles/yolov3.weights') # 啟用 CUDA net.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA) net.setPreferableTarget(cv2.dnn.DNN_TARGET_CUDA)
2.其它代碼不需要做太多修改:
使用CUDA優(yōu)化后,主要是模型推理過程(即net.forward()
的調(diào)用)會更快。數(shù)據(jù)準(zhǔn)備和后處理(例如非極大值抑制)的代碼不需要太多修改,因為它們?nèi)匀辉?CPU 上執(zhí)行。
這些改動僅在你已有 OpenCV 版本支持 CUDA,并且你的系統(tǒng)擁有合適的 NVIDIA GPU 時有效。如果你的環(huán)境滿足這些條件,這樣的更改可以顯著加快模型推理的速度,尤其是在進(jìn)行視頻流處理時。
最后,你一定要確定你的環(huán)境(包括 NVIDIA 驅(qū)動程序和 CUDA Toolkit)被正確設(shè)置以支持 GPU 加速。如果你對如何編譯支持 CUDA 的 OpenCV 或如何配置你的系統(tǒng)環(huán)境有任何疑問,我建議查閱 OpenCV 官方文檔和 NVIDIA 的 CUDA 安裝指導(dǎo),因為我真的沒有仔細(xì)研究過。
總結(jié)
希望這篇博客對你有所幫助。最后我想說,雖然NVIDIA對我們的學(xué)習(xí)有幫助,但是我還是想說。
到此這篇關(guān)于如何使用Python和OpenCV進(jìn)行實時目標(biāo)檢測的文章就介紹到這了,更多相關(guān)Python和OpenCV實時目標(biāo)檢測內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python實現(xiàn)用networkx繪制MultiDiGraph
這篇文章主要介紹了Python實現(xiàn)用networkx繪制MultiDiGraph方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02python使用pandas讀xlsx文件的實現(xiàn)
這篇文章主要介紹了python使用pandas讀xlsx文件的實現(xiàn)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05pytorch 把MNIST數(shù)據(jù)集轉(zhuǎn)換成圖片和txt的方法
這篇文章主要介紹了pytorch 把MNIST數(shù)據(jù)集轉(zhuǎn)換成圖片和txt的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-05-05使用pycharm創(chuàng)建Django項目失敗的解決方案
使用PyCharm創(chuàng)建Django項目時遇到無法運行的問題,可以檢查Python的安裝路徑設(shè)置是否正確,在PyCharm的設(shè)置中找到項目解釋器的位置,確保路徑正確,如果不確定Python的安裝位置,可以在命令提示符中使用“where Python”命令查詢2024-09-09Python3中l(wèi)ambda表達(dá)式與函數(shù)式編程講解
今天小編就為大家分享一篇關(guān)于Python3中l(wèi)ambda表達(dá)式與函數(shù)式編程講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01