本文章先介绍对象跟踪过程,考虑对象跟踪的特点决定使用:质心跟踪算法,然后会一步一步说明质心跟踪算法的实现;最后是如何用python代码实现。

实验效果如下:

对象跟踪过程

  1. 进行一组初始的对象检测(如:边界框坐标的输入集)
  2. 为每个初始检测创建唯一的ID(每个独立对象有唯一的ID)
  3. 然后跟踪每个对象在视频中的帧中移动时的情况,并保持唯一ID的分配

补充第二点:对象跟踪允许我们将唯一的ID应用于每个被跟踪的对象,从而使我们能够对视频中的唯一对象进行计数。

好了下一步我们应该考虑对象跟踪算法的特点。

对象跟踪算法的特点(理想下)

  • 仅要求对象检测阶段一次(即,最初检测到对象时)
  • 将是非常快- 比实际运行的物体探测器本身更快
  • 能够处理被跟踪对象何时“消失”或移动到视频帧的边界之外
  • 遮挡力强
  • 能够拾取帧之间“丢失”的对象

不妨使用OpenCV实现质心跟踪,OpenCV是一种易于理解但非常有效的跟踪算法。

质心跟踪依赖于

(1)现有对象质心(即检测出对象,然后计算对象的质心)

(2)实时图像数据连续帧之间,新对象质心之间的欧氏距离(EUCLIDEAN DISTAN)

备注:如果对欧氏距离不了解的可以到文章底部看看。

质心跟踪算法实现

步骤1:接受边界框坐标并计算质心

图1:要使用质心跟踪构建简单的对象跟踪算法,第一步是接受来自对象检测器的边界框坐标,然后使用它们来计算质心。

质心追踪算法假定我们传递一组边界框的(X,Y)坐标-对于每个检测到的对象的每一个帧

1)这些边界框可以由大家想要的任何类型的对象检测器生成(颜色阈值+轮廓提取,Haar级联,HOG +线性SVM,SSD,Faster R-CNN等),前提是要针对帧中的每一帧进行计算视频。

2)有了边界框坐标后,我们必须计算“质心”或更简单地计算边界框的中心(x,y)坐标。 上面的图1演示了接受一组边界框坐标并计算质心。

3)由于这些是提供给我们算法的边界框的第一组初始集合,因此我们将为其分配唯一的ID。

步骤2:计算新边界框与现有对象之间的欧氏距离(EUCLIDEAN DISTAN)

图2:此图像中存在三个对象,用于使用Python和OpenCV进行简单的对象跟踪。我们需要计算每对原始质心(紫)和新质心(黄)之间的欧氏距离(EUCLIDEAN DISTAN)。

可能你会疑惑,为什么下面说一共检测到了三个对象,图中就有5个质心了?

答:本来是有两个对象(其质心为紫色),当下一帧数据时,这两个对象移动了,原来的质心位置自然也会改变的,会产生新的质心(黄色的);于是在原来两个紫色质心,由于原对象移动,产生两个新质心(黄色),再加上一个新对象的质心,就变成了3个黄色质心+2个紫色质心。

对于视频流中的每个后续帧,我们应用计算对象质心的步骤#1但是,我们首先需要确定是否可以将新的对象质心(黄色)与旧的对象质心(紫色)相关联,而不是为每个检测到的对象分配新的唯一ID(这会破坏对象跟踪的目的)。为了完成此过程,我们计算了每对现有对象质心和输入对象质心之间的欧氏距离(EUCLIDEAN DISTAN)(用绿色箭头突出显示)。

图2中可以看到,这次我们在图像中检测到三个对象。靠近的两对是两个现有对象。

其实这里简单来说,通过计算原始质心(黄色)和新质心(紫色)之间的欧氏距离(EUCLIDEAN DISTAN)后,计算出最小值的(箭头最短),是指向原来的对象;步骤3会进一步将的。

步骤#3:更新(x,y) -现有对象的坐标

