在我們介紹目標(biāo)物體檢測(cè)算法時(shí),前期小編的文章也分享了很多目標(biāo)檢測(cè)算法,比如YOLO, Faster RCNN等,喜歡目標(biāo)檢測(cè)的小伙伴們可以參考往期的文章學(xué)習(xí),本期的文章代碼也 在往期文章中有較多的介紹。前幾天剛聽說YOLO V4的出現(xiàn)打破了YOLO系列作者不更新目標(biāo)檢測(cè)算法的新聞,突然又聽說YOLO V5已經(jīng)出現(xiàn),且檢測(cè)速度與精度有了較大的提高。不得不說現(xiàn)在的節(jié)奏太快,一不留神,我們就錯(cuò)過了很多。目標(biāo)檢測(cè)算法YOLO V3算是當(dāng)今最受大家喜歡,且檢測(cè)速度與精度都有很大的優(yōu)勢(shì),這里我們利用YOLO V3目標(biāo)檢測(cè)算法來進(jìn)行人物的檢測(cè),并計(jì)算人與人之間的距離
目標(biāo)檢測(cè)
首先我們建立一個(gè)目標(biāo)檢測(cè)函數(shù)來檢測(cè)人物
from scipy.spatial import distance as dist
import numpy as np
import cv2
import os
def detect_people(frame, net, ln, personIdx=0):
(H, W) = frame.shape[:2]
results = []
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layerOutputs = net.forward(ln)
boxes = []
centroids = []
confidences = []
from scipy.spatial import distance as dist歐拉距離,主要用于質(zhì)心之間的距離計(jì)算
detect_people(frame, net, ln, personIdx=0)這里接受四個(gè)參數(shù)
frame:從視頻幀中提取的圖片幀,用于后期的目標(biāo)檢測(cè)
net:基于yolo v3的目標(biāo)檢測(cè)算法的神經(jīng)網(wǎng)絡(luò)
ln:我們提取yolo v3輸出層的神經(jīng)網(wǎng)絡(luò),用于神經(jīng)網(wǎng)絡(luò)的前向傳播的輸入層,便于進(jìn)行目標(biāo)檢測(cè)
personIdx:神經(jīng)網(wǎng)絡(luò)檢測(cè)到人的目標(biāo)的索引
(H, W) = frame.shape[:2]:獲取視頻幀圖片的尺寸
blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416), swapRB=True, crop=False)
net.setInput(blob)
layerOutputs = net.forward(ln)
此三行代碼便是yolo v3目標(biāo)檢測(cè)算法的核心代碼了,我們計(jì)算圖片的blob值
放入神經(jīng)網(wǎng)絡(luò)進(jìn)行預(yù)測(cè),并把輸出層進(jìn)行反向傳播進(jìn)行目標(biāo)的預(yù)測(cè)
for output in layerOutputs:
for detection in output:
scores = detection[5:]
classID = np.argmax(scores)
confidence = scores[classID]
if classID == personIdx and confidence > 0.5:
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)])
centroids.append((centerX, centerY))
confidences.append(float(confidence))
神經(jīng)網(wǎng)絡(luò)檢測(cè)完成后,所有檢測(cè)結(jié)果放置在layerOutputs里面
通過for循環(huán)遍歷出每個(gè)目標(biāo)的置信度,我們只提取目標(biāo)為人且置信度大于0.5的目標(biāo),其它目標(biāo)直接忽略
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))
當(dāng)檢測(cè)到我們需要的目標(biāo)時(shí),我們記錄其目標(biāo)的中心(質(zhì)心)坐標(biāo)值以及目標(biāo)box,并保存
idxs = cv2.dnn.NMSBoxes(boxes, confidences, 0.3, 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])
r = (confidences[i], (x, y, x + w, y + h), centroids[i])
results.append(r)
return results
由于人在移動(dòng)過程中,很容易拍到的圖片2個(gè)人有重合的區(qū)域,這里使用非極大值抑制(NMS)算法,進(jìn)行目標(biāo)的低置信度的篩選
最后,我們把檢測(cè)到的目標(biāo)box,目標(biāo)質(zhì)心坐標(biāo),以及置信度保存到results中便于后期的運(yùn)算
初始化神經(jīng)網(wǎng)絡(luò)
labelsPath = os.path.sep.join(["yolo-coco", "coco.names"])
LABELS = open(labelsPath).read().strip().split("n")
weightsPath = os.path.sep.join(["yolo-coco", "yolov3.weights"])
configPath = os.path.sep.join(["yolo-coco", "yolov3.cfg"])
net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)
ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]
vs = cv2.VideoCapture("123.mp4")
#vs=cv2.VideoCapture(0)打開攝像頭
目標(biāo)檢測(cè)函數(shù)完成后,需要初始化神經(jīng)網(wǎng)絡(luò),這里直接使用opencv的dnn.readNetFromDarknet來加載yolo v3模型
ln = [ln[i[0] - 1] for i in
net.getUnconnectedOutLayers()]來提取神經(jīng)網(wǎng)絡(luò)的輸出層,為什么這里需要提取輸出層,小伙伴們可以參考往期文章
這里為了演示,直接打開一段視頻來進(jìn)行神經(jīng)網(wǎng)絡(luò)的檢測(cè)
進(jìn)行目標(biāo)檢測(cè),并計(jì)算目標(biāo)距離
while True:
# read the next frame from the file
(grabbed, frame) = vs.read()
# if the frame was not grabbed, then we have reached the end
# of the stream
if not grabbed:
break
# resize the frame and then detect people (and only people) in it
frame = imutils.resize(frame, width=700)
results = detect_people(frame, net, ln,personIdx=LABELS.index("person"))
# initialize the set of indexes that violate the minimum social
# distance
violate = set()
# ensure there are *at least* two people detections (required in
# order to compute our pairwise distance maps)
if len(results) >= 2:
# extract all centroids from the results and compute the
# Euclidean distances between all pairs of the centroids
centroids = np.array([r[2] for r in results])
D = dist.cdist(centroids, centroids, metric="euclidean")
# loop over the upper triangular of the distance matrix
for i in range(0, D.shape[0]):
for j in range(i + 1, D.shape[1]):
# check to see if the distance between any two
if D[i, j] < 50:
violate.add(i)
violate.add(j)
for (i, (prob, bbox, ce
(cX, cY) = centroid
color = (0, 255, 0)
if i in violate:
color = (0, 0, 255)
cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)
cv2.circle(frame, (cX, cY), 5, color, 1)
text = " Distancing: {}".format(len(violate))
cv2.putText(frame, text, (10, frame.shape[0] - 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.85, (0, 0, 255), 3)
if 1 > 0:
cv2.imshow("Frame", frame)
key = cv2.waitKey(1) & 0xFF
if key == ord("q"):
break
cv2.stop()
cv2.destroyAllwindows()
當(dāng)打開視頻后,實(shí)時(shí)提取視頻幀中的圖片,并resize圖片,這里為了進(jìn)行更快的目標(biāo)檢測(cè)
results = detect_people(frame, net, ln,personIdx=LABELS.index("person"))使用前面的目標(biāo)檢測(cè)函數(shù)進(jìn)行人物的目標(biāo)檢測(cè)
當(dāng)獲取了目標(biāo)信息后,我們要確保視頻幀中要多于2個(gè)人的存在,因?yàn)檫@樣距離計(jì)算才有意義
centroids = np.array([r[2] for r in results])
D = dist.cdist(centroids, centroids, metric="euclidean")
當(dāng)檢測(cè)到目標(biāo)后,我們提取所有目標(biāo)的質(zhì)心,并計(jì)算每個(gè)質(zhì)心之間的歐拉距離
for i in range(0, D.shape[0]):
for j in range(i + 1, D.shape[1]):
if D[i, j] < 50:
violate.add(i)
violate.add(j)
通過for循環(huán)來判斷是否存在質(zhì)心距離小于設(shè)置值的質(zhì)心,并記錄質(zhì)心的索引
for (i, (prob, bbox, centroid)) in enumerate(results):
(startX, startY, endX, endY) = bbox
(cX, cY) = centroid
color = (0, 255, 0)
if i in violate:
color = (0, 0, 255)
為了便于區(qū)分,當(dāng)2個(gè)質(zhì)心的間距小于設(shè)置值時(shí),我們更改為紅色顏色框,相反,其他的設(shè)置為綠色框
最后,實(shí)時(shí)把數(shù)據(jù)以及box顯示在視頻中
說在最后
本期主要使用yolo v3來實(shí)時(shí)進(jìn)行圖片幀的人物檢測(cè),并計(jì)算質(zhì)心的距離,這樣的方式導(dǎo)致了大量計(jì)算都是在神經(jīng)網(wǎng)絡(luò)的目標(biāo)檢測(cè)上,因?yàn)槊繋曨l都要進(jìn)行一次目標(biāo)的檢測(cè)與質(zhì)心的運(yùn)算
當(dāng)然你的電腦配置夠好的話,可以參考這樣的設(shè)計(jì)
我們這里提供另外一個(gè)方式,就是質(zhì)心追蹤與質(zhì)心運(yùn)算,感興趣的小伙伴可以參考小編的專欄
《打造屬于自己的天眼目標(biāo)追蹤系統(tǒng)》
本專欄詳細(xì)介紹了目標(biāo)的質(zhì)心追蹤與目標(biāo)的質(zhì)心距離運(yùn)算,以及其他更多的目標(biāo)追蹤技術(shù),由于我們采用目標(biāo)質(zhì)心追蹤算法,不在用大量的資源來進(jìn)行神經(jīng)網(wǎng)絡(luò)的檢測(cè),更好更快的來達(dá)到了我們的目的
通過質(zhì)心的目標(biāo)追蹤算法來搭配質(zhì)心距離的計(jì)算,能夠更好的運(yùn)行本期的代碼

專欄
作者:人工智能研究所