主要内容

如何有效地跟踪对象的大数

这个例子说明了如何使用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日);positionSelector = [1 0 0 0 0;0 0 1 0 0 0;0 0 0 0 0];

在第一次调用step时,跟踪器实例化所有跟踪。要将实例化轨道所需的时间与第一步所需的处理时间隔离开来,可以调用设置重启前步进跟踪。见支持函数金宝apprunTracker在这个例子中了解更多详情的结束。

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

从现在开始的所有步骤都不会被发现。步骤6时间:0.53103步骤7时间:0.52582步骤8时间:0.50639步骤9时间:0.50909步骤10时间:0.16034方案完成。所有轨道现在都被删除了。

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

assignmentMetricsSummary (trkSummary truSummary)
轨道分配指标摘要:TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength ______________ ______________ ____________ __________________ ___________________ 900 0 0 0 0真理分配指标摘要:TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount ______________ ________________ ______________________ _____________ 900 0 1 0

使用粗糙分配成本计算

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

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

厘米= info.CostMatrix;disp (“成本矩阵有”+元素个数(cm) +“元素”。);disp ("但有限值的数量是"+ numel(cm(isfinite(cm))) + newline)
成本矩阵有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时间:0.51446步骤7时间:0.52277步骤8时间:0.54865步骤9时间:0.50941步骤10时间: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时间:0.60809步骤7时间:0.61374步骤8时间:0.616步骤9时间:0.63798步骤10时间: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第四步时间:3.1212第5步时间:3.1458

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

Jonker-Volgenant算法执行第二步分配的速度比默认Munkres算法快。

蒙特卡罗模拟

如果你想在不修改跟踪器设置运行多个方案,也没有必要调用释放方法。相反,只要打电话给重启方法从跟踪器中清除以前的跟踪信息。这样,您就节省了实例化所有轨道所需的时间。注意下面的“跟踪器设置时间”相对于以前的运行。

复位(跟踪器)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平台的平台。

函数(平台、tp zoomedtp) = createPlatforms这是一个helper函数,用于运行跟踪器并显示结果。它%可能在将来被移除。nh = 15;水平网格细胞的%数nv = 15;%垂直网格单元格数nsq = 2;网格单元格中的% 2x2平台不良贷款= 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);《不扩散核武器条约》= 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)];%以下创建结构为平台,这是一个数组%稍后用于跟踪分配指标。VEL = [3 1 0];%平台速度平台= repmat(结构体(“PlatformID”, 1“位置”,[0 0 0],“速度”韦尔),不良贷款,1);i = 1:nPl平台(i)。PlatformID =我;平台(我).Position (,) = pos(我:);结束%的可视化图(f =“位置”,[1 1 1425 700]);movegui中央;h1 = uipanel (f,'字体大小'12“位置”[01 0.01 0.48 0.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)网格页= trackPlotter (tp,'标签''真相'“标记”“^”'MarkerEdgeColor'数k“MarkerSize”4,“HistoryDepth”10);plotTrack (pp、重塑([platforms.Position] 3 []) ');trackPlotter (tp,'标签'“跟踪”'MarkerEdgeColor'“b”“MarkerSize”6“HistoryDepth”10);c = (a1。父母,“孩子”);i = 1:元素个数(c)如果isa (c(我),“matlab.graphics.illustration.Legend”)组(c(我),'可见的''离开'结束结束h2 = uipanel (f,'字体大小'12“位置”,(。50.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信息]= runTracker(平台、跟踪positionSelector、tp zoomedtp)这是一个helper函数,用于运行跟踪器并显示结果。它%可能在将来被移除。PP = findPlotter(TP,'标签''真相');TRP = findPlotter(TP,'标签'“跟踪”);zoomedpp = findPlotter (zoomedtp,“DisplayName的”'真相');zoomedtrp = findPlotter (zoomedtp,“DisplayName的”“跟踪”);%为了节省时间,预先分配所有的检测并动态分配它们。不良贷款=元素个数(平台);侦破= objectDetection (0, 0, 0, 0));依据= repmat({侦破},[不良贷款,1]);定义一个轨道分配指标对象。tam = trackAssignmentMetrics;%带来的可视化回来。集(tp.Parent.Parent.Parent,'可见的'“上”)hasExternalCostFunction = tracker.HasCostMatrixInput;%测量需要设置跟踪了时间。抽搐如果~ isLocked(跟踪)如果hasExternalCostFunction设置(追踪,侦破,0,0);其他的设置(追踪,侦破,0);结束结束复位(跟踪器)DISP(“跟踪器设置时间:”+ TOC);%对所有平台运行5步检测。t = 1:5i = 1:nPl det {i}。时间= t;依据我{}。测量=平台(i) .Position (:);结束抽搐如果hasExternalCostFunction如果isLocked(跟踪)%用途predictTracksToTime让所有的预测轨迹。allTracks = predictTracksToTime(追踪,“所有”t);其他的allTracks = [];结束costMatrix = predictedEuclidean(allTracks,dets的,positionSelector);[轨道,〜,〜,信息] =跟踪器(dets的,吨,costMatrix);其他的[痕迹,~,~,信息]=追踪(侦破,t);结束trPos = getTrackPositions(轨道,位置选择器);trIDs =字符串([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)。位置+平台(我).Velocity;结束结束snapnow%在没有检测的情况下运行步骤,直到跟踪器删除所有轨道。disp (“从现在开始的所有步骤都不会被发现。”~isempty(tracks) t = t+1;抽搐如果hasExternalCostFunction allTracks = predictTracksToTime(跟踪器,“所有”t);costMatrix = predictedEuclidean(allTracks,{},positionSelector);曲目=跟踪器({},T,costMatrix);其他的跟踪=追踪({},t);结束disp (“步骤”+ t +“ 时间: ”+ toc)%更新曲目情节的位置。trPos = getTrackPositions(跟踪、positionSelector);trIDs =字符串([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)。位置+平台(我).Velocity;结束结束disp (”场景。所有的音轨现在都被删除了。”+ newline) clearData(pp) clearData(trp) clearData(zoomedpp) clearData(zoomedtrp) set(tp.Parent.Parent.Parent,'可见的''离开'%防止过度快照drawnow结束

predictedEuclidean

的函数计算从检测测量位置和从轨道预测位置之间的欧几里得距离。

函数euclidDist = predictedEuclidean(跟踪、检测、positionSelector)这是一个helper函数,用于运行跟踪器并显示结果。它%可能在将来被移除。如果isempty(tracks) || isempty(detections) euclidDist = 0 (numel(tracks),numel(detections));返回结束predictedStates = [tracks.State];predictedPositions = positionSelector * predictedStates;依据=(检测{:});measuredPositions = [dets.Measurement];euclidDist = 0(元素个数(跟踪),元素个数(检测);i = 1:numel(检测)diffs = bsxfun(@minus, predictedPositions',measuredPositions(:,i)');euclidDist(:,i) =√(sum((diff .* diff),2));结束结束

assignmentMetricsSummary

的功能显示在一个表中的形式键分配指标。

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