图3:我们的简单质心对象跟踪方法将关联的对象的对象距离最小化。但是,我们该如何处理左下角的对象呢?

质心跟踪算法的主要假设是一个给定的对象将潜在地移动在后续的帧之间,但距离为帧中的质心之间比对象之间的所有其它距离。

因此,如果我们选择将质心与后续帧之间的最小距离相关联,则可以构建对象跟踪器。

图3中,大家可以看到我们的质心跟踪器算法如何选择将最小化其欧氏距离(EUCLIDEAN DISTAN)的质心关联起来。

但是左下角的孤独点呢?

它没有任何关联-我们如何处理它?

步骤4:注册新对象

图4:在使用Python和OpenCV进行对象跟踪的示例中,我们有一个与现有对象不匹配的新对象,因此将其注册为对象ID#3。

如果输入检测的数量多于被跟踪的现有对象,则我们需要注册新对象。“注册”仅表示通过以下方式将新对象添加到跟踪对象列表中:

  1. 给它分配一个新的对象ID
  2. 存储该对象的边界框坐标的质心

然后,我们可以返回到步骤2,并为视频流中的每个帧重复步骤流水线。

图4演示了使用最小欧氏距离(EUCLIDEAN DISTAN)关联现有对象ID,然后注册新对象的过程。

步骤5:注销旧对象

任何合理的对象跟踪算法都必须能够处理对象丢失,消失或离开视野时的情况。

实际情况下,您如何处理这些情况实际上取决于对象跟踪器的部署位置,但是对于此实现,我们将在旧对象无法与任何现有对象匹配的情况下(总共N个后续帧)注销旧对象。

质心跟踪代码实现:centroidtracker.py

# import the necessary packages
from scipy.spatial import distance as dist
from collections import OrderedDict
import numpy as npclass CentroidTracker():def __init__(self, maxDisappeared=50):self.nextObjectID = 0self.objects = OrderedDict()self.disappeared = OrderedDict()#存储给定对象被允许标记为“消失”的最大连续帧数,直到我们需要从跟踪中注销该对象self.maxDisappeared = maxDisappeareddef register(self, centroid):#注册对象时,我们使用下一个可用的对象ID来存储质心self.objects[self.nextObjectID] = centroidself.disappeared[self.nextObjectID] = 0self.nextObjectID += 1def deregister(self, objectID):#要注销注册对象ID,我们从两个字典中都删除了该对象IDdel self.objects[objectID]del self.disappeared[objectID]def update(self, rects):# 检查输入边界框矩形的列表是否为空if len(rects) == 0:#遍历任何现有的跟踪对象并将其标记为消失for objectID in list(self.disappeared.keys()):self.disappeared[objectID] += 1#如果达到给定对象被标记为丢失的最大连续帧数,请取消注册if self.disappeared[objectID] > self.maxDisappeared:self.deregister(objectID)#由于没有质心或跟踪信息要更新,请尽早返回return self.objects# 初始化当前帧的输入质心数组inputCentroids = np.zeros((len(rects), 2), dtype="int")#在边界框矩形上循环for (i, (startX, startY, endX, endY)) in enumerate(rects):# use the bounding box coordinates to derive the centroidcX = int((startX + endX) / 2.0)cY = int((startY + endY) / 2.0)inputCentroids[i] = (cX, cY)#如果我们当前未跟踪任何对象,请输入输入质心并注册每个质心if len(self.objects) == 0:for i in range(0, len(inputCentroids)):self.register(inputCentroids[i])#否则,当前正在跟踪对象,因此我们需要尝试将输入质心与现有对象质心进行匹配else:#抓取一组对象ID和相应的质心objectIDs = list(self.objects.keys())objectCentroids = list(self.objects.values())#分别计算每对对象质心和输入质心之间的距离-我们的目标是将输入质心与现有对象质心匹配D = dist.cdist(np.array(objectCentroids), inputCentroids)#为了执行此匹配,我们必须(1)在每行中找到最小值,然后(2)根据行索引的最小值对行索引进行排序,以使具有最小值的行位于索引列表的* front *处rows = D.min(axis=1).argsort()#接下来,我们在列上执行类似的过程,方法是在每一列中找到最小值,然后使用先前计算的行索引列表进行排序cols = D.argmin(axis=1)[rows]# 为了确定是否需要更新,注册或注销对象,我们需要跟踪已经检查过的行索引和列索引usedRows = set()usedCols = set()#循环遍历(行,列)索引元组的组合for (row, col) in zip(rows, cols):#如果我们之前已经检查过行或列的值,请忽略它if row in usedRows or col in usedCols:continue#否则,获取当前行的对象ID,设置其新的质心,然后重置消失的计数器objectID = objectIDs[row]self.objects[objectID] = inputCentroids[col]self.disappeared[objectID] = 0#表示我们已经分别检查了行索引和列索引usedRows.add(row)usedCols.add(col)#计算我们尚未检查的行和列索引unusedRows = set(range(0, D.shape[0])).difference(usedRows)unusedCols = set(range(0, D.shape[1])).difference(usedCols)#如果对象质心的数量等于或大于输入质心的数量#我们需要检查一下其中的某些对象是否已潜在消失if D.shape[0] >= D.shape[1]:# loop over the unused row indexesfor row in unusedRows:#抓取相应行索引的对象ID并增加消失的计数器objectID = objectIDs[row]self.disappeared[objectID] += 1#检查是否已将该对象标记为“消失”的连续帧数以用于注销该对象的手令if self.disappeared[objectID] > self.maxDisappeared:self.deregister(objectID)#否则,如果输入质心的数量大于现有对象质心的数量,我们需要将每个新的输入质心注册为可跟踪对象else:for col in unusedCols:self.register(inputCentroids[col])# return the set of trackable objectsreturn self.objects

