主要内容

如何有效跟踪大量对象

方法的使用trackerGNN追踪大量目标。类似的技术可以应用于trackerJPDAtrackerTOMHT

简介

在许多应用程序中,需要跟踪器跟踪数百或数千个对象。增加跟踪器维护的轨道数量是一个挑战,这是由每个跟踪器核心算法的计算复杂性引起的。特别是,跟踪器更新步骤中的两个常见阶段不容易伸缩:计算分配成本和执行分配。分配成本的计算是常见的trackerGNNtrackerJPDA,trackerTOMHT,在使用这些跟踪器时,可以应用此示例中显示的技术。每个跟踪器执行赋值的方式对每个跟踪器都是唯一的,并且可能需要定制的解决方案来提高跟踪器的性能,这超出了本示例的范围。金宝搏官方网站

场景

为了本例的目的,您定义了一个包含900个平台的场景,这些平台组织在一个15 × 15的网格中,每个网格单元包含4个平台。网格单元格的目的是演示粗成本计算的好处,稍后将在示例中解释。

下面的代码在网格单元格中排列900个对象并创建可视化。左边显示了整个场景。在右边,可视化放大了4个网格单元格。注意,每个单元格包含4个平台。

[平台,tp,zoomedtp] = createPlatforms;

使用默认分配成本计算

本节展示了使用类跟踪上面定义的平台的结果trackerGNN用默认AssignmentThreshold.的AssignmentThreshold属性包含两个值:(C1, C2),在那里C1阈值是否用于分配和C2是用于下一节解释的粗计算的阈值。

当跟踪器更新为一组新的检测时,它会计算将每个检测分配给每个跟踪的成本。准确的成本计算必须考虑每个检测的测量和不确定度,以及每个轨道的预期测量和预期不确定度,如下所示。

默认情况下,C2设置为Inf,要求计算所有跟踪和检测组合的代价。这将导致更精确的分配,但计算量更大。您应该从默认设置开始,以确保跟踪器以最佳方式将检测分配给轨道,然后考虑降低的值C2减少计算分配成本所需的时间。

在分配成本计算过程中,成本矩阵中值大于的元素C1这样做可以帮助赋值算法忽略不可能的赋值。

定义一个可以跟踪多达1000个跟踪的跟踪器。跟踪器使用默认的等速扩展卡尔曼滤波器,其状态定义为[x, vx; y; v; z; vz],由positionSelector下面得到位置组件。

跟踪器= trackerGNN(“MaxNumTracks”, 1000,“AssignmentThreshold”, [30 Inf]);positionSelector = [1 0 0 0 0 0 0;0 0 1 0 0 0;0 0 0 0 0 0];

在对step的第一次调用中,跟踪器实例化所有轨道。要将实例化轨道所需的时间与第一步所需的处理时间隔离开来,您可以调用设置重置在踩上追踪器之前。参见支持函数金宝apprunTracker在本例的末尾可以获得更多详细信息。

[trkSummary,truSummary,info] = runTracker(平台,跟踪器,positionSelector,tp,zoomedtp);
跟踪器设置时间:8.3108步骤1时间:3.7554步骤2时间:15.3029步骤3时间:14.1099步骤4时间:14.3506步骤5时间:14.3963

从现在开始的所有步骤都不会被发现。步骤6 time: 0.53103步骤7 time: 0.52582步骤8 time: 0.50639步骤9 time: 0.50909步骤10 time: 0.16034场景完成所有音轨现在都被删除了。

您可以通过检查跟踪分配指标值来分析跟踪结果。为了完美的跟踪,轨道的总数应该等于平台的数量,并且不应该有错误的、交换的或发散的轨道。类似地,在真理总结中不应该有遗漏的真理或间断。

assignmentMetricsSummary (trkSummary truSummary)
跟踪任务指标简介:TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength  ______________ ______________ ____________ __________________ ___________________ 900 0 0 0 0真理的任务指标简介:TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount  ______________ ________________ ______________________ _____________ 900 0 1 0

