+-
利用YOLOV3检测算法来实现人物定位与距离计算,打造全球定位系统

在我们介绍目标物体检测算法时,前期小编的文章也分享了很多目标检测算法,比如YOLO, Faster RCNN等,喜欢目标检测的小伙伴们可以参考往期的文章学习,本期的文章代码也 在往期文章中有较多的介绍。前几天刚听说YOLO V4的出现打破了YOLO系列作者不更新目标检测算法的新闻,突然又听说YOLO V5已经出现,且检测速度与精度有了较大的提高。不得不说现在的节奏太快,一不留神,我们就错过了很多。目标检测算法YOLO V3算是当今最受大家喜欢,且检测速度与精度都有很大的优势,这里我们利用YOLO V3目标检测算法来进行人物的检测,并计算人与人之间的距离

目标检测

首先我们创建一个目标检测函数来检测人物

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欧拉距离,主要用于质心之间的距离计算

detect_people(frame, net, ln, personIdx=0)这里接受四个参数

frame:从视频帧中提取的图片帧,用于后期的目标检测

net:基于yolo v3的目标检测算法的神经网络

ln:我们提取yolo v3输出层的神经网络,用于神经网络的前向传播的输入层,便于进行目标检测

personIdx:神经网络检测到人的目标的索引

(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目标检测算法的核心代码了,我们计算图片的blob值

放入神经网络进行预测,并把输出层进行反向传播进行目标的预测

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

神经网络检测完成后,所有检测结果放置在layerOutputs里面

通过for循环遍历出每个目标的置信度,我们只提取目标为人且置信度大于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))

当检测到我们需要的目标时,我们记录其目标的中心(质心)坐标值以及目标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

由于人在移动过程中,很容易拍到的图片2个人有重合的区域,这里使用非极大值抑制(NMS)算法,进行目标的低置信度的筛选

最后,我们把检测到的目标box,目标质心坐标,以及置信度保存到results中便于后期的运算

初始化神经网络

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)打开摄像头

目标检测函数完成后,需要初始化神经网络,这里直接使用opencv的dnn.readNetFromDarknet来加载yolo v3模型

ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]来提取神经网络的输出层,为什么这里需要提取输出层,小伙伴们可以参考往期文章

这里为了演示,直接打开一段视频来进行神经网络的检测

进行目标检测,并计算目标距离

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

当打开视频后,实时提取视频帧中的图片,并resize图片,这里为了进行更快的目标检测

results = detect_people(frame, net, ln,personIdx=LABELS.index("person"))使用前面的目标检测函数进行人物的目标检测

当获取了目标信息后,我们要确保视频帧中要多于2个人的存在,因为这样距离计算才有意义

centroids = np.array([r[2] for r in results]) D = dist.cdist(centroids, centroids, metric="euclidean")

当检测到目标后,我们提取所有目标的质心,并计算每个质心之间的欧拉距离

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循环来判断是否存在质心距离小于设置值的质心,并记录质心的索引

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)

为了便于区分,当2个质心的间距小于设置值时,我们更改为红色颜色框,相反,其他的设置为绿色框

最后,实时把数据以及box显示在视频中

说在最后

本期主要使用yolo v3来实时进行图片帧的人物检测,并计算质心的距离,这样的方式导致了大量计算都是在神经网络的目标检测上,因为每帧视频都要进行一次目标的检测与质心的运算

当然你的电脑配置够好的话,可以参考这样的设计

我们这里提供另外一个方式,就是质心追踪与质心运算,感兴趣的小伙伴可以参考小编的专栏

《打造属于自己的天眼目标追踪系统》

本专栏详细介绍了目标的质心追踪与目标的质心距离运算,以及其他更多的目标追踪技术,由于我们采用目标质心追踪算法,不在用大量的资源来进行神经网络的检测,更好更快的来达到了我们的目的

通过质心的目标追踪算法来搭配质心距离的计算,能够更好的运行本期的代码

...