【yolov4目标检测】(4) opencv+yolov4-tiny 实现选择性目标检测,附python完整代码
各位同學好,今天和大家分享一下如何使用 opencv 調用 yolov4-tiny 目標檢測方法,并對指定類別進行檢測。用b站的視頻做測試。
點擊按鈕 'all',按鈕變紅色,對所有的類別檢測
點擊按鈕 'person',按鈕變紅色,只對'person'類別檢測
1.文件配置
首先,我們需要導入 yolov4-tiny 網絡模型結構 cfg 文件,網絡權重 weights 文件,以及 COCO 數據集的分類名稱的 txt 文件。這里我已經給大家提供好了各種配置文件及代碼,有需要的自取。
鏈接:https://pan.baidu.com/s/19SMNuvCQGvl_V9O0RHsLog?
提取碼:zyp7
2. 目標檢測
(1)首先使用 cv2.dnn.readNet() 函數構造CSPDarknet53網絡結構,傳入模型結構cfg文件,以及網絡權重weights文件。新版的 opencv(4.1.2以上)針對神經網絡模塊提供了支持圖像分類、檢測、分割的幾種方法,自動實現輸入圖像的預處理及后處理。這里使用目標檢測模塊cv2.dnn_DetectionModel() 傳入網絡模型。
(2)目標檢測方法如下:
classids, scores, bboxes = cv2.dnn_DetectionModel.detect(frame, confThreshold,?numsThreshold)
參數:
frame:輸入的圖像
confThreshold:用來過濾選擇框的置信度閾值,目標檢測最小置信度
numsThreshold:非極大值抑制中的自定義閾值
返回值:
classIds:類別索引
confidences:置信度,檢測框屬于某個分類的概率
boxes:檢測框信息,左上角坐標(x,y),框的寬高(w, h)
(3)使用 model.setInputParams(size, scale) 設置網絡模型的輸入。參數設置,size 表示將輸入的圖像縮放至指定大小。size越大檢測效果越好,但是檢測速度越慢。scale 表示像素值的縮放大小。在opencv中每個像素值的范圍在0-255之間,而在神經網絡中每個像素值在0-1之間,scale=1/255
綜上,目標檢測代碼如下:
# yolov4-tiny目標檢測
import cv2#(1)導入yolov4-tiny網絡模型結構
# 傳入模型結構.cfg文件,模型權重參數.weight文件
net = cv2.dnn.readNet('dnn_model\yolov4-tiny.cfg', 'dnn_model\yolov4-tiny.weights')# 定義一個目標檢測模型,將模型傳進去
model = cv2.dnn_DetectionModel(net)# 設置模型的輸入
model.setInputParams(size=(320,320), scale=1/255)#(2)獲取分類文本的信息
classes = [] # 存放每個分類的名稱
with open('dnn_model\classes.txt') as file_obj:# 獲取文本中的每一行for class_name in file_obj.readlines():# 刪除文本中的換行符、空格等class_name = class_name.strip()# 將每個分類名保存到列表中classes.append(class_name)#(3)視頻捕獲
filepath = 'C:\\GameDownload\\Deep Learning\\traffic6.mp4'
cap = cv2.VideoCapture(filepath) #(4)對每一幀視頻圖像處理
while True:# 返回是否讀取成功ret和讀取的幀圖像frameret, frame = cap.read()# 圖像比較大把它縮小一點frame = cv2.resize(frame, (1280,720))# 視頻比較短,循環播放if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):# 如果當前幀==總幀數,那就重置當前幀為0cap.set(cv2.CAP_PROP_POS_FRAMES, 0)# 目標檢測classids, scores, bboxes = model.detect(frame, 0.5, 0.3)print('classids:', classids) # 如:[0]print('score:', scores) # 如:0.9469002print('bboxes:', bboxes) # 如:[159 176 816 533]#(5)顯示檢測結果# 遍歷所有的檢測框信息,把它們繪制出來for class_id, score, bbox in zip(classids, scores, bboxes):# 獲取檢測框的左上角坐標和寬高x, y, w, h = bbox# 獲取檢測框對應的分類名class_name = classes[class_id]# 繪制矩形框cv2.rectangle(frame, (x,y), (x+w,y+h), (255,255,0), 2)# 顯示分類文本cv2.putText(frame, class_name, (x,y+h+20), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,0), 2)# 顯示類別概率cv2.putText(frame, str(int(score*100))+'%', (x,y-5), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,255), 2)#(6)顯示圖像cv2.imshow('Image', frame) #窗口名,圖像變量if cv2.waitKey(30) & 0xFF==27: #每幀滯留30毫秒后消失break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
檢測效果如下:
3. 繪制按鈕
在同路徑下定義一個繪制矩形按鈕的類?drawButton,避免重復寫很多代碼。調用時只需要傳入幀圖像frame,和需要檢測類別的名稱classnames。代碼就不詳細介紹了,了解過面向對象編程的同學應該都看得懂吧。對面向對象不熟悉的可以看我之前的博客:https://blog.csdn.net/dgvv4/category_11569694.html?spm=1001.2014.3001.5482
# 定義創建按鈕的函數
import cv2# 定義類
class drawButton:# 定義類屬性w = 200 # 每個按鈕的寬h = 60 # 每個按鈕的高angerLine = 15 # 角點線段長度thick = 3 # 角點線段厚度# 矩形框顏色colorBG = (255,255,0) # 底色colorBL = (255,0,255) # 邊界colorBA = (0,255,255) # 角點邊線顏色# 初始化def __init__(self, classnames:list):# 分配屬性self.classnames = classnamesself.len = len(classnames)# 美化角點def drawAnger(self, img, x, y):# 給矩形的四個角添加線段cv2.line(img, (x,y), (x,y+self.angerLine), self.colorBA, self.thick)cv2.line(img, (x,y), (x+self.angerLine,y), self.colorBA, self.thick)cv2.line(img, (x+self.w,y), (x+self.w,y+self.angerLine), self.colorBA, self.thick)cv2.line(img, (x+self.w,y), (x+self.w-self.angerLine,y), self.colorBA, self.thick)cv2.line(img, (x,y+self.h), (x,y+self.h-self.angerLine), self.colorBA, self.thick)cv2.line(img, (x,y+self.h), (x+self.angerLine,y+self.h), self.colorBA, self.thick)cv2.line(img, (x+self.w,y+self.h), (x+self.w,y+self.h-self.angerLine), self.colorBA, self.thick)cv2.line(img, (x+self.w,y+self.h), (x+self.w-self.angerLine,y+self.h), self.colorBA, self.thick)# 定義繪圖方法def drawRec_alone(self, img, x, y, name):# 透明矩形參數設置alphaReserve = 0.5 # 透明度BChannel, GChannel, RChannel = self.colorBG # 設置矩形顏色 yMin, yMax = y, y+self.h # 矩形框的y坐標范圍xMin, xMax = x, x+self.w # 矩形框的y坐標范圍# 繪制透明矩形img[yMin:yMax, xMin:xMax, 0] = img[yMin:yMax, xMin:xMax, 0] * alphaReserve + BChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 1] = img[yMin:yMax, xMin:xMax, 1] * alphaReserve + GChannel * (1 - alphaReserve)img[yMin:yMax, xMin:xMax, 2] = img[yMin:yMax, xMin:xMax, 2] * alphaReserve + RChannel * (1 - alphaReserve)# 矩形框邊界cv2.rectangle(img, (x,y), (x+self.w, y+self.h), self.colorBL, 2)# 美化角點self.drawAnger(img, x, y)# 顯示文本cv2.putText(img, name, (x+20, y+40), cv2.FONT_HERSHEY_COMPLEX, 1.3, (255,255,255), 3)# 繪制多個按鈕框,保存每個按鈕的左上坐標def drawRec_many(self, img):self.recList = [] # 存放每個矩形框的左上角坐標 # 每個分類繪制一個矩形框for i in range(self.len):# 分類名name = self.classnames[i]# 每個矩形框的左上角坐標recx = 10recy = 100*i+50# 保存在列表中self.recList.append([[recx, recy], # 左上角[recx+self.w, recy], # 右上角[recx+self.w, recy+self.h], # 右下角[recx, recy+self.h] # 左下角]) # 每一個分類畫一個矩形框# 10代表x位置,y=110*i+50,矩形框之間縱向間隔50self.drawRec_alone(img, recx, recy, name)
然后我們用單張圖片測試一下效果:
filepath = 'C:\\GameDownload\\Deep Learning\\TF2.jpg'
img = cv2.imread(filepath)
# 重塑圖像大小
img = cv2.resize(img, (1280,720))
# 實例化,傳入需要繪制的按鈕的名稱
draw = drawButton(['person', 'bus', 'car', 'mot', 'tree'])
# 調用類方法,繪制多個矩形按鈕
draw.drawRec_many(img)
# 顯示每個矩形按鈕的四個角的坐標
print(draw.recList)
# 顯示圖像
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
4. 構建可選類別的目標檢測框架
首先我們看到下面代碼中的第(4)步。
這里用到鼠標響應 cv2.setMouseCallback() 可以在圖像上用鼠標操作,觸發一些事件。
鼠標響應: setMousecallback(winname, onMouse, userdata=0)
參數:
winname: 窗口的名字
onMouse: 鼠標響應函數,回調函數。指定窗口里每次鼠標時間發生的時候,被調用的函數指針。
userdate:傳給回調函數的參數?
回調函數: onMouse(int event, x, y, ?flags, param)
event: 是 CV_EVENT_* 變量之一
x和y: 鼠標指針在圖像坐標系的坐標(像素坐標)
flags: 是CV_EVENT_FLAG的組合
param: 是用戶定義的傳遞到setMouseCallback函數調用的參數
常用事件event變量:
cv2_EVENT_MOUSEMOVE 0 # 滑動
cv2_EVENT_LBUTTONDOWN 1 # 左鍵點擊
cv2_EVENT_RBUTTONDOWN 2 # 右鍵點擊
cv2_EVENT_MBUTTONDOWN 3 # 中間點擊
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 # 中間拖拽
。。。。。。。。。。。。。。。。。。。
當在視頻上點擊鼠標左鍵時,判斷鼠標所在位置(x, y)是否在矩形按鈕內部,其中 buttonList 記錄的是每個矩形按鈕的四個角坐標 [左上角,右上角,右下角,左下角]。使用 cv2.pointPolygonTest(contour, pt, measureDist) 函數判斷一個點 pt 是否在多邊形輪廓 counter 內部。如果設置 measureDist=True,返回值是點 pt 到多邊形輪廓 counter 的最小距離。如果設置 measureDist=False,判斷點 pt 是否在多邊形輪廓內部,返回值是:-1 代表在外部,0 代表在輪廓上,1 代表在內部。
如果鼠標點擊位置在某個按鈕內部,記下這個按鈕的索引 button_index = index,表示開始檢測這個按鈕對應的類別。
看到下面代碼中的第(7)步。繪制檢測框前,依次遍歷檢測返回的視頻中的所有分類結果?class_name,指定繪制的按鍵名稱是 usenames。如果所有分類中有分類在 usenames 中,并且鼠標點擊的按鈕的索引也等于usenames中某個類別的索引,class_name == name and index == button_index,那么就繪制這個檢測框。
# yolov4-tiny目標檢測
import cv2
import numpy as np
from myFunction import drawButton#(1)導入yolov4-tiny網絡模型結構
# 傳入模型結構.cfg文件,模型權重參數.weight文件
net = cv2.dnn.readNet('dnn_model\yolov4-tiny.cfg', 'dnn_model\yolov4-tiny.weights')# 定義一個目標檢測模型,將模型傳進去
model = cv2.dnn_DetectionModel(net)# 設置模型的輸入
model.setInputParams(size=(416, 416), scale=1/255)#(2)獲取分類文本的信息
classes = [] # 存放每個分類的名稱
with open('dnn_model\classes.txt') as file_obj:# 獲取文本中的每一行for class_name in file_obj.readlines():# 刪除文本中的換行符、空格等class_name = class_name.strip()# 將每個分類名保存到列表中classes.append(class_name)#(3)視頻捕獲
filepath = 'C:\\GameDownload\\Deep Learning\\trafficvideo3.mp4'
cap = cv2.VideoCapture(filepath) #(4)創建鼠事件
button_index = None # 存放哪個按鍵被點亮了# 定義鼠標回調函數
def click_button(event, x, y, flags, params):# 調用外部變量global button_index# 設置事鼠標件event為點擊鼠標左鍵if event == cv2.EVENT_LBUTTONDOWN:# 檢查鼠標的坐標是否在矩形框按鍵內部,index代表第幾個按鈕# 遍歷每個矩形框,每個框包含四個角的坐標for index, pt in enumerate(np.array(buttonList)): # 要轉換成numpy類型 # 如果設為True,計算鼠標左鍵距離矩形框的距離is_inside = cv2.pointPolygonTest(pt, (x,y), False)if is_inside > 0: # 鼠標在矩形框內部print(f'click in the No.{index+1}', (x,y))# 激活哪個分類的檢測框button_index = index#(5)創建窗口
cv2.namedWindow('Image') # 窗口名和顯示圖像的窗口名相同# 設置鼠標回調,窗口名和上面相同,自定義回調函數
cv2.setMouseCallback('Image', click_button)# 創建按鈕
usenames = ['all', 'person', 'car', 'bus', 'truck']
button = drawButton(usenames)#(6)定義檢測框繪制函數
colorline = (0,255,0) # 角點線段顏色
angerline = 13 # 角點線段長度def drawbbx(img, x, y, w, h, predName, score):# 檢測框cv2.rectangle(img, (x, y), (x+w, y+h), (255,255,0), 1)# 角點美化cv2.line(img, (x,y), (x+angerline,y), colorline, 2)cv2.line(img, (x,y), (x,y+angerline), colorline, 2) cv2.line(img, (x+w,y), (x+w,y+angerline), colorline, 2)cv2.line(img, (x+w,y), (x+w-angerline,y), colorline, 2)cv2.line(img, (x,y+h), (x,y+h-angerline), colorline, 2)cv2.line(img, (x,y+h), (x+angerline,y+h), colorline, 2)cv2.line(img, (x+w,y+h), (x+w,y+h-angerline), colorline, 2) cv2.line(img, (x+w,y+h), (x+w-angerline,y+h), colorline, 2)# 顯示預測的類別cv2.putText(img, predName, (x,y+h+20), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,0), 2)# 顯示預測概率cv2.putText(img, str(int(score*100))+'%', (x,y-5), cv2.FONT_HERSHEY_COMPLEX, 1, (0,255,255), 2)#(6)對每一幀視頻圖像處理
while True:# 返回是否讀取成功ret和讀取的幀圖像frameret, frame = cap.read()# 圖像比較大把它縮小一點frame = cv2.resize(frame, (1280,720))# 視頻比較短,循環播放if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):# 如果當前幀==總幀數,那就重置當前幀為0cap.set(cv2.CAP_PROP_POS_FRAMES, 0)#(7)目標檢測classids, scores, bboxes = model.detect(frame, 0.5, 0.3)# 在畫面上創建按鈕button.drawRec_many(frame)# 獲取所有矩形框的四個角的坐標buttonList = button.recList #(8)顯示檢測結果# 遍歷所有的檢測框信息,把它們繪制出來for class_id, score, bbox in zip(classids, scores, bboxes):# 獲取檢測框的左上角坐標和寬高x, y, w, h = bbox# 獲取檢測框對應的分類名class_name = classes[class_id]# 遍歷四個按鍵的名稱for index, name in enumerate(usenames):# 設置檢測條件,只有檢測到的類別是person并且鼠標點擊位置在矩形框內if class_name == name and index == button_index:# 繪制class_name類別的檢測框drawbbx(frame, x, y, w, h, class_name, score) # 改變按鈕顏色cv2.rectangle(frame, buttonList[index][0], buttonList[index][2], (0,0,255), 5)# 點擊按鈕'all'elif name == 'all' and index == button_index:# 繪制所有類別的檢測框drawbbx(frame, x, y, w, h, class_name, score)# 改變按鈕顏色cv2.rectangle(frame, buttonList[index][0], buttonList[index][2], (0,0,255), 5)#(9)顯示圖像cv2.imshow('Image', frame) #窗口名,圖像變量if cv2.waitKey(30) & 0xFF==27: #每幀滯留1毫秒后消失break# 釋放視頻資源
cap.release()
cv2.destroyAllWindows()
檢測目標設置為'car'的效果圖如下:
總結
以上是生活随笔為你收集整理的【yolov4目标检测】(4) opencv+yolov4-tiny 实现选择性目标检测,附python完整代码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【yolov3目标检测】(3) open
- 下一篇: 【seaborn】(1) 数据可视化,绘