使用粗分配成本计算

在前一节中,您看到跟踪器能够跟踪所有平台,但是每个更新步骤都需要很长时间。大部分时间花在计算分配成本矩阵上。

检查成本矩阵,你可以看到它的绝大多数元素实际上是无穷大的。

cm = info.CostMatrix;disp (“成本矩阵有”+数字(cm) +“元素”。);disp (但有限值的个数是+数字(cm(isfinite(cm))) +换行符)
成本矩阵有810000个元素。但是有限值的数目是2700

从上述结果可以看出,成本计算在计算所有跟踪与检测组合的分配成本上花费了过多的时间。然而,这些组合大多太远,无法分配,因为实际测量距离基于传感器特性的期望测量轨道太远。为了避免在计算所有成本时的浪费,你可以使用粗略的成本计算。

进行粗计算以验证哪些跟踪和探测组合可能需要精确的归一化距离计算。只有粗分配代价低于C2计算准确。粗略的成本计算如下图所示。检测是由它的测量来表示的z美元测量噪声R美元.两条轨迹被预测到检测时间,并投影到测量空间,由点表示美元z_ {e_1} $美元z_ {e_2} $.请注意,轨迹不确定度没有投影到测量空间,这允许我们向量化粗计算。这是一个粗略的估计,因为只考虑了检测的不确定性。在所述示例中,第一轨道落在粗计算门之外,而第二轨道落在粗计算门内部。因此,只有将该检测与第二轨道相结合,才能进行准确的成本计算。

使用粗成本计算,释放跟踪器并修改其AssignmentThreshold值为[30 200]。然后,重新运行跟踪器。

发布追踪(追踪)。AssignmentThreshold= [30 200]; [trkSummary,truSummary] = runTracker(platforms,tracker,positionSelector,tp,zoomedtp);
跟踪器设置时间:6.5846步骤1时间:3.5863步骤2时间:3.4095步骤3时间:2.9347步骤4时间:2.8555步骤5时间:2.9397

从现在开始的所有步骤都不会被发现。步骤6 time: 0.51446步骤7 time: 0.52277步骤8 time: 0.54865步骤9 time: 0.50941步骤10 time: 0.19085场景完成所有音轨现在都被删除了。

您可以观察到,现在完成步骤3-5所需的时间大大减少了。第2步也比以前快,但仍然比第3-5步慢。

要理解为什么第2步更慢,请考虑第一次跟踪器更新后的跟踪状态。状态包含位置信息,但速度仍然为零。当跟踪器计算分配代价时,它将跟踪状态预测到检测时间,但由于跟踪速度为零,它们保持在相同的位置。这导致探测测量值与预测航迹状态的预期测量值之间的距离很大。这些相对较大的赋值代价使得赋值算法更难找到最佳赋值,这导致第2步比第3-5步花费更多的时间。

验证使用粗成本计算的轨道分配与不使用粗成本计算的轨道分配是否相同是很重要的。如果轨道分配指标不相同,则必须增大粗计算门的尺寸。下面显示的跟踪仍然是完美的,因为它是在前一节,但每个处理步骤所花费的时间更少。

assignmentMetricsSummary (trkSummary truSummary)
跟踪任务指标简介:TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength  ______________ ______________ ____________ __________________ ___________________ 900 0 0 0 0真理的任务指标简介:TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount  ______________ ________________ ______________________ _____________ 900 0 1 0

使用外部成本计算

控制计算成本分配所需时间的另一种方法是使用您自己的分配成本计算,而不是跟踪器使用的默认值。

外部成本计算可以考虑不属于跟踪状态和预期度量的属性。它还可以使用不同的距离度量,例如欧几里得范数而不是标准化距离。选择应用哪种成本计算取决于问题的具体情况、度量空间以及如何定义状态和度量。

