目標檢測就是對目標進行動態實時跟蹤定位,常見的目標檢測演算法有 R-CNN、Fast R-CNN、Faster R-CNN、SSD、Yolo 等,其中 Yolo 的速度和精確度都比較高,且只需訓練一次,使用起來比較方便。

這裡我們就使用官方現成的模型來檢測圖片,看一看效果,先學會使用流程,以後再訓練自己的模型。

注意

:opencv-python 目前只有

4.4.0

版本適配了 YOLOv4

匯入庫

import numpy as np

import time

import cv2

設定標籤和標註顏色

LABELS = open(“coco。names”)。read()。strip()。split(“\n”)

np。random。seed(666)

COLORS = np。random。randint(0, 255, size=(len(LABELS), 3), dtype=“uint8”)

coco。names 內包含了很多目標標籤,如 person、bicycle、car 等,且按一定順序排列,裡面基本包含了 Yolo 官方模型中可檢測的物件。該檔案可從以下連結中提取:

https://

gitee。com/public_sharin

g/ObjectDetection-YOLO/blob/master/coco。names

每個物件配備了不一樣的顏色,以便在圖片中標記時便於區分。

載入網路

# 匯入 YOLO 配置和權重檔案並載入網路:

net = cv2。dnn_DetectionModel(‘yolov4。cfg’, ‘yolov4。weights’)

# 獲取 YOLO 未連線的輸出圖層

layer = net。getUnconnectedOutLayersNames()

yolov4。cfg 和 yolov4。weights 檔案就是官方提供的模型,下載連結:

https://

pan。baidu。com/s/1XrcPHd

p2_4c-dKge2Guw4w

提取碼:xsxb 。如果失效,可以直接百度搜索

Yolov4模型下載

,有很多人都分享出來了。

cv2。dnn_DetectionModel 是 opencv 4。1。2 開始新增的方法,用於載入網路。以前是使用 cv2。dnn。readNetFromDarknet ,此處使用也可以達到同樣的效果。

getUnconnectedOutLayersNames() 用於提取輸出圖層的名稱,yolo 含有很多的圖層,可以使用 getLayerNames() 將所有圖層的名稱提取出來。但在這裡,我們只需要使用 yolo 的最後輸出圖層。

檢測圖片

# 匯入圖片

image = cv2。imread(‘timg。jpg’)

# 獲取圖片尺寸

(H, W) = image。shape[:2]

# 從輸入影象構造一個 blob,然後執行 YOLO 物件檢測器的前向傳遞,給我們邊界盒和相關機率

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))

blobFromImage 用於對影象進行預處理

cv2。dnn。blobFromImage(image[, scalefactor[, size[, mean[, swapRB[, crop[, ddepth]]]]]])

image:輸入影象

scalefactor:影象各通道數值的縮放比例

size:輸出影象的空間尺寸

mean:用於各通道減去的值,以降低光照的影響

swapRB:交換 RB 通道,預設為 False

crop:影象裁剪,預設為 False。當值為 True 時,先按比例縮放,然後從中心裁剪成 size 尺寸

ddepth:輸出的影象深度,可選 CV_32F 或者 CV_8U

資料提取

boxes = []

confidences = []

classIDs = []

# 迴圈提取每個輸出層

for output in layerOutputs:

# 迴圈提取每個框

for detection in output:

# 提取當前目標的類 ID 和置信度

scores = detection[5:]

classID = np。argmax(scores)

confidence = scores[classID]

# 透過確保檢測機率大於最小機率來過濾弱預測

if confidence > 0。5:

# 將邊界框座標相對於影象的大小進行縮放,YOLO 返回的是邊界框的中心(x, y)座標,

# 後面是邊界框的寬度和高度

box = detection[0:4] * np。array([W, H, W, H])

(centerX, centerY, width, height) = box。astype(“int”)

# 轉換出邊框左上角座標

x = int(centerX - (width / 2))

y = int(centerY - (height / 2))

# 更新邊界框座標、置信度和類 id 的列表

boxes。append([x, y, int(width), int(height)])

confidences。append(float(confidence))

classIDs。append(classID)

3 個列表內儲存的內容:

boxes:物件的邊界框

confidences :YOLO 分配給物件的置信度值,較低的置信度值表示該物件可能不是網路認為的物件。上面的程式碼中將過濾掉小於 0。5 閾值的物件

classIDs:檢測到的物件的類標籤

這樣每個被提取出的物件,都確定了標籤和區域座標就、位置。接下來就是在圖片中標記出來,便於我們觀看。

標記顯示

# 非最大值抑制,確定唯一邊框

idxs = cv2。dnn。NMSBoxes(boxes, confidences, 0。5, 0。3)

# 確定每個物件至少有一個框存在

if len(idxs) > 0:

# 迴圈畫出儲存的邊框

for i in idxs。flatten():

# 提取座標和寬度

(x, y) = (boxes[i][0], boxes[i][1])

(w, h) = (boxes[i][2], boxes[i][3])

# 畫出邊框和標籤

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)

對於每個物件,Yolo 會框出 3 個左右的區域,我們只需要顯示出最合適的區域。非最大值抑制,就是搜尋出局部最大值,將置信度最大的框儲存,其餘剔除。

cv2。dnn。NMSBoxes(bboxes, scores, score_threshold, nms_threshold, eta=None, top_k=None)

bboxes:一組邊框

scores:一組對應的置信度

score_threshold:置信度的閾值

nms_threshold:非最大抑制的閾值

之後將每個物件的方框和標籤都畫出來

結果展示:

OpenCV呼叫YOLOv4進行目標檢測!是真的強!

OpenCV呼叫YOLOv4進行目標檢測!是真的強!

完整程式碼

import numpy as np

import time

import cv2

LABELS = open(“coco。names”)。read()。strip()。split(“\n”)

np。random。seed(666)

COLORS = np。random。randint(0, 255, size=(len(LABELS), 3), dtype=“uint8”)

# 匯入 YOLO 配置和權重檔案並載入網路:

net = cv2。dnn_DetectionModel(‘yolov4。cfg’, ‘yolov4。weights’)

# 獲取 YOLO 未連線的輸出圖層

layer = net。getUnconnectedOutLayersNames()

image = cv2。imread(‘timg。jpg’)

# 獲取圖片尺寸

(H, W) = image。shape[:2]

# 從輸入影象構造一個 blob,然後執行 YOLO 物件檢測器的前向傳遞,給我們邊界盒和相關機率

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 = []

# 迴圈提取每個輸出層

for output in layerOutputs:

# 迴圈提取每個框

for detection in output:

# 提取當前目標的類 ID 和置信度

scores = detection[5:]

classID = np。argmax(scores)

confidence = scores[classID]

# 透過確保檢測機率大於最小機率來過濾弱預測

if confidence > 0。5:

# 將邊界框座標相對於影象的大小進行縮放,YOLO 返回的是邊界框的中心(x, y)座標,

# 後面是邊界框的寬度和高度

box = detection[0:4] * np。array([W, H, W, H])

(centerX, centerY, width, height) = box。astype(“int”)

# 轉換出邊框左上角座標

x = int(centerX - (width / 2))

y = int(centerY - (height / 2))

# 更新邊界框座標、置信度和類 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:

# 迴圈畫出儲存的邊框

for i in idxs。flatten():

# 提取座標和寬度

(x, y) = (boxes[i][0], boxes[i][1])

(w, h) = (boxes[i][2], boxes[i][3])

# 畫出邊框和標籤

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)

原始碼地址