YOLO 目標檢測實戰(zhàn)項目『體驗篇』
什么是目標檢測
目標檢測(Object Detection)的任務是找出圖像中所有感興趣的目標(物體),確定它們的類別和位置,是計算機視覺領域的核心問題之一。由于各類物體有不同的外觀、形狀和姿態(tài),加上成像時光照、遮擋等因素的干擾,目標檢測一直是計算機視覺領域最具有挑戰(zhàn)性的問題。
計算機視覺中關于圖像識別有四大類任務:
分類 - Classification:解決 “是什么?” 的問題,即給定一張圖片或一段視頻判斷里面包含什么類別的目標。
定位 - Location:解決 “在哪里?” 的問題,即定位出這個目標的的位置。
檢測 - Detection:解決 “是什么?在哪里?” 的問題,即定位出這個目標的的位置并且知道目標物是什么。
分割 - Segmentation:分為實例的分割(Instance-level)和場景分割(Scene-level),解決 “每一個像素屬于哪個目標物或場景” 的問題。
目標檢測初體驗
當前基于深度學習的目標檢測算法主要分為兩類:
- 1.Two stage 目標檢測算法:R-CNN、SPP-Net、Fast R-CNN、Faster R-CNN 和 R-FCN 等。
- 2.One stage 目標檢測算法:OverFeat、YOLOv1、YOLOv2、 YOLOv3、SSD 和 RetinaNet 等。
在本文中,我們將使用 YOLOv3 在檢測圖像類別的位置及名稱。
我們將使用 Darknet (是一個用 C 和 CUDA 編寫的開源神經網絡框架。它快速,易于安裝,并支持 CPU 和 GPU 計算。)、 OpenCV 在 3.3.1 版本中開始支持 Darknet,我們在 Darknet 框架下訓練出來的模型,通過 OpenCV 讀取模型,從而進行預測。
在這里,我們假設大家沒有目標檢測的知識,只是想體驗一下目標檢測做出來的效果,有個大致的概念。為滿足一下大家的好奇心,我們將從 Darknet 官網上(https://pjreddie.com/darknet/yolo/)下載官方已經訓練好的 YOLOv3 模型,直接讀取模型做目標檢測。
首先,看一下我們的目錄結構
└─ root
│ code.py # 預測的代碼
├─ cfg # 目標檢測模型的配置文件
│ coco.names # 各個類別的名稱
│ yolov3_coco.cfg # 目標檢測網絡的結構
│ yolov3_coco.weights # 目標檢測模型的權重
│
├─ result_imgs # 測試圖片結果保存
│ test1.jpg
│ test2.jpg
│ test3.jpg
│ test4.jpg
│
└─ test_imgs # 測試圖片
test1.jpg
test2.jpg
test3.jpg
test4.jpg
接下來上我們的代碼:
# -*- coding: utf-8 -*-
# 載入所需庫
import cv2
import numpy as np
import os
import time
def yolo_detect(pathIn='',
pathOut=None,
label_path='./cfg/coco.names',
config_path='./cfg/yolov3_coco.cfg',
weights_path='./cfg/yolov3_coco.weights',
confidence_thre=0.5,
nms_thre=0.3,
jpg_quality=80):
'''
pathIn:原始圖片的路徑
pathOut:結果圖片的路徑
label_path:類別標簽文件的路徑
config_path:模型配置文件的路徑
weights_path:模型權重文件的路徑
confidence_thre:0-1,置信度(概率/打分)閾值,即保留概率大于這個值的邊界框,默認為0.5
nms_thre:非極大值抑制的閾值,默認為0.3
jpg_quality:設定輸出圖片的質量,范圍為0到100,默認為80,越大質量越好
'''
# 加載類別標簽文件
LABELS = open(label_path).read().strip().split("\n")
nclass = len(LABELS)
# 為每個類別的邊界框隨機匹配相應顏色
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]
# 加載模型配置和權重文件
print('從硬盤加載YOLO......')
net = cv2.dnn.readNetFromDarknet(config_path, weights_path)
# 獲取YOLO輸出層的名字
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
# 將圖片構建成一個blob,設置圖片尺寸,然后執(zhí)行一次
# YOLO前饋網絡計算,最終獲取邊界框和相應概率
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()
# 顯示預測所花費時間
print('YOLO模型花費 {:.2f} 秒來預測一張圖片'.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 > confidence_thre:
# 將邊界框的坐標還原至與原圖片相匹配,記住YOLO返回的是
# 邊界框的中心坐標以及邊界框的寬度和高度
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))
# 更新邊界框,置信度(概率)以及類別
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)
# 確保至少一個邊界框
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(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)
# 輸出結果圖片
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])
## 測試
pathIn = './test_imgs/test1.jpg'
pathOut = './result_imgs/test1.jpg'
yolo_detect(pathIn,pathOut)
運行結果如下:
以上源碼可在 https://github.com/FLyingLSJ/Computer_Vision_Project 查看
目標檢測的文章將會分為以下幾個板塊逐步更新
- 目標檢測實戰(zhàn)項目『體驗篇』
- 目標檢測實戰(zhàn)項目『訓練自己的數據』
- 目標檢測實戰(zhàn)項目『原理篇』
從項目到理論,更有趣味!