要使用外部成本计算,您可以释放跟踪器并设置其HasCostMatrixInput属性为true。您必须将自己的成本矩阵作为每次更新到跟踪器的额外输入。参见支持函数金宝apprunTracker欲知详情。

释放(跟踪);跟踪器。HasCostMatrixInput = true;[trkSummary,truSummary] = runTracker(平台,跟踪器,positionSelector,tp,zoomedtp);assignmentMetricsSummary (trkSummary truSummary)
跟踪器设置时间:6.559步骤1时间:3.4394步骤2时间:1.7852步骤3时间:1.474步骤4时间:1.5312步骤5时间:1.5152

从现在开始的所有步骤都不会被发现。步骤6 time: 0.60809步骤7 time: 0.61374步骤8 time: 0.616步骤9 time: 0.63798步骤10 time: 0.22762场景完成所有音轨现在都被删除了。跟踪任务指标简介:TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength  ______________ ______________ ____________ __________________ ___________________ 900 0 0 0 0真理的任务指标简介:TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount  ______________ ________________ ______________________ _____________ 900 0 1 0

正如预期的那样,当使用外部成本计算函数时,处理时间甚至更短。

修改GNN分配算法

另一个尝试的选择是使用不同的GNN分配算法,通过修改赋值跟踪器的属性。

发布追踪(追踪)。赋值=“Jonker-Volgenant”;跟踪器。HasCostMatrixInput = true;runTracker(平台、跟踪positionSelector tp, zoomedtp);
跟踪器设置时间:6.494步骤1时间:3.5346步骤2时间:1.894步骤3时间:3.1192步骤4时间:3.1212步骤5时间:3.1458

从现在开始的所有步骤都不会被发现。步骤6 time: 0.61109步骤7 time: 0.62456步骤8 time: 0.61849步骤9 time: 0.60604步骤10 time: 0.22303场景完成所有音轨现在都被删除了。

与默认的Munkres算法相比,Jonker-Volgenant算法在第二步中更快地执行分配。

蒙特卡罗模拟

如果希望在不修改跟踪器设置的情况下运行多个场景,则不需要调用释放方法。相反,只需调用重置方法从跟踪器中清除以前的跟踪信息。这样,您就节省了实例化所有轨道所需的时间。注意下面相对于之前运行的“跟踪器设置时间”。

重置(跟踪)runTracker(平台、跟踪positionSelector、tp zoomedtp);
跟踪器设置时间:0.097531步骤1时间:3.4684步骤2时间:1.6592步骤3时间:3.1429步骤4时间:3.1274步骤5时间:3.0994

从现在开始的所有步骤都不会被发现。步骤6时间:0.63232步骤7时间:0.61857步骤8时间:0.61433步骤9时间:0.60698步骤10时间:0.25301场景完成所有音轨现在都被删除了。

总结

这个例子展示了如何跟踪大量的对象。当跟踪许多目标时,跟踪器将大量的处理时间用于计算每个跟踪和检测组合的成本分配。您看到了如何使用成本计算阈值来改进用于计算分配成本的时间。此外,该示例还展示了如何使用外部成本计算,对于您遇到的特定跟踪问题,外部成本计算可能被设计为计算效率更高。

可以降低成本分配阈值或使用外部成本计算来提高的速度trackerJPDAtrackerTOMHT

金宝app支持功能

createPlatforms

该函数在20x20网格中创建平台,每个网格单元有2x2个平台。