主函数代码实验:object_tracker.py

# 执行程序,运行如下命令
# python object_tracker.py --prototxt deploy.prototxt --model res10_300x300_ssd_iter_140000.caffemodel
# 导入必要的软件包
from centroidtracker import CentroidTracker
from imutils.video import VideoStream
import numpy as np
import argparse
import imutils
import time
import cv2
# 构造参数解析并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-p", "--prototxt", required=True,help="path to Caffe 'deploy' prototxt file")
ap.add_argument("-m", "--model", required=True,help="path to Caffe pre-trained model")
ap.add_argument("-c", "--confidence", type=float, default=0.5,help="minimum probability to filter weak detections")
args = vars(ap.parse_args())
# 初始化质心跟踪器和框架尺寸
ct = CentroidTracker()
(H, W) = (None, None)
# 从磁盘加载我们的检测人脸的模型
print("[INFO] loading model...")
net = cv2.dnn.readNetFromCaffe(args["prototxt"], args["model"])
# 初始化视频流并允许相机传感器预热
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
time.sleep(2.0)
# 循环播放图像流中的帧
while True:# 从视频流中读取下一帧并调整其大小frame = vs.read()frame = imutils.resize(frame, width=600)# 如果帧中尺寸为“无”,则抓住它们if W is None or H is None:(H, W) = frame.shape[:2]#从帧中构造一个Blob,将其通过网络,#获取输出预测,并初始化边界框矩形的列表blob = cv2.dnn.blobFromImage(frame, 1.0, (W, H),(104.0, 177.0, 123.0))net.setInput(blob)detections = net.forward()rects = []#循环检测for i in range(0, detections.shape[2]):#通过确保预测的概率大于最小阈值来过滤掉弱检测if detections[0, 0, i, 2] > args["confidence"]:# 计算对象边界框的(x,y)坐标,然后更新边界框矩形列表box = detections[0, 0, i, 3:7] * np.array([W, H, W, H])rects.append(box.astype("int"))# 在对象周围画一个边界框,以便我们可视化它(startX, startY, endX, endY) = box.astype("int")cv2.rectangle(frame, (startX, startY), (endX, endY),(0, 255, 0), 2)# 使用边界框矩形的计算集更新质心跟踪器objects = ct.update(rects)# 循环跟踪对象for (objectID, centroid) in objects.items():# 在输出帧上绘制对象的ID和对象的质心text = "ID {}".format(objectID)cv2.putText(frame, text, (centroid[0] - 10, centroid[1] - 10),cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)cv2.circle(frame, (centroid[0], centroid[1]), 4, (0, 255, 0), -1)# 显示输出画面cv2.imshow("Frame", frame)key = cv2.waitKey(1) & 0xFF# 如果按下“ q”键,则退出循环if key == ord("q"):break
cv2.destroyAllWindows()
vs.stop()

