1 場(chǎng)景
YOLO全稱You Only Look Once,YOLO實(shí)現(xiàn)了自動(dòng)駕駛汽車等前沿技術(shù)中使用的實(shí)時(shí)對(duì)象檢測(cè)。
可以實(shí)現(xiàn)對(duì)圖像中的對(duì)象進(jìn)行識(shí)別和定位,如下效果:

1.png
這里不研究算法,只研究,在python環(huán)境下,如何使用yolo進(jìn)行圖像中物體的識(shí)別和定位。
2 官網(wǎng)
2.1 官方地址
YOLO使用相關(guān)網(wǎng)站如下:
github地址:
https://github.com/pjreddie/darknet
2.2 百度網(wǎng)盤(pán)
如下為作者在百度網(wǎng)盤(pán)中備份的相關(guān)文件(配置文件+演示文件):
鏈接:https://pan.baidu.com/s/1dsXTUB_MHAeEnPDeJBNvHg
提取碼:i8pm
3 版本
python:3.6.3
4 依賴
(1)安裝cv2依賴
pip install opencv-python
(2)安裝numpy依賴
pip install numpy
4 代碼
4.1 準(zhǔn)備
(1)創(chuàng)建yolo配置文件
創(chuàng)建配置文件夾:cfg
將配置文件下載后,拷貝到cfg配置文件中:
鏈接:https://pan.baidu.com/s/1x_xIPC19lQ8sAljXtZqWWg
提取碼:6w0x
(2)創(chuàng)建測(cè)試文件夾
測(cè)試文件夾:yoloSrc
輸出文件夾:yoloRes
4.2 引入依賴
import cv2
import numpy as np
import os
import time
4.3 定義函數(shù)
def yolo_detect(pathIn='',
pathOut=None,
label_path='cfg/coco.names',
config_path='cfg/yolov3.cfg',
weights_path='cfg/yolov3.weights',
confidence_thre=0.5,
nms_thre=0.3,
jpg_quality=80):
'''
pathIn:原始圖片的路徑
pathOut:結(jié)果圖片的路徑
label_path:類別標(biāo)簽文件的路徑
config_path:模型配置文件的路徑
weights_path:模型權(quán)重文件的路徑
confidence_thre:0-1,置信度(概率/打分)閾值,即保留概率大于這個(gè)值的邊界框,默認(rèn)為0.5
nms_thre:非極大值抑制的閾值,默認(rèn)為0.3
jpg_quality:設(shè)定輸出圖片的質(zhì)量,范圍為0到100,默認(rèn)為80,越大質(zhì)量越好
'''
# 加載類別標(biāo)簽文件
LABELS = open(label_path).read().strip().split("\n")
nclass = len(LABELS)
# 為每個(gè)類別的邊界框隨機(jī)匹配相應(yīng)顏色
np.random.seed(42)
COLORS = np.random.randint(0, 255, size=(nclass, 3), dtype='uint8')
# 載入圖片并獲取其維度
base_path = os.path.basename(pathIn)
img = cv2.imread(pathIn)
(H, W) = img.shape[:2]
# 加載模型配置和權(quán)重文件
print('從硬盤(pán)加載YOLO......')
net = cv2.dnn.readNetFromDarknet(config_path, weights_path)
# 獲取YOLO輸出層的名字
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# 將圖片構(gòu)建成一個(gè)blob,設(shè)置圖片尺寸,然后執(zhí)行一次
# YOLO前饋網(wǎng)絡(luò)計(jì)算,最終獲取邊界框和相應(yīng)概率
blob = cv2.dnn.blobFromImage(img, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
start = time.time()
layerOutputs = net.forward(ln)
end = time.time()
# 顯示預(yù)測(cè)所花費(fèi)時(shí)間
print('YOLO模型花費(fèi) {:.2f} 秒來(lái)預(yù)測(cè)一張圖片'.format(end - start))
# 初始化邊界框,置信度(概率)以及類別
boxes = []
confidences = []
classIDs = []
# 迭代每個(gè)輸出層,總共三個(gè)
for output in layerOutputs:
# 迭代每個(gè)檢測(cè)
for detection in output:
# 提取類別ID和置信度
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
# 只保留置信度大于某值的邊界框
if confidence > confidence_thre:
# 將邊界框的坐標(biāo)還原至與原圖片相匹配,記住YOLO返回的是
# 邊界框的中心坐標(biāo)以及邊界框的寬度和高度
box = detection[0:4] * np.array([W, H, W, H])
(centerX, centerY, width, height) = box.astype("int")
# 計(jì)算邊界框的左上角位置
x = int(centerX - (width / 2))
y = int(centerY - (height / 2))
# 更新邊界框,置信度(概率)以及類別
boxes.append([x, y, int(width), int(height)])
confidences.append(float(confidence))
classIDs.append(classID)
# 使用非極大值抑制方法抑制弱、重疊邊界框
idxs = cv2.dnn.NMSBoxes(boxes, confidences, confidence_thre, nms_thre)
# 確保至少一個(gè)邊界框
if len(idxs) > 0:
# 迭代每個(gè)邊界框
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(img, (x, y), (x + w, y + h), color, 2)
text = '{}: {:.3f}'.format(LABELS[classIDs[i]], confidences[i])
(text_w, text_h), baseline = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 2)
cv2.rectangle(img, (x, y - text_h - baseline), (x + text_w, y), color, -1)
cv2.putText(img, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0), 2)
# 輸出結(jié)果圖片
if pathOut is None:
cv2.imwrite('with_box_' + base_path, img, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality])
else:
cv2.imwrite(pathOut, img, [int(cv2.IMWRITE_JPEG_QUALITY), jpg_quality])
4.4 使用
if __name__ == '__main__':
yolo_detect('yoloSrc/trunk.jpg', 'yoloRes/trunk.jpg')
4.5 結(jié)果
輸出日志:
從硬盤(pán)加載YOLO......
YOLO模型花費(fèi) 1.75 秒來(lái)預(yù)測(cè)一張圖片
(1)原文件

trunk.jpg
(2)輸出結(jié)果
監(jiān)測(cè)結(jié)果為truck,后面的0.999為對(duì)象匹配度。

trunk-2.jpg