函数[platforms,tp,zoomedtp] = createPlatforms .[平台,tp,zoomedtp] = createPlatforms .这是一个辅助函数,用于运行跟踪器并显示结果。它%将来可能会被删除。Nh = 15;%水平网格单元格数Nv = 15;%垂直网格单元格数NSQ = 2;% 2x2平台在网格单元格中nPl = nh*nv*nsq^2;%平台总数XGV = sort(-50 + repmat(100 * (1:nh), [1 nsq]));Ygv = sort(-50 + repmat(100 * (1:nv), [1 nsq]));[X,Y] = meshgrid(xgv,ygv);NPTS = nsq/2;Xshift = 10*((-npts+1):npts) -5;Yshift = xshift;Xadd = repmat(xshift, [1 nh]);Yadd = repmat(yshift, [1 nv]);[Xx, Yy] = meshgrid(xadd,yadd);X = X + Xx; Y = Y + Yy; pos = [X(:),Y(:),zeros(numel(X),1)];下面的代码为平台创建一个struct数组%稍后用于跟踪分配指标。Vel = [3 10 0];%平台速度平台= repmat(struct(“PlatformID”, 1“位置”, [0 0 0],“速度”韦尔),不良贷款,1);i = 1:nPl平台(i)。PlatformID = i;平台(i).Position(:) = pos(i,:);结束%的可视化F =数字(“位置”,[1 1 1425 700]);movegui中心;H1 = uipanel(f,“字形大小”12“位置”,(。01 .01 .48 .98],“标题”“场景视图”);A1 =坐标轴(h1,“位置”,[0.05 0.05 0.9 0.9]);tp = theaterPlot(“父”a1,“XLimits”[0 nh * 100],“YLimits”[0 nv * 100]);集(a1,“XTick”0:100: nh * 100)集(a1,“YTick”0:100: nv * 100)网格pp = trackPlotter(tp,“标签”“真相”“标记”“^”“MarkerEdgeColor”“k”“MarkerSize”4“HistoryDepth”10);plotTrack (pp、重塑([platforms.Position] 3 []) ');trackPlotter (tp,“标签”“跟踪”“MarkerEdgeColor”“b”“MarkerSize”6“HistoryDepth”10);C = get(a1;父母,“孩子”);I = 1:数字(c)如果isa (c(我),“matlab.graphics.illustration.Legend”)组(c(我),“可见”“关闭”结束结束H2 = uipanel(f,“字形大小”12“位置”,(。51 .01 .48 .98],“标题”“放大视图”);A2 =坐标轴(h2,“位置”,[0.05 0.05 0.9 0.9]);zoomedtp = theaterPlot(“父”a2“XLimits”(400 500),“YLimits”500年[400]);集(a2,“XTick”400:100:500)组(a2,“YTick”400:100:500电网)zoomedpp = trackPlotter(zoomedtp,“DisplayName的”“真相”“标记”“^”“MarkerEdgeColor”“k”“MarkerSize”6“HistoryDepth”10);plotTrack (zoomedpp重塑([platforms.Position] 3 []) ');trackPlotter (zoomedtp“DisplayName的”“跟踪”“MarkerEdgeColor”“b”“MarkerSize”8“HistoryDepth”10“ConnectHistory”“上”“字形大小”1);结束

runTracker

这个函数运行跟踪器,更新绘图仪,并收集轨道分配指标。

