OpenCV调用YOLOv4进行目标检测
目標(biāo)檢測就是對目標(biāo)進(jìn)行動態(tài)實時跟蹤定位,常見的目標(biāo)檢測算法有 R-CNN、Fast R-CNN、Faster R-CNN、SSD、Yolo 等,其中 Yolo 的速度和精確度都比較高,且只需訓(xùn)練一次,使用起來比較方便。
這里我們就使用官方現(xiàn)成的模型來檢測圖片,看一看效果,先學(xué)會使用流程,以后再訓(xùn)練自己的模型。
注意:opencv-python 目前只有?4.4.0?版本適配了 YOLOv4
導(dǎo)入庫
import numpy as np import time import cv2- 1
- 2
- 3
設(shè)置標(biāo)簽和標(biāo)注顏色
LABELS = open("coco.names").read().strip().split("\n") np.random.seed(666) COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8")- 1
- 2
- 3
coco.names?內(nèi)包含了很多目標(biāo)標(biāo)簽,如 person、bicycle、car 等,且按一定順序排列,里面基本包含了 Yolo 官方模型中可檢測的對象。該文件可從以下鏈接中提取:https://gitee.com/public_sharing/ObjectDetection-YOLO/blob/master/coco.names
每個對象配備了不一樣的顏色,以便在圖片中標(biāo)記時便于區(qū)分。
加載網(wǎng)絡(luò)
# 導(dǎo)入 YOLO 配置和權(quán)重文件并加載網(wǎng)絡(luò): net = cv2.dnn_DetectionModel('yolov4.cfg', 'yolov4.weights') # 獲取 YOLO 未連接的輸出圖層 layer = net.getUnconnectedOutLayersNames()- 1
- 2
- 3
- 4
yolov4.cfg?和?yolov4.weights?文件就是官方提供的模型,下載鏈接:https://pan.baidu.com/s/1XrcPHdp2_4c-dKge2Guw4w?提取碼:xsxb 。如果失效,可以直接百度搜索?Yolov4模型下載,有很多人都分享出來了。
cv2.dnn_DetectionModel?是 opencv 4.1.2 開始新增的方法,用于加載網(wǎng)絡(luò)。以前是使用?cv2.dnn.readNetFromDarknet?,此處使用也可以達(dá)到同樣的效果。
getUnconnectedOutLayersNames()?用于提取輸出圖層的名稱,yolo 含有很多的圖層,可以使用?getLayerNames()?將所有圖層的名稱提取出來。但在這里,我們只需要使用 yolo 的最后輸出圖層。
檢測圖片
# 導(dǎo)入圖片 image = cv2.imread('timg.jpg') # 獲取圖片尺寸 (H, W) = image.shape[:2]# 從輸入圖像構(gòu)造一個 blob,然后執(zhí)行 YOLO 對象檢測器的前向傳遞,給我們邊界盒和相關(guān)概率 blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416),swapRB=True, crop=False) net.setInput(blob) start = time.time() # 前向傳遞,獲得信息 layerOutputs = net.forward(layer) # 用于得出檢測時間 end = time.time() print("[INFO] YOLO took {:.6f} seconds".format(end - start))- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
blobFromImage 用于對圖像進(jìn)行預(yù)處理
cv2.dnn.blobFromImage(image[, scalefactor[, size[, mean[, swapRB[, crop[, ddepth]]]]]])
- image:輸入圖像
- scalefactor:圖像各通道數(shù)值的縮放比例
- size:輸出圖像的空間尺寸
- mean:用于各通道減去的值,以降低光照的影響
- swapRB:交換 RB 通道,默認(rèn)為 False
- crop:圖像裁剪,默認(rèn)為 False。當(dāng)值為 True 時,先按比例縮放,然后從中心裁剪成 size 尺寸
- ddepth:輸出的圖像深度,可選 CV_32F 或者 CV_8U
數(shù)據(jù)提取
boxes = [] confidences = [] classIDs = []# 循環(huán)提取每個輸出層 for output in layerOutputs:# 循環(huán)提取每個框for detection in output:# 提取當(dāng)前目標(biāo)的類 ID 和置信度scores = detection[5:]classID = np.argmax(scores)confidence = scores[classID]# 通過確保檢測概率大于最小概率來過濾弱預(yù)測if confidence > 0.5:# 將邊界框坐標(biāo)相對于圖像的大小進(jìn)行縮放,YOLO 返回的是邊界框的中心(x, y)坐標(biāo),# 后面是邊界框的寬度和高度box = detection[0:4] * np.array([W, H, W, H])(centerX, centerY, width, height) = box.astype("int")# 轉(zhuǎn)換出邊框左上角坐標(biāo)x = int(centerX - (width / 2))y = int(centerY - (height / 2))# 更新邊界框坐標(biāo)、置信度和類 id 的列表boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
3 個列表內(nèi)保存的內(nèi)容:
- boxes:對象的邊界框
- confidences :YOLO 分配給對象的置信度值,較低的置信度值表示該對象可能不是網(wǎng)絡(luò)認(rèn)為的對象。上面的代碼中將過濾掉小于 0.5 閾值的對象
- classIDs:檢測到的對象的類標(biāo)簽
這樣每個被提取出的對象,都確定了標(biāo)簽和區(qū)域坐標(biāo)就、位置。接下來就是在圖片中標(biāo)記出來,便于我們觀看。
標(biāo)記顯示
# 非最大值抑制,確定唯一邊框 idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.3) # 確定每個對象至少有一個框存在 if len(idxs) > 0:# 循環(huán)畫出保存的邊框for i in idxs.flatten():# 提取坐標(biāo)和寬度(x, y) = (boxes[i][0], boxes[i][1])(w, h) = (boxes[i][2], boxes[i][3])# 畫出邊框和標(biāo)簽color = [int(c) for c in COLORS[classIDs[i]]]cv2.rectangle(image, (x, y), (x + w, y + h), color, 1, lineType=cv2.LINE_AA)text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX,0.5, color, 1, lineType=cv2.LINE_AA) cv2.imshow("Tag", image) cv2.waitKey(0)- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
對于每個對象,Yolo 會框出 3 個左右的區(qū)域,我們只需要顯示出最合適的區(qū)域。非最大值抑制,就是搜索出局部最大值,將置信度最大的框保存,其余剔除。
cv2.dnn.NMSBoxes(bboxes, scores, score_threshold, nms_threshold, eta=None, top_k=None)
- bboxes:一組邊框
- scores:一組對應(yīng)的置信度
- score_threshold:置信度的閾值
- nms_threshold:非最大抑制的閾值
之后將每個對象的方框和標(biāo)簽都畫出來
結(jié)果展示:
完整代碼
import numpy as np import time import cv2LABELS = open("coco.names").read().strip().split("\n") np.random.seed(666) COLORS = np.random.randint(0, 255, size=(len(LABELS), 3), dtype="uint8") # 導(dǎo)入 YOLO 配置和權(quán)重文件并加載網(wǎng)絡(luò): net = cv2.dnn_DetectionModel('yolov4.cfg', 'yolov4.weights') # 獲取 YOLO 未連接的輸出圖層 layer = net.getUnconnectedOutLayersNames() image = cv2.imread('timg.jpg') # 獲取圖片尺寸 (H, W) = image.shape[:2] # 從輸入圖像構(gòu)造一個 blob,然后執(zhí)行 YOLO 對象檢測器的前向傳遞,給我們邊界盒和相關(guān)概率 blob = cv2.dnn.blobFromImage(image, 1/255.0, (416, 416),swapRB=True, crop=False) net.setInput(blob) start = time.time() # 前向傳遞,獲得信息 layerOutputs = net.forward(layer) # 用于得出檢測時間 end = time.time() print("YOLO took {:.6f} seconds".format(end - start))boxes = [] confidences = [] classIDs = []# 循環(huán)提取每個輸出層 for output in layerOutputs:# 循環(huán)提取每個框for detection in output:# 提取當(dāng)前目標(biāo)的類 ID 和置信度scores = detection[5:]classID = np.argmax(scores)confidence = scores[classID]# 通過確保檢測概率大于最小概率來過濾弱預(yù)測if confidence > 0.5:# 將邊界框坐標(biāo)相對于圖像的大小進(jìn)行縮放,YOLO 返回的是邊界框的中心(x, y)坐標(biāo),# 后面是邊界框的寬度和高度box = detection[0:4] * np.array([W, H, W, H])(centerX, centerY, width, height) = box.astype("int")# 轉(zhuǎn)換出邊框左上角坐標(biāo)x = int(centerX - (width / 2))y = int(centerY - (height / 2))# 更新邊界框坐標(biāo)、置信度和類 id 的列表boxes.append([x, y, int(width), int(height)])confidences.append(float(confidence))classIDs.append(classID) # 非最大值抑制,確定唯一邊框 idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.5, 0.3) # 確定每個對象至少有一個框存在 if len(idxs) > 0:# 循環(huán)畫出保存的邊框for i in idxs.flatten():# 提取坐標(biāo)和寬度(x, y) = (boxes[i][0], boxes[i][1])(w, h) = (boxes[i][2], boxes[i][3])# 畫出邊框和標(biāo)簽color = [int(c) for c in COLORS[classIDs[i]]]cv2.rectangle(image, (x, y), (x + w, y + h), color, 1, lineType=cv2.LINE_AA)text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX,0.5, color, 1, lineType=cv2.LINE_AA) cv2.imshow("Tag", image) cv2.waitKey(0)總結(jié)
以上是生活随笔為你收集整理的OpenCV调用YOLOv4进行目标检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 结构体和联合体
- 下一篇: python导入mysqldb_Pyth