Python目标跟踪算法详解与实践
对象跟踪是一项计算机视觉任务,可以识别各种对象并通过视频帧跟踪它们。
了解视频中物体的位置有许多实际应用,尤其是在制造业和物流业。例如,物体跟踪可用于监控装配线、跟踪仓库中的库存,并帮助优化供应链管理。
在我们了解对象跟踪的工作原理之前,让我们先了解它是如何产生的。
最初,在 20 世纪 80 年代末和 90 年代初,对象跟踪主要依赖于背景减法和帧差分技术等方法。这些方法具有开创性,但难以处理动态背景或光照条件的变化。 技术随着时间而发展,在 20 世纪 90 年代中后期,出现了基于特征的跟踪算法等新方法。很快,更复杂的跟踪解决方案问世,这些解决方案专注于物体的边缘和角落等特定特征。20 世纪 90 年代,卡尔曼滤波和光流等机器学习技术的引入为高级跟踪铺平了道路。然而,真正的突破出现在 2010 年代,随着卷积神经网络(CNN) 和循环神经网络 (RNN) 等深度学习技术的发展。这些 AI 方法使复杂的物体跟踪具有更高的准确性、稳健性和适应性。如今的系统可以同时跟踪多个物体,即使在具有挑战性的条件下,也可以学习和适应新物体或环境。
目标跟踪算法的工作原理
对象跟踪的基本概念是使用算法检测视频中的对象并预测其在帧序列中的未来位置。它结合了对象检测和跟踪算法。对象检测使用参考帧中的边界框识别对象,而对象跟踪则预测其运动并在整个视频中跟踪它。一旦检测到对象,跟踪算法就可以从多个摄像机角度跟踪其在视频中随时间的运动,甚至可以同时跟踪多个对象。
其中涉及的几个关键技术如下:
特征提取:识别物体的独特特征,例如颜色、形状和纹理,以将其与背景和其他物体区分开来。
运动估计和轨迹预测:根据物体在前几帧中的运动预测物体的未来位置。
数据关联:为每个对象分配一个唯一的 ID,并确保它在各个帧之间保持一致,即使在部分遮挡或背景混乱的情况下也是如此。
重新识别:当物体超出画面范围或暂时被遮挡(例如另一个物体从其前面经过)时,重新识别方法可帮助软件在物体再次出现时检测并重新确定其身份。为此,通常使用基于深度学习的方法(如外观匹配)。
最流行的7个开源目标跟踪算法
ByteTrack
ByteTrack是一种用于多对象跟踪的计算机视觉算法。它为视频中的对象分配唯一的 ID 以跟踪每个对象。大多数跟踪方法仅使用得分高的检测框,而忽略得分较低的检测框,从而遗漏一些对象并导致轨迹碎片化。ByteTrack 通过在匹配过程中使用所有检测框(从高到低)来改善这种情况。
它根据运动相似性将高分检测框与现有轨迹匹配。轨迹是跟踪对象轨迹的短片段,用于保持随时间推移的连续跟踪。通过将高分检测框与轨迹匹配,ByteTrack 即使在部分被遮挡或快速移动时也能正确识别和跟踪对象。对于低分检测,ByteTrack 会根据对象与现有轨迹的相似性从背景中识别出对象。
由于 ByteTrack 可用于跟踪视频中的多个对象,因此它可以应用于波士顿动力公司的机器人在仓库中堆放箱子等场景。这些机器人使用机器视觉来精确地抬起、移动和放置箱子。ByteTrack 可以通过精确跟踪每个箱子的位置和移动来提高其效率。
Norfair
Tryolabs 的Norfair是一个轻量级且可自定义的对象跟踪库,可与大多数检测器配合使用。用户定义用于计算跟踪对象与新检测之间的距离的函数,该函数可以像欧几里得距离的一行代码一样简单,也可以使用嵌入或 Person ReID 模型等外部数据更复杂。
它还可以轻松集成到复杂的视频处理管道中,或用于从头开始构建视频推理循环。这使得 Norfair 适用于工厂工人监控、监控、体育分析和交通监控等应用。
Norfair 提供了几个预定义的距离函数,用户可以创建自己的函数来实现不同的跟踪策略。它支持各种视频分析应用程序并支持 Python 3.8+,Python 3.7 的最新版本是 Norfair 2.2.0。
MMTracking
MMTracking是一个免费的开源工具箱,旨在分析视频。它使用PyTorch构建,是名为 OpenMMLab 的大型项目的一部分。MMTracking 的独特之处在于它将多个视频分析任务整合到一个平台中。这些任务包括对象检测、对象跟踪,甚至视频实例分割。凭借其模块化设计,您可以轻松交换这些工具以创建满足您特定需求的自定义方法。
它还可以与其他 OpenMMLab 项目(尤其是MMDetection)很好地配合使用。这意味着您只需更改一些设置即可将 MMDetection 中可用的任何对象检测器与 MMTracking 一起使用。最重要的是,MMTracking 包含预构建的模型,这些模型的准确率非常高,有些甚至比原始版本更好。
MMTracking 非常适合需要高精度和高速度的应用,例如制造业中的自动检测和自动驾驶。其模块化设计允许轻松定制,使其成为各种视频分析任务的强大工具。
DeepSORT
DeepSORT(深度简单在线实时跟踪)是 SORT 算法的改进版本。它使用深度学习特征提取器来识别各种物体,非常适合同时跟踪多个物体。DeepSORT 使用卡尔曼滤波器来预测物体运动。它非常擅长处理物体之间的遮挡和相互作用,非常适合监控和人群监控应用。
FairMOT
FairMOT是一种基于无锚点物体检测架构 CenterNet 的跟踪方法。与其他将检测视为主要任务、将重新识别 (re-ID) 视为次要任务的框架不同,FairMOT 将这两项任务同等对待。它具有简单的网络结构,包含两个相似的分支:一个用于检测物体,另一个用于提取重新识别特征。
FairMOT 使用ResNet-34作为主干,以实现准确度和速度的良好平衡。它使用深度层聚合 (DLA) 增强了此主干,以组合来自多个层的信息。上采样模块中的可变形卷积可动态调整以适应不同的对象尺度和姿势,这有助于解决对齐问题。基于 CenterNet 的检测分支具有三个并行头,用于估计热图、对象中心偏移和边界框大小。re-ID 分支生成特征以识别对象。
FairMOT 适用于需要平衡精度和速度的场景,例如制造车间的实时质量检测、安全监控和自动驾驶汽车导航。它能够处理遮挡和动态物体尺度,因此是这些应用的理想选择。
BoT-SORT
BoT-SORT(SORT 的技巧包)是一种跟踪多个物体的方法,它改进了 SORT(简单在线实时跟踪)等传统方法。特拉维夫大学的研究人员开发了 BoT-SORT,以便能够更准确、更可靠地跟踪物体。它结合了运动和外观信息来区分不同的物体并随着时间的推移保持它们的身份。
BoT-SORT 还包含一项称为“相机运动补偿 (CMC)”的功能,该功能考虑了相机的运动,因此即使相机不静止,物体跟踪也能保持准确。此外,BoT-SORT 使用更先进的卡尔曼滤波器,可以更精确地预测被跟踪物体的位置和大小。这些改进有助于 BoT-SORT 表现出色,即使在具有大量运动或拥挤场景的具有挑战性的情况下也是如此。它在标准数据集上的 MOTA(多物体跟踪准确度)、IDF1(身份 F1 分数)和 HOTA(高阶跟踪准确度)等关键性能指标中排名第一。
BoT-SORT 具有高精度和高稳定性的跟踪能力,是工业应用的理想选择。在大型仓库等环境中,光照条件可能会发生变化,其他物品经常会遮挡物体,但 BoT-SORT 仍能表现出色。它可用于跟踪包裹和托盘,以改善库存管理并降低物品丢失的风险。它能够监控货物从收货到发货的整个过程,有助于简化运营并提高供应链的可视性。精确的跟踪支持物流运营,实时更新每件物品的位置和状态。
StrongSORT
StrongSORT旨在改进经典的 DeepSORT 算法。它是为了解决多对象跟踪中的常见问题而开发的,例如检测准确性和对象关联。StrongSORT 使用强大的对象检测器、复杂的特征嵌入模型和多种技巧来提高跟踪性能。它还引入了两种新算法:AFLink(无外观链接)和 GSI(高斯平滑插值),它们有助于更准确地跟踪对象,而无需过度依赖外观特征。
AFLink 和 GSI 都是轻量级的,易于集成到各种跟踪系统中。AFLink 仅使用时空信息即可帮助将轨迹链接在一起,使其既快速又准确。GSI 通过考虑运动信息来改进处理缺失检测的方式。这些改进使 StrongSORT 在多个公共基准测试中取得了最佳成绩,包括 MOT17、MOT20、DanceTrack 和 KITTI。
StrongSORT 的准确性和稳健性使其可用于需要非常仔细地跟踪物体的应用中。例如,假设有一个摄像头可以鸟瞰一个建筑工地,那里有许多重型车辆在不断移动。StrongSORT 可以实时监控这些车辆,帮助防止事故发生,并确保高效运营。它能够处理遮挡和多变的光照条件,即使在建筑工地动态且通常混乱的环境中也能可靠运行。
目标跟踪的挑战和限制
虽然对象跟踪技术已经取得了长足的进步,但仍然存在一些因素,导致难以获得一致的结果。使用这些对象跟踪工具时需要牢记的一些挑战和限制是:
遮挡:遮挡是指一个物体遮挡另一个物体,例如两个人擦肩而过,或者一辆车在桥下行驶。系统很难跟踪部分被遮挡的物体。
外观的变化:物体会根据其与相机的距离、角度或大小而看起来不同。
光照变化:光照变化会改变物体的外观,使检测和跟踪变得复杂。计算机视觉系统通常难以应对这些变化。
多摄像头跟踪:跨多个摄像头跟踪物体涉及一个称为 ReID 的过程,该过程涉及一组不同的算法。
可扩展性:针对许多摄像机或分散部署的扩展解决方案可能很复杂且昂贵,通常需要额外的基础设施或定制开发。
——————————–
目标跟踪算法是一种计算机视觉技术,用于在视频或图像序列中检测并跟踪移动的目标,如人、车辆或物体。这些算法利用图像处理和机器学习技术,通过分析连续帧之间的变化,识别并跟踪目标的位置、轨迹和其他属性。这些算法在监控、自动驾驶、增强现实等领域有广泛应用。常见的目标跟踪算法包括卡尔曼滤波器、粒子滤波器、相关滤波器以及基于深度学习的算法,如卷积神经网络(CNN)和循环神经网络(RNN)。
下面介绍一些常见的目标跟踪算法及其原理:
-
Mean-Shift Tracking Mean-Shift算法是一种无监督的迭代方法,用于寻找数据点密度的模式。在目标跟踪中,Mean-Shift通过计算目标模型(例如颜色直方图)与搜索窗口之间的相似度来更新目标位置。算法不断迭代地调整搜索窗口的中心,直到收敛到最大似然估计位置。
-
CamShift Tracking CamShift(Continuously Adaptive Mean-Shift)是Mean-Shift的扩展版本,除了跟踪目标的位置之外,还能够估计目标的大小和形状。CamShift算法首先使用Mean-Shift算法确定目标的新位置,然后根据颜色分布的变化调整目标的矩形框大小和长宽比。
-
Kernelized Correlation Filters (KCF) KCF算法利用循环矩阵和快速傅里叶变换来高效地计算相关滤波器。它将目标表示为一个高维特征向量,并在每个帧中更新滤波器,以适应目标外观变化。KCF算法因其速度快和精度高而被广泛应用。
-
Multiple Object Tracking by Detection (MOT) 基于检测的多目标跟踪(MOT)首先使用目标检测算法(如YOLO, Faster R-CNN等)在每一帧中检测出所有潜在目标,然后使用数据关联算法(如匈牙利算法)将检测到的目标与跟踪列表中的目标关联起来。
-
SORT (Simple Online and Realtime Tracking) SORT算法是一种基于跟踪的多目标跟踪方法,它使用卡尔曼滤波器来预测目标的运动轨迹,并结合检测结果进行数据关联。SORT的优点是实时性好,适用于需要快速响应的场景。
-
Deep Learning Trackers 基于深度学习的目标跟踪算法使用卷积神经网络(CNN)来提取目标特征,并通过在线学习或域适应技术来更新模型,以适应目标在视频序列中的外观变化。代表算法包括SiameseFC、SiamRPN和YOLOTrack等。
-
Correlation Filter with Deep Features (CFNet) 结合了传统相关滤波器和深度学习特征的CFNet算法,使用CNN提取的深度特征来增强相关滤波器的性能。这种结合方法旨在保留传统相关滤波器的计算效率,同时提高跟踪精度。
-
Transparent Object Tracking (TOT) TOT算法专注于透明物体的跟踪,它通过分析透明物体和背景之间的光学特性差异来实现跟踪。该算法通常结合深度学习技术来提高对透明物体的检测和跟踪能力。
一,Mean-Shift
Mean-Shift 算法是一种非参数的迭代搜索方法,用于寻找概率密度函数的模式(或均值)。在目标跟踪领域,Mean-Shift 用于更新目标的位置,使之与目标的特征直方图(如颜色分布)的当前估计保持一致。
Mean-Shift 算法的核心思想是利用目标的特征直方图作为其概率密度函数,并通过迭代过程不断更新目标的位置,直到收敛到概率密度函数的最大值处。这个过程不需要事先知道目标的大小和形状,因此具有很强的鲁棒性。
Mean-Shift 算法的基本步骤如下:
1)初始化:设定搜索窗口的中心 c 为目标的初始位置,并计算窗口内的特征直方图作为目标模型。
2)计算目标模型和候选区域的特征直方图:对于搜索窗口 c,计算窗口内的特征直方图 q(x);同样,计算周围区域内的特征直方图 p(x),这个区域称为候选区域或搜索区域。
3)计算目标和候选区域之间的相似度:通常使用Bhattacharyya距离来度量两个直方图的相似度,公式如下:
其中,D(p, q) 越小,表示两个直方图越相似。
4)更新搜索窗口的中心:使用Mean-Shift向量 m 更新搜索窗口的中心,公式如下:
其中,S 是候选区域,w(x) 是权重函数,通常定义为:
Mean-Shift向量 m 指向概率密度函数 p(x) 相对于 q(x) 的加权平均位置。
5)迭代:重复步骤2至4,直到收敛,即搜索窗口的中心 c 不再发生显著变化或者达到预设的迭代次数。
以下是一个简单的Mean-Shift 跟踪算法的Python实现代码示例,这 里使用了OpenCV库中的MeanShift函数来执行跟踪:
import cv2
# 读取视频
cap = cv2.VideoCapture('video.mp4')
# 初始化捕获器
ret, frame = cap.read()
# 创建HSV颜色空间的掩膜
lower_bound = np.array([0, 40, 10])
upper_bound = np.array([10, 255, 255])
# 初始化目标的颜色直方图
roi = frame[0:150, 0:150]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_roi, lower_bound, upper_bound)
hist = cv2.calcHist([hsv_roi], [0], mask, [180], [0, 180])
# 归一化直方图
cv2.normalize(hist, hist)
# 创建MeanShift对象
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
ms = cv2.createTrackbar("Threshold", "Trackbar", 10, 100, nothing)
tracker = cv2.TrackerMIL_create()
while ret:
# 读取帧
ret, frame = cap.read()
# 转换为HSV颜色空间
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 应用掩膜
mask = cv2.inRange(hsv_frame, lower_bound, upper_bound)
# 使用MeanShift跟踪
success, track_box = tracker.update(frame, mask)
# 绘制跟踪框
if success:
p1 = (int(track_box[0]), int(track_box[1]))
p2 = (int(track_box[0] + track_box[2]), int(track_box[1] + track_box[3]))
cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
# 显示结果
cv2.imshow("Frame", frame)
cv2.imshow("Mask", mask)
# 按'q'退出循环
k = cv2.waitKey(1) & 0xFF
if k == ord('q'):
break
# 释放捕获器
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
在这个例子中,我们首先读取了一个视频文件,然后创建了一个颜色直方图用于描述目标的特征。接下来,我们使用OpenCV的TrackerMIL类来初始化Mean-Shift跟踪器,并在视频的每一帧中更新目标的位置。最终,我们将跟踪框绘制在原始帧上,并显示给用户。
二,CamShift
CamShift(Continuously Adapted Mean-Shift)是一种结合了Mean-Shift跟踪算法和颜色直方图的自适应方法,用于在视频序列中跟踪目标。CamShift算法不仅能够跟踪目标的位置,而且能够根据目标的形状和大小的变化进行自适应调整。
CamShift算法的原理可以概括为以下几个步骤:
1)目标初始化:在视频的第一帧中选择一个区域作为目标,并计算该区域的颜色直方图。
2)目标建模:使用目标区域的颜色直方图作为目标模型。
3)目标定位:在随后的每一帧中,使用Mean-Shift算法根据目标模型来更新目标的位置。Mean-Shift算法会寻找与目标模型最相似的区域,并将搜索窗口移动到该区域的中心。
4)目标形状估计:通过计算目标区域的轮廓矩来估计目标的形状。
5)目标大小调整:根据轮廓矩的估计结果,调整搜索窗口的大小,使之更贴合目标的实际大小。
6)迭代更新:重复步骤3到5,直到目标离开视野或跟踪失败。
以下是一个简单的CamShift跟踪算法的实现代码,使用Python和OpenCV库:
import cv2
import numpy as np
# 初始化摄像头
cap = cv2.VideoCapture(0)
# 读取第一帧
ret, frame = cap.read()
# 转换到HSV颜色空间
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 定义目标颜色的HSV范围
lower_blue = np.array([110,50,50])
upper_blue = np.array([130,255,255])
# 创建一个蓝色区域的掩码
mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
# 计算蓝色区域的直方图
roi = cv2.bitwise_and(frame, frame, mask=mask)
hist = cv2.calcHist([roi], [0], None, [180], [0, 180])
# 归一化直方图
cv2.normalize(hist, hist)
# 创建CamShift对象
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
camshift = cv2.CamShift(hist, mask, term_crit)
while True:
# 读取帧
ret, frame = cap.read()
# 转换到HSV颜色空间
hsv_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# 创建一个蓝色区域的掩码
mask = cv2.inRange(hsv_frame, lower_blue, upper_blue)
# 使用CamShift跟踪目标
ret, track_box = camshift(mask, term_crit)
# 如果跟踪成功,绘制目标框
if ret:
pts = cv2.boxPoints(track_box)
pts = np.int0(pts)
cv2.polylines(frame, [pts], True, (255,0,0), 2)
# 显示结果
cv2.imshow('CamShift Demo', frame)
# 按'q'键退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头
cap.release()
# 关闭所有窗口
cv2.destroyAllWindows()
上述代码中,我们首先初始化摄像头,并在第一帧中选择一个目标区域,然后根据该区域的颜色创建掩码并计算直方图。接着,我们创建一个CamShift对象,并在随后的每一帧中使用它来更新目标的位置和大小。最后,我们将更新后的目标框绘制在原始帧上,并显示给用户。
三,KCF
1)在初始帧中基于初始的目标bounding box,扩大2.5倍(跟踪区域是目标大小的2.5倍可以提供上下文信息),得到大小为M × N的ROI。
2)计算初始图像patch的HOG特征,得到31维的HOG特征图,即HOG特征图的大小为m × n × 31(m 和n的大小取决于M、N以及HOG的cell size参数)。
3)对HOG特征图进行余弦窗口加权,从而减轻由于边界移位导致的图像不光滑。
4)利用二维高斯函数得到长宽和HOG特征图一样的标签矩阵y(即大小也为m × n)。越靠近中心的像素点具有更高的权重,使得训练出的模型更关心目标的中心区域。
5)基于快速核相关公式得到 k^{xx}
6)针对输入的HOG特征图,训练出非线性回归器:
7)在接下来的一帧中,基于上一帧的目标中心,框选出大小为M × N 的ROI,求得HOG特征图,进行余弦窗加权,之后,同样基于快速核相关求得 k^{xz}。
8)基于下述公式计算傅域下的响应矩阵,然后计算逆傅里叶变换得到f ( z ),即,最终的响应矩阵:
9)找到响应矩阵f ( z ) f(z)f(z)中响应值最大的位置,若该位置的响应值大于给定阈值,则输出该位置作为当前全局图像中的目标位置。若最大响应值仍小于给定阈值,则采取补救方法(这个还不太清楚是什么,好像是全局图像搜索,然后重新初始化)。
10)模型更新, 基于当前输出的目标位置,选取样本,类似于步骤1-6计算得到新的α ′ ,然后采用线性插值来更新模型:
m为学习率,是一个0-1之间的值。m越大说明以前的模型影响越大(太大容易跟丢),越小说明以前的模型影响越小(太小鲁棒性低)。
11)重复7-10的检测过程。
四,MOT
基于深度学习的多目标跟踪算法通常包括以下几个核心步骤:
1)检测:利用目标检测算法,如Faster R-CNN、YOLO等,在视频帧中检测出所有的目标对象,并获得它们的边界框。
2)特征提取与运动预测:对于每个检测到的目标,提取其视觉特征(如颜色、纹理等)和运动特征(如速度、加速度等)。这些特征将用于后续的目标匹配和数据关联。
3)相似度计算:计算目标之间的相似度,包括外观相似度和运动相似度。相似度计算的结果将用于确定目标之间的匹配关系。
4)数据关联:根据相似度计算结果,将不同帧中的目标进行关联,形成目标轨迹。数据关联算法可以采用匈牙利算法、网络流算法等。
通过以上四个步骤,基于深度学习的多目标跟踪算法可以在视频序列中同时跟踪多个目标对象,并获取它们的运动轨迹。在实际应用中,还需要考虑算法的实时性、鲁棒性等问题。
以下是一个简单的MOT跟踪算法的实现代码,使用Python和OpenCV库:
import cv2
import numpy as np
# 初始化追踪器
tracker = cv2.MultiTracker_create()
# 初始化视频
video = cv2.VideoCapture("path_to_your_video.mp4")
# 读取视频的第一帧
ret, frame = video.read()
while True:
# 读取视频的下一帧
ret, frame = video.read()
if not ret:
break
# 检测视频中的对象(例如使用HOG+Linear SVM的行人检测器)
# 这里需要你自己实现或者使用OpenCV的预训练检测器
# 假设 'bboxes' 是检测到的边界框列表,格式为 [x, y, width, height]
bboxes = detect_objects(frame) # 替换为你的检测函数
# 添加追踪器
for bbox in bboxes:
tracker.add(frame, bbox)
# 更新追踪器的位置
success, boxes = tracker.update(frame)
# 绘制追踪器的位置
for i, newbox in enumerate(boxes):
p1 = (int(newbox[0]), int(newbox[1]))
p2 = (int(newbox[0] + newbox[2]), int(newbox[1] + newbox[3]))
cv2.rectangle(frame, p1, p2, (255,0,0), 2, 1)
cv2.putText(frame, "Tracking object " + str(i), (int(newbox[0]), int(newbox[1]-10)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 显示帧
cv2.imshow("Tracking", frame)
# 按 'q' 退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放视频和销毁所有窗口
video.release()
cv2.destroyAllWindows()
请注意,这个示例假设你已经有一个可以检测多个对象并返回它们边界框的函数 detect_objects(frame)
。在实际应用中,你需要使用一个合适的目标检测模型来替换这个函数。
由于MOT是一个复杂的任务,上述代码只是一个基本的示例,实际应用中可能需要更复杂的逻辑来处理丢失的追踪器、测量运动、处理相似对象等问题。
五,SORT
SORT(Simple Online and Realtime Tracking)是一种基于卡尔曼滤波的目标跟踪算法,它可以在实时场景中对移动目标进行鲁棒跟踪。SORT算法最初是由Alex Bewley等人在2016年提出的,它已被广泛应用于计算机视觉领域的各种应用中,例如视频监控、自动驾驶、机器人导航等。
SORT算法主要基于两个核心思想:卡尔曼滤波和匈牙利算法。卡尔曼滤波是一种用于估计系统状态的算法,它可以利用系统的动态模型和传感器测量值,对系统状态进行预测和更新,从而提高状态估计的准确性。匈牙利算法是一种用于解决二分图最大权匹配问题的算法,它可以在给定一个二分图的情况下,找到最大权匹配。
SORT算法的主要步骤如下:
1)目标检测:使用目标检测算法(如YOLO、SSD等)提取当前帧中的目标信息。
2)状态预测:对于每个已经跟踪的目标,利用卡尔曼滤波对其状态进行预测。
3)数据关联:根据预测状态和当前帧中的目标信息,使用匈牙利算法进行数据关联,找到每个已经跟踪的目标在当前帧中对应的目标。
4)状态更新:对于每个已经跟踪的目标,利用卡尔曼滤波对其状态进行更新。
5)目标输出:输出每个已经跟踪的目标的状态信息和跟踪结果。
在计算机视觉中,SORT算法可以应用于各种目标跟踪场景。例如,在视频监控中,SORT算法可以对移动目标进行实时跟踪,从而实现对场景中的异常行为进行检测和预警。在自动驾驶领域,SORT算法可以对其他车辆、行人等交通参与者进行跟踪,从而实现车辆的自主导航和避障。在机器人导航中,SORT算法可以对移动目标进行跟踪,从而实现机器人的自主导航和避障。
以下是一个使用Python实现的简单示例代码:
#python
import numpy as np
from filterpy.kalman import KalmanFilter
from scipy.optimize import linear_sum_assignment
class Track:
def init(self,prediction,track_id,track_lifetime):
self.prediction=np.atleast_2d(prediction)
self.track_id=track_id
self.track_lifetime=track_lifetime
self.age=0
self.total_visible_count=1
self.consecutive_invisible_count=0
def predict(self, kf):
self.prediction = kf.predict()
self.age += 1
def update(self, detection, kf):
self.prediction = kf.update(detection)
self.total_visible_count += 1
self.consecutive_invisible_count = 0
def mark_missed(self):
self.consecutive_invisible_count += 1
def is_dead(self):
return self.consecutive_invisible_count >= self.track_lifetime
class Tracker:
def init(self,track_lifetime,detection_variance,process_variance):
self.next_track_id=0
self.tracks=[]
self.track_lifetime=track_lifetime
self.detection_variance=detection_variance
self.process_variance=process_variance
self.kf=KalmanFilter(dim_x=4,dim_z=2)
self.kf.F=np.array([[1,0,1,0],
[0,1,0,1],
[0,0,1,0],
[0,0,0,1]])
self.kf.H=np.array([[1,0,0,0],
[0,1,0,0]])
self.kf.R=np.array([[self.detection_variance,0],
[0,self.detection_variance]])
self.kf.Q=np.array([[self.process_variance,0,0,0],
[0,self.process_variance,0,0],
[0,0,self.process_variance,0],
[0,0,0,self.process_variance]])
def update(self, detections):
# predict track positions using Kalman filter
for track in self.tracks:
track.predict(self.kf)
# associate detections with tracks using Hungarian algorithm
if len(detections) > 0:
num_tracks = len(self.tracks)
num_detections = len(detections)
cost_matrix = np.zeros((num_tracks, num_detections))
for i, track in enumerate(self.tracks):
for j, detection in enumerate(detections):
diff = track.prediction - detection
distance = np.sqrt(diff[0,0]**2 + diff[0,1]**2)
cost_matrix[i,j] = distance
row_indices, col_indices = linear_sum_assignment(cost_matrix)
unassigned_tracks = set(range(num_tracks)) - set(row_indices)
unassigned_detections = set(range(num_detections)) - set(col_indices)
for i, j in zip(row_indices, col_indices):
self.tracks[i].update(detections[j], self.kf)
for i in unassigned_tracks:
self.tracks[i].mark_missed()
for j in unassigned_detections:
new_track = Track(detections[j], self.next_track_id, self.track_lifetime)
self.tracks.append(new_track)
self.next_track_id += 1
# remove dead tracks
self.tracks = [track for track in self.tracks if not track.is_dead()]
# return list of track positions
return [track.prediction.tolist()[0] for track in self.tracks]
以上代码实现了一个简单的SORT跟踪算法,使用Kalman滤波器对目标位置和速度进行预测和估计,然后使用匈牙利算法对目标进行关联,最后根据目标的连续不可见次数判断目标是否死亡并移除死亡的目标。以上代码实现了一个简单的SORT跟踪算法,使用Kalman滤波器对目标位置和速度进行预测和估计,然后使用匈牙利算法对目标进行关联,最后根据目标的连续不可见次数判断目标是否死亡并移除死亡的目标。
六,Deep Learning Trackers
Deep Learning Trackers 基于深度学习的目标跟踪算法使用卷积神经网络(CNN)来提取目标特征,并通过在线学习或域适应技术来更新模型,以适应目标在视频序列中的外观变化。代表算法包括SiameseFC、SiamRPN和YOLOTrack等。具体略。
七,CFNet
不同数据集间场景(域)差异较大(large domain differences)且视差分布不平衡,这极大地限制了现有深度立体匹配模型在现实生活的应用。为提高立体匹配网络的鲁棒性,文中提出一种基于级联和融合的代价量网络:CFNet。具体来说,作者基于SiamseFC的结构引入CF层(Correlation Filter),网络通过端到端训练,证明可以用较少网络的卷积层数而不降低准确度。CFNet整体结构如下图所示:
CFNet整体结构,网络由3部分组成:金字塔特征提取网络、融合代价体和级联代价体
CFNet网络由三部分组成:金字塔特征提取网络 — pyramid feature extraction;融合代价体 — fused cost volume;级联代价体 — cascade cost volume。
金字塔特征提取网络。该网络是带有跳跃连接的编码器解码器结构,由 5 个残差块组成,提取多尺度图像特征。后面紧接一个SPP(Spatial Pyramid Pooling,空间金字塔池化)模块,用以更好的合并多尺度特征的上下文信息。SPP模块就是对特征进行不同Size的池化,然后进行信息融合。
融合代价体。文中提出融合多个低分辨率密集代价体(小于原始输入图像分辨率的1/4的代价体,代码中是1/8,1/16,1/32),以减少初始视差估计中不同数据集之间的域差异 (domain shifts)。很多工作都意识到多尺度代价体的重要性,但这些工作通常都认为低分辨率的代价体特征信息不足,无法生成准确的视差图,所以弃之不用。但文中认为不同尺度的低分辨率代价体可以融合在一起提取全局结构化表示,其生成的初始视差图更加准确(鲁棒)。具体的,在每个尺度上分别构建低分辨率成本体积,文中同时使用特征拼接(feature concatenation)和组相关(group-wise correlation)来生成融合代价体,公式如下:
接下来对代价体进行融合。如下图,首先对每个 cost volume 使用 4 个具有skip connection的 3D 卷积层(每个分支的前四个蓝色块)。使用stride = 2 的 3D 卷积将 scale3 的分辨率从 1/8 降到 1/16。然后将下采样后的 scale3 和 scale4 拼接再通过一个额外的 3D 卷积将特征通道缩放。继续采取类似的操作来逐步将 scale3 的 cost volume 下采样到原始输入图像分辨率的 1/32与 scale5进行信息融合 ,最后采用 3D 转置卷积对 cost volume上采样并对上采样后的 cost volume 利用特征信息进行细化。对细化后的 cost volume 进行视差回归(soft argmin operation)就可以得到初始视差图:
图 成本代价体融合模块结构。三个低分辨率的成本代价体(i∈(3, 4, 5))被融合以生成初始差异图
级联代价体。有了初始化视差下一步就是构建高分辨率的cost volume,细化视差图。理想的视差概率分布应该是单峰的,即该位置属于某个视差的概率非常高、属于其它视差的概率非常低。然而视差的实际的概率分布主要是多峰,即对某个位置的视差不是很确定,这种情况常出现于遮挡、无纹理区域。文中提出定义一个不确定性估计来量化视差概率分布趋向于多峰分布的程度:
文中根据当前阶段的不确定性来计算下一阶段的视差搜索范围,具体公式如下:
根据均匀采样,得到下一阶段离散的平面假设深度:
八,TOT
论文链接:https://arxiv.org/abs/2011.10875
透明目标指玻璃杯或塑料制品。
采用ResNet18和简单的FCN构建分割网络来进行inference。在任务中,只分割尺寸小、可移动的透明物体。训练完分割网络后用该网络提取透明物体的相关特征。将其特征与ATOM相融合,称为TransATOM。TransATOM包含两个特征分支,一个分支是ResNet18用来分类,另一个是训练得到的分割网络。对于两个分支,提取block4之后的特征,concatenate两者来获取更加鲁棒特征。
分类网络包含两层卷积网络
TransATOM能够很好地对透明物体进行定位,实时速度为26fps。
针对提出的TransATOM,意图通过提取透明特征来增强对透明物体跟踪的能力。采用全卷积网络来进行分割,特征提取网络用的是ResNet-18。
用来训练该网络用的数据集是从文献【Segmenting transparent objects in the wild. 】中得到的,选择thing类别的图片进行训练。总共用了2844张静态的图片,主干网络的初始参数是ResNet18中的,损失函数用的是交叉熵损失函数。对于优化,使用SGD优化器,动量0.9,权重decay为0.0005。训练的batch为8,初始学习率为0.02,然后在30个epoch中呈poly递减(power为0.9)。更加复杂的分割网络可以达到更好的效果,但是出于跟踪对于效率的要求,本文采用ResNet-18的全卷积网络。训练之后,使用网络的block1-4来提取特征。
作者:我真不会起名字啊