函数[trkSummary,truSummary,info] = runTracker(平台,跟踪器,positionSelector,tp,zoomedtp)这是一个辅助函数,用于运行跟踪器并显示结果。它%将来可能会被删除。pp = findPlotter(tp,“标签”“真相”);trp = findPlotter(tp,“标签”“跟踪”);zoomedpp = findPlotter(zoomedtp,“DisplayName的”“真相”);zoomedtrp = findPlotter(zoomedtp,“DisplayName的”“跟踪”);为了节省时间,请预先分配所有检测并动态分配。。nPl =数字(平台);det = objectDetection(0,[0;0;0]);dets = repmat({det},[nPl,1]);定义一个轨道分配指标对象。tam = trackAssignmentMetrics;将可视化恢复。集(tp.Parent.Parent.Parent,“可见”“上”hasExternalCostFunction = tracker.HasCostMatrixInput;测量设置跟踪器所需的时间。抽搐如果~ isLocked(跟踪)如果hasExternalCostFunction设置(追踪,侦破,0,0);其他的设置(追踪,侦破,0);结束结束重置(跟踪)disp (跟踪器设置时间:+ toc);运行5步,对所有平台进行检测。T = 1:5i = 1:nPl dets{i}。时间= t;依据我{}。测量=平台(i).位置(:);结束抽搐如果hasExternalCostFunction如果isLocked(跟踪)使用predictTracksToTime获取所有的预测曲目。allTracks = predictTracksToTime(跟踪器,“所有”t);其他的allTracks = [];结束costMatrix = predictedEuclidean(allTracks,dets,positionSelector);[tracks,~,~,info] = tracker(dets,t,costMatrix);其他的[tracks,~,~,info] =跟踪器(dets,t);结束trPos = getTrackPositions(tracks, positionSelector);trIDs = string([tracks.TrackID]');disp (“步骤”+ t +“时间:”+ toc)%更新情节。plotTrack (pp、重塑([platforms.Position] 3 []) ');trPos plotTrack (trp);plotTrack (zoomedpp重塑([platforms.Position] 3 []) ');plotTrack (zoomedtrp trPos trIDs);drawnow更新轨道分配指标对象。如果nargout [trkSummary, truSummary] = tam(轨道,平台);结束更新平台位置。i = 1:nPl平台(i)。位置=平台(i)。位置+平台(i).速度;结束结束snapnow%运行没有检测到的步骤,直到跟踪器删除所有轨道。disp (“从现在开始的所有步骤都不会被发现。”~isempty(tracks) t = t+1;抽搐如果hasExternalCostFunction allTracks = predictTracksToTime(跟踪器,“所有”t);costMatrix = predictedEuclidean(allTracks,{},positionSelector);tracks = tracker({},t,costMatrix);其他的Tracks = tracker({},t);结束disp (“步骤”+ t +“时间:”+ toc)更新轨道的位置以绘图。%trPos = getTrackPositions(tracks,positionSelector);trIDs = string([tracks.TrackID]');%更新情节。plotTrack (pp、重塑([platforms.Position] 3 []) ');trPos plotTrack (trp);plotTrack (zoomedpp重塑([platforms.Position] 3 []) ');plotTrack (zoomedtrp trPos trIDs);drawnow更新平台位置。i = 1:nPl平台(i)。位置=平台(i)。位置+平台(i).速度;结束结束disp (”场景。所有音轨现在都被删除了。”+换行符)clearData(pp) clearData(trp) clearData(zoomedpp) clearData(zoomedtrp) set(tp.Parent.Parent.Parent)“可见”“关闭”%防止快照过多drawnow结束

predictedEuclidean

该函数计算来自探测的测量位置和来自航迹的预测位置之间的欧几里得距离。

函数euclidDist = predictedEuclidean(轨道,检测,位置选择器)这是一个辅助函数,用于运行跟踪器并显示结果。它%将来可能会被删除。如果isempty(轨道)|| isempty(检测)euclidDist =零(数字(轨道),数字(检测));返回结束predictedStates = [tracks.State];predictedPositions = positionSelector * predictedStates;Dets =[检测{:}];measuredPositions = [dts . measurement];euclidDist =零(数字(轨道),数字(检测));i = 1:数字(检测)diff = bsxfun(@minus, predictedPositions',measuredPositions(:,i)');euclidDist(:,i) =√(sum((diffs .* diffs),2));结束结束

assignmentMetricsSummary

该函数以表格形式显示关键分配指标。

函数assignmentMetricsSummary(trkSummary,truSummary) trkSummary = rmfield(trkSummary, {“TotalSwapCount”“TotalDivergenceCount”...“TotalDivergenceLength”“MaxRedundancyCount”“TotalRedundancyCount”...“MaxRedundancyLength”“TotalRedundancyLength”});truSummary = rmfield(truSummary, {“TotalEstablishmentLength”“TotalBreakCount”...“MaxBreakLength”“TotalBreakLength”});trkTable = struct2table(trkSummary);truTable = struct2table(truSummary);disp ("跟踪分配指标总结:"(trkTable表)“真值赋值指标总结:”) disp (truTable)结束