如今,“图像分类”、“目标检测”、“语义分割”、“实例分割”和“目标追踪”等5大领域是计算机视觉的热门应用。其中“图像分类”与“目标检测”是最基础的应用,在此基础上,派生出了“语义分割”、“实例分割”和“目标跟踪”等相对高级的应用。
一、基于目标检测的追踪概述
基于目标检测的目标追踪方法(Tracking By Detecting,简称TBD)一般使用目标检测模型(如YOLO),在每个视频帧上进行目标检测,然后将检测出来的目标进行关联,找到每个目标的运行轨迹。如图1所示,先使用目标检测模型检测出7个目标,然后通过算法,将
和
进行关联,从而追踪到这两个足球的运行轨迹。
图1 基于目标检测的目标追踪方法
TBD方法完整的流程如图2所示,该方法共有5个步骤,其中最关键的是“目标检测”和“目标关联”两个步骤,“目标检测”需要一个训练好的目标检测模型,用来发现图像中的各个目标,“目标关联”需要一个关联算法,用来进行目标的配对。
(1)目标检测,检测出要追踪目标的位置坐标、目标分类等信息,初始化每个目标的轨迹。
(2)目标关联,使用算法,给当前帧中的目标和前一帧的目标进行配对。
(3)关联成功,在上一帧中找到了当前帧中检测到的目标,配对成功,记录目标的轨迹。
(4)新出现目标,在上一帧中没有找到当前帧中检测到的目标,初始化新目标的轨迹。
(5)目标消失,在当前帧中没有找到上一帧中检测出来的目标,删除该目标的轨迹。
图2 基于目标检测的目标追踪方法(TBD)流程图
在基于目标检测的目标追踪方法中,为了实现目标的关联,容易想到的方法是“通过目标识别进行目标关联”:对每一帧图像进行目标检测,然后对每一个目标提取特征,通过特征识别出每一个目标,从而实现目标关联。
但是,“通过目标识别进行目标关联”需要在每一帧图像中,提取出每一个目标的特征,这需要大量的计算资源,同时还需要稳定的特征提取器,在实际场景中很难做到,因此,通常采用其他方法进行目标的关联,如常用的质心法。
二、使用质心法进行目标关联
质心法是一种基于目标检测的目标追踪方法,只在目标首次出现的时候,对目标进行识别,在后续的视频帧中,通过欧氏距离将检测到的目标进行关联,如图3所示。
(1)目标检测,使用深度学习模型,对视频帧进行目标检测。
(2)计算质心坐标,使用目标预测框的中心点作为质心坐标。
(3)计算质心距离,计算视频的上一帧和当前帧中目标之间的欧式距离。
(4)目标关联,距离相近的为同一目标,如A和C是同一目标,B是新出现目标。
(5)目标更新,更新已知目标的坐标,生成新目标ID,如果有目标消失,则注销消失目标ID。
图3 使用质心法实现目标关联
三、质心法使用示例
质心法是目标关联算法,在进行目标追踪时,还需要配合目标检测模型使用,下面代码使用YOLO模型进行目标检测(已经在coco数据集上训练好的YOLO模型),使用质心法进行目标关联,实现目标的追踪。
在以下代码中,详细介绍了两帧图像中的目标(足球)的追踪过程,在本书配套的源代码中,还演示了对视频中的目标进行追踪的方法。
(1)导入库用到的库(在配套代码目录下的yolo_detect.py文件里,封装了YOLO模型的使用)
代码语言:javascript复制1 import cv2,math
2 import numpy as np
3 import IPython.display as display
4 from yolo_detect import Init_Yolo,Detect,Draw #封装YOLO模型的检测操作
5 from matplotlib import pyplot as plt
6 plt.rcParams['font.sans-serif']=['SimHei'] #在统计图上显示中文
(2)初始化YOLO模型(模型的初始化方法请查看yolo_detect.py文件中的Init_Yolo函数)。
代码语言:javascript复制1 model,labels = Init_Yolo('./models/yolov3-tiny.cfg',
2 './models/yolov3-tiny.weights',
3 './models/coco.names')
(3)读取两帧图像,并转换为RGB格式,其中frame_1是上一帧图像,frame_2是当前帧图像。
代码语言:javascript复制 1 frame_1 = cv2.imread('./images/ball_1.png')
2 frame_1 = cv2.cvtColor(frame_1, cv2.COLOR_BGR2RGB)
3 frame_2 = cv2.imread('./images/ball_2.png')
4 frame_2 = cv2.cvtColor(frame_2, cv2.COLOR_BGR2RGB)
(4)检测两帧图像中的足球目标(调用yolo_detect.py文件中的Detect函数)。
代码语言:javascript复制1 #使用YOLO检测两帧图像中的目标
2 b1 = Detect(model,labels,frame_1)
3 b2 = Detect(model,labels,frame_2)
4 #只保留足球的检测结果
5 filter=np.where(b1[:,-1]=='sports ball')
6 bbox1 = b1[filter]
7 filter=np.where(b2[:,-1]=='sports ball')
8 bbox2 = b2[filter]
(5)计算质心坐标,根据第4步检测结果bbox1和bbox2,计算目标的质心(即绑定框的中心)。
代码语言:javascript复制1 A = (int(bbox1[0][0]) int(bbox1[0][2])/2,int(bbox1[0][1]) int(bbox1[0][3])/2)
2 B = (int(bbox2[0][0]) int(bbox2[0][2])/2,int(bbox2[0][1]) int(bbox2[0][3])/2)
3 C = (int(bbox2[1][0]) int(bbox2[1][2])/2,int(bbox2[1][1]) int(bbox2[1][3])/2)
4 print("第一帧目标A",A,"第二帧目标B",B,"第二帧目标C",C)
使用第4和第5步代码,在第一帧图像中检测到目标A,在第二帧图像中检测到目标B和C,并分别计算这3个目标的质心。如图4所示,图中白色边框为检测到的目标边界框,中间的绿点为目标的质心(即边界框的中心)。
图4 检测到的目标与质心
(6)计算第一帧中的目标和后一帧中目标的欧氏距离,根据最近距离,确定AB是同一目标。
代码语言:javascript复制 1 AB = math.sqrt(math.pow((A[0]-B[0]),2) math.pow((A[1]-B[1]),2))
2 AC = math.sqrt(math.pow((A[0]-C[0]),2) math.pow((A[1]-C[1]),2))
3 print("AB距离",AB,"AC距离",AC,"AB是同一目标")
(7)显示追踪的结果,将两帧图像合并到一起,用连线表示目标的运行轨迹,如图5所示。
代码语言:javascript复制 1 mask1 = Draw(frame_1,bbox1) #绘制在第一帧中检测到的目标
2 mask2 = Draw(frame_2,bbox2) #绘制在第二帧中检测到的目标
3 all_img = np.hstack((mask1, mask2)) #将两帧图像合并成一幅图像
4 #绘制运动轨迹
5 H,W = mask1.shape[:2]
6 cv2.line(all_img,(int(A[0]),int(A[1])),(W int(C[0]),int(C[1])),(0,255,255),2)
7 ##显示追踪结果
8 plt.title('目标运行轨迹')
9 plt.imshow(all_img)
图5 目标的运行轨迹
本文章出自北京理工大学出版社《深度学习与计算机视觉:核心算法与应用》一书中,经授权此公号,略有修改,经出版纸质书为准。