执行程序

实验环境:pyCharm中安装了opencv3.4,和一些基本库(NumPy,SciPy 和 imutils)

pip install numpy scipy imutils              #执行此命令进行安装

执行命令:python object_tracker.py   --prototxt deploy.prototxt    --model res10_300x300_ssd_iter_140000.caffemodel

注意:这里需要指定的两个参数文件 deploy.prototxt 为检测人脸时的配置(基于opencv深度学习)

res10_300x300_ssd_iter_140000.caffemodel 为检测人脸的模型,可以直接使用(在文章后面会给大家下载)

在pyCharm的命令窗口中执行:

实验效果:

文章中代码,放到网盘了,有需要可以去提取。

链接: https://pan.baidu.com/s/1h13-FPlnP2JyikHGesQRUA   提取码: erd4

备注:本程序只给大家学习研究,请不要作为商业用途,大家加油。


补充一下 欧氏距离(EUCLIDEAN DISTANCE)

欧氏距离定义: 欧氏距离( Euclidean distance)是一个通常采用的距离定义,它是在m维空间中两个点之间的真实距离。

在二维和三维空间中的欧式距离的就是两点之间的距离,二维的公式是
d = sqrt((x1-x2)^+(y1-y2)^)

三维的公式是
d=sqrt(x1-x2)^+(y1-y2)^+(z1-z2)^)

推广到n维空间,欧式距离的公式是
d=sqrt( ∑(xi1-xi2)^ ) 这里i=1,2..n    ( xi1表示第一个点的第i维坐标,xi2表示第二个点的第i维坐标 )
n维欧氏空间是一个点集,它的每个点可以表示为(x(1),x(2),...x(n)),其中x(i)(i=1,2...n)是实数,称为x的第i个坐标,两个点x和y=(y(1),y(2)...y(n))之间的距离d(x,y)定义为上面的公式.

欧氏距离看作信号的相似程度。 距离越近就越相似,就越容易相互干扰,误码率就越高。

看下图解释:求ab边两端点的距离

设a(x1,y1),b(x2,y2),c边两点距离其实就是:sqrt((x1-x2)^+(y1-y2)^)

希望对你有帮助。

