问题描述
这是我大学四年级时,在一家计算机视觉公司实习期间自己想出来的一个算法,感觉超好用,就记录下来了,供大家和以后的自己参考。
其实我本来做的是基于深度学习的目标检测+目标分类算法。也就是先检测到物体,然后对物体进行分类识别。如下图所示。
在对视频流进行检测时,上述算法需要对获取的每一帧都进行目标检测+目标分类,如下图所示。
这样就会导致一个问题:重复多次无用的识别。
什么叫重复多次无用的识别?就是我们在视频的第一帧已经检测到目标物体,并且对目标物体进行识别了,假设第一帧的识别结果已经很好了,那么在第二帧的时候,其实我们是没必要再去进行目标识别的,只需要想办法把第一帧识别出来的结果直接赋给第二帧相应的目标即可。因为识别算法一般都是用深度学习,重复识别是非常耗时耗算力的,如果能通过一种简单的方法去跟踪前后两帧的目标,正确地传递分类结果,那么算法的推理速度将成倍增长。也就是说,我们要将算法设计成如下图所示的样子。
所以问题的关键在于:如何判断当前这一帧图像里检测到的目标是不是前面一帧已经检测过的目标,也就是如何去跟踪目标,也就是本文的核心所在:利用IOU去跟踪目标。
算法原理
IOU算法的原理很简单,它的中文名字就叫交并比,故名思意,两个集合的交除以两个集合的并,用这个来判断两个集合的重合度再适合不过了。
由于在几乎所有的目标检测算法中,都会给目标画一个矩形框,这个矩形框的大小和位置由左上角和右下角的坐标决定,大概如下图所示。
正是因为有这些矩形框,才给了我们计算IOU的机会,我们可以把前后两帧图片里的目标框之间都计算一下IOU,当IOU大于0.5时,我们就可以认为这两个目标框标定的是同一个目标,就可以把前一帧目标框的分类结果直接赋值给后一帧的目标框了,是不是很简单啊。
所以接下来的问题就是如何计算两个目标框的IOU了。其实很简单,其实很自然,两个框之间的IOU由两个框的坐标来算。如下图所示。
IOU的计算程序如下:
def IOU(A,B):
W = min(A[2], B[2]) - max(A[0], B[0])
H = min(A[3], B[3]) - max(A[1], B[1])
if W <= 0 or H <= 0:
return 0;
SA = (A[2] - A[0]) * (A[3] - A[1])
SB = (B[2] - B[0]) * (B[3] - B[1])
cross = W * H
return cross/(SA + SB - cross)
算法实现
下面是整个算法的逻辑流程,用python语言结合简体中文表述的,也不知道这样能不能帮助大家理解。
#-----------------------------------------------------------------------#
#这个程序文件所需要的依赖项
import cv2
#------------------------------------------------------------------------#
FrontFrames=[] #用来记录前一帧的目标框
FrontFrame_data_queding={} #用来记录前一帧目标框的分类结果
capture=cv2.VideoCapture(0) #调用摄像头
while True:
#------------------------------------------------------------------------------------------------------#
#从视频中读取某一帧,并进行处理
ref,frame=capture.read()
#------------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------------#
#利用深度学习进行目标检测得到目标框
det_boxes=目标框
#------------------------------------------------------------------------------------------------------#
if FrontFrames != []:
i=0 #记录目标框的分类结果要用的
FrontFrame_data={}
for det_boxe in det_boxes: #获取一个个目标框
hh=0 #用于判断目标框是不是新产生的
j=0 #用于抽取FrontFrame_data_queding中的分类信息。
for FrontFrame in FrontFrames:
if IOU(det_boxe,FrontFrame) > 0.5: #计算IOU
good_datas=FrontFrame_data_queding[j]
if good_datas[置信度] > 0.90: #这一步是判断前一帧分类结果的置信度,可以用这个来筛选置信度大的类。
FrontFrame_data[i]=good_datas
hh=1
j=j+1
if hh==0: #hh==0说明上一个if语句没有执行成功,代表这个目标第一次进入监控视频流。
#--------------------------------------------------------------------------------------------------#
#用分类算法对新进来的框进行分类得到分类结果
#--------------------------------------------------------------------------------------------------#
#--------------------------------------------------------------------------------------------------#
#将分类结果记录下来,用于下一帧的判断
FrontFrame_data[i]=分类结果
#--------------------------------------------------------------------------------------------------#
i=i+1
FrontFrames=det_boxes
FrontFrame_data_queding=FrontFrame_data
else: #说明是监控视频流的第一帧
#------------------------------------------------------------------------------------------------------#
FrontFrames=det_boxes
i=0
#------------------------------------------------------------------------------------------------------#
for det_boxe in det_boxes:
#--------------------------------------------------------------------------------------------------#
#用分类算法对第一帧的框进行分类,得到分类结果
#--------------------------------------------------------------------------------------------------#
#--------------------------------------------------------------------------------------------------#
#记录每个框的结果
FrontFrame_data_queding[i]=分类结果
i=i+1
#--------------------------------------------------------------------------------------------------#
#------------------------------------------------------------------------------------------------#
#画图或者干点其他的事
#------------------------------------------------------------------------------------------------#
算法的优缺点总结
优点:
- 能够很大程度提高整个算法的运行速度,避免重复无用的识别
- 能够筛选出置信度高的分类结果,忽视掉不好的分类结果
- 目标跟踪的准确率几乎只取决于目标检测的准确率
- 目标跟踪的环境可以很复杂
缺点:
- 需要和一个准确度高目标检测算法搭配使用。