OpenCV 实时对象跟踪(质心跟踪)相关推荐

  1. 使用 YOLOv8 和 Streamlit 构建实时对象检测和跟踪应用程序:第2部分-探索模型和目标检测

    在教程系列的第 1 部分中,我们向您介绍了使用 YOLOv8 和 Streamlit 的实时对象检测和跟踪应用程序.我们还使用一些演示图像演示了该应用程序的功能. 我们详细解释了我们为这个项目选择 Y ...

  2. opencv实现对象跟踪_如何使用opencv跟踪对象的距离和角度

    opencv实现对象跟踪 介绍 (Introduction) Tracking the distance and angle of an object has many practical uses, ...

  3. 使用 OpenCV 进行对象跟踪的几种算法解读

    使用 OpenCV 进行对象跟踪--算法 在本节中,我们将深入研究不同的跟踪算法.目标不是对每个跟踪器有深入的理论理解,而是从实践的角度理解它们. 让我首先解释跟踪背后的一些一般原则.在跟踪中,我们的 ...

  4. 使用OpenCV和Python进行对象检测和跟踪

    在此功能中,我将介绍使用OpenCV和Python代码设置对象检测和跟踪所需的功能.使用随附的代码片段,您可以轻松设置Raspberry Pi和网络摄像头,以便制作用于物体检测的便携式图像传感器. 本 ...

  5. 如何利用Tensorflow和OpenCV构建实时对象识别程序?

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 引言 在本文中,将逐步介绍如何使用Tensorflow(TF)的新 ...

  6. OpenCV 3 Tracking API目标跟踪学习笔记——定义、物体跟踪常用算法、demo

    今天开始接触目标跟踪 本文翻译自https://www.learnopencv.com/object-tracking-using-opencv-cpp-python/#opencv-tracking ...

  7. python运动目标检测与跟踪_基于OpenCV的运动目标检测与跟踪

    尹俊超,刘直芳:基于 OpenCV 的运动目标检测与跟踪 2011, V ol.32, No.8 2817 0 引 言 运动目标检测跟踪技术在航空航天遥感. 生物医学. 工业 自动化生产. 军事公安目 ...

  8. 超实时性单目标跟踪网络——Siamese RPN(CVPR2018 spotlight论文)

    今年sensetime在CVPR上的表现力压国内其他科研机构,直逼谷歌.以44篇论文(3oral,11spotlight,28poster)在国内一骑绝尘.其中有一篇北航大四学生李博为一作的论文Sia ...

  9. 【yolov5+deepsort+tensorRT+QT+opencv临时启动内置跟踪器c++部署jetson-nx】

    [yolov5+deepsort+tensorRT+QT+opencv临时启动内置跟踪器c++部署jetson-nx] [yolov5+deepsort+tensorRT+QT+opencv临时启动内 ...

最新文章

  1. Windows下FFmpeg高速入门
  2. 2019腾讯后台开发暑期实习面经汇总
  3. HTML/CSS快速入门
  4. kubernetes实战篇之通过api-server访问dashboard
  5. Android下添加新的自定义键值和按键处理流程【转】
  6. 体二极管的原理及应用
  7. python之moviepy库的安装与使用
  8. 从 linux内核来看进程与线程的异同
  9. 信息提示无法建立数据连接服务器,FileZilla 链接FTP服务器无法建立数据连接: ECONNREFUSED...
  10. 20171116-构建之法:现代软件工程-阅读笔记
  11. dvm与art的区别_Android运行时– DVM与ART,AOT与JIT
  12. KnockOutlook:针对Outlook的红队安全研究工具
  13. java asm 全称,java ASM
  14. N+1个数据恢复软件,全中文!全破解免费!(潘中医)_-Chaz-_新浪博客
  15. 量子计算机宋超,蒿杰团队实感计算架构助力20超导量子比特薛定谔猫态制备-资讯-知识分子...
  16. 开源推荐 - CoDo开源一站式DevOps平台
  17. DDL和DML的定义和区别
  18. Centos6.7安装VNC及VNC客户端用来安装oracle11g
  19. header报文时间通用送法
  20. TG申请取消禁言教程

热门文章

  1. 怎么隐藏服务器真实IP地址?
  2. index.php打开失败,phpmyadmin无法打开index.php的解决方法
  3. Josh 的学习笔记之 Verilog(Part 4——RTL 概念与常用 RTL 建模)
  4. 计算机职业生涯规划书一万字,大学生职业规划一万字
  5. oracle如何总计,按组SQL运行总计(Oracle)
  6. 2022年云办公行业研究报告
  7. 用户使用移动支付的风险与防范策略
  8. 靶机实战(bulldog)
  9. vue使用报错记录(cli4):[vue/valid-v-for] Custom elements in iteration require ‘v-bind:key‘ direc
  10. 班级奖学金管理系统java_(奖学金评定管理系统设计)(最终版)