В этом примере показано, как использовать trackerGNN для отслеживания большого количества целей. Аналогичные методы могут быть применены к trackerJPDA и trackerTOMHT также.
Во многих приложениях от трекеров требуется отслеживать сотни или тысячи объектов. Увеличение числа дорожек, поддерживаемых трекером, является проблемой, вызванной вычислительной сложностью алгоритма в основе каждого трекера. В частности, два общих этапа на этапе обновления трекера не легко масштабируются: вычисление стоимости назначения и выполнение назначения. Расчет затрат на присвоение является общим для trackerGNN, trackerJPDA, и trackerTOMHTи методы, показанные в этом примере, могут быть применены при использовании любого из этих трекеров. Способ, которым каждый трекер выполняет назначение, уникален для каждого трекера и может потребовать специальных решений для повышения производительности трекера, которые выходят за рамки данного примера.
Сценарий
Для целей этого примера определяется сценарий, содержащий 900 платформ, организованных в сетке 15 на 15, при этом каждая ячейка сетки содержит 4 платформы. Целью ячеек сетки является демонстрация преимуществ расчета грубых затрат, поясненных ниже в примере.
Следующий код упорядочивает 900 объектов в ячейке сетки и создает визуализацию. Слева показан весь сценарий. Справа изображение увеличивается на 4 ячейки сетки. Обратите внимание, что каждая ячейка содержит 4 платформы.
[platforms,tp,zoomedtp] = createPlatforms;
![]()
В этом разделе показаны результаты отслеживания платформ, определенных выше, с помощью trackerGNN со значением по умолчанию AssignmentThreshold. AssignmentThreshold свойство содержит два значения: [C1 C2], где C1 - порог, используемый для назначения и C2 - пороговое значение для грубого вычисления, поясненное в следующем разделе.
Когда трекер обновляется новым набором обнаружений, он вычисляет стоимость назначения каждого обнаружения каждой дорожке. Точный расчет стоимости должен учитывать измерение и неопределенность каждого обнаружения, а также ожидаемое измерение и ожидаемую неопределенность от каждой дорожки, как показано ниже.

По умолчанию C2 имеет значение Inf, что требует вычисления затрат на все комбинации дорожки и обнаружения. Это приводит к более точному назначению, но является более вычислительной интенсивностью. Необходимо начать с настройки по умолчанию, чтобы убедиться, что трекер назначает обнаружения трекам наилучшим образом, а затем рассмотреть возможность снижения значения C2 сокращение времени, необходимого для расчета стоимости присвоения.
Во время расчета затрат присвоения элементы матрицы затрат, значения которых превышают C1 заменяются на Inf. Это помогает алгоритму назначения игнорировать невозможные назначения.
Определите трекер, который может отслеживать до 1000 дорожек. Трекер использует фильтр Калмана с постоянной скоростью по умолчанию, и его состояние определяется как [x;vx;y;vy;z;vz], который используется positionSelector ниже, чтобы получить компоненты позиции.
tracker = trackerGNN('MaxNumTracks',1000, 'AssignmentThreshold', [30 Inf]); positionSelector = [1 0 0 0 0 0; 0 0 1 0 0 0; 0 0 0 0 0 0];
При первом вызове шага трекер создает экземпляры всех дорожек. Чтобы изолировать время, необходимое для создания экземпляров дорожек, от времени обработки, необходимого для первого шага, можно вызвать setup и reset перед шагом трекера. См. вспомогательную функцию runTracker в конце этого примера для получения более подробной информации.
[trkSummary,truSummary,info] = runTracker(platforms,tracker,positionSelector,tp,zoomedtp);
Tracker set up time: 8.3108 Step 1 time: 3.7554 Step 2 time: 15.3029 Step 3 time: 14.1099 Step 4 time: 14.3506 Step 5 time: 14.3963
![]()
All steps from now are without detections. Step 6 time: 0.53103 Step 7 time: 0.52582 Step 8 time: 0.50639 Step 9 time: 0.50909 Step 10 time: 0.16034 Scenario done. All tracks are now deleted.
Результаты отслеживания анализируются путем анализа значений метрик назначения дорожек. Для идеального отслеживания общее количество дорожек должно быть равно количеству платформ и не должно быть ложных, заменяемых или расходящихся дорожек. Точно так же не должно быть отсутствующей правды или разрывов в резюме правды.
assignmentMetricsSummary(trkSummary,truSummary)
Track assignment metrics summary:
TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength
______________ ______________ ____________ __________________ ___________________
900 0 0 0 0
Truth assignment metrics summary:
TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount
______________ ________________ ______________________ _____________
900 0 1 0
В предыдущем разделе вы видели, что трекер способен отслеживать все платформы, но каждый шаг обновления занимает много времени. Большая часть времени была потрачена на расчет матрицы затрат на присвоение.
Рассматривая матрицу затрат, можно увидеть, что подавляющее большинство ее элементов, по сути, Inf.
cm = info.CostMatrix; disp("Cost matrix has " + numel(cm) + " elements."); disp("But the number of finite values is " + numel(cm(isfinite(cm))) + newline)
Cost matrix has 810000 elements. But the number of finite values is 2700
Вышеприведенный результат показывает, что вычисление затрат тратит слишком много времени на вычисление стоимости назначения всех комбинаций дорожки и обнаружения. Однако большинство этих комбинаций слишком далеко для назначения, так как фактическое измерение слишком далеко от ожидаемого измерения на основе характеристик датчика. Во избежание расточительства при расчете всех затрат можно использовать расчет грубых затрат.
Грубый расчет выполняется для проверки того, какие комбинации пути и обнаружения могут потребовать точного нормализованного расчета расстояния. Только комбинации, грубая стоимость присвоения которых ниже C2 рассчитываются точно. Расчет грубых затрат показан на рисунке ниже. Обнаружение представлено его измерительным
и измерительным шумом.
Две дорожки предсказываются на время обнаружения и проецируются на измерительное пространство, изображаемое точками
и.
Заметим, что неопределенность дорожки не проецируется на пространство измерения, что позволяет векторизировать грубый расчет. Это грубая оценка, потому что учитывается только неопределенность вокруг обнаружения. В изображенном примере первая дорожка падает за пределы стробированного логического элемента вычисления, в то время как вторая дорожка падает внутри него. Таким образом, точное вычисление стоимости выполняется только для комбинации этого обнаружения и второй дорожки.

Для использования грубого расчета затрат деблокируйте трекер и измените его AssignmentThreshold до значения [30 200]. Затем снова запустите трекер.
release(tracker) tracker.AssignmentThreshold = [30 200]; [trkSummary,truSummary] = runTracker(platforms,tracker,positionSelector,tp,zoomedtp);
Tracker set up time: 6.5846 Step 1 time: 3.5863 Step 2 time: 3.4095 Step 3 time: 2.9347 Step 4 time: 2.8555 Step 5 time: 2.9397
![]()
All steps from now are without detections. Step 6 time: 0.51446 Step 7 time: 0.52277 Step 8 time: 0.54865 Step 9 time: 0.50941 Step 10 time: 0.19085 Scenario done. All tracks are now deleted.
Следует отметить, что для выполнения шагов 3-5 теперь требуется значительно меньше времени. Шаг 2 также быстрее, чем раньше, но все же медленнее, чем шаги 3-5.
Чтобы понять, почему шаг 2 медленнее, рассмотрите состояния дорожки после первого обновления трекера. Состояния содержат информацию о положении, но скорость по-прежнему равна нулю. Когда трекер вычисляет стоимость назначения, он предсказывает состояния дорожки до времени обнаружения, но поскольку дорожки имеют нулевую скорость, они остаются в том же положении. Это приводит к большим расстояниям между измерениями обнаружения и ожидаемыми измерениями из предсказанных состояний дорожки. Эти относительно большие затраты на назначение затрудняют алгоритм назначения найти наилучшее назначение, что приводит к тому, что шаг 2 занимает больше времени, чем шаги 3-5.
Важно проверить, что назначение пути с грубым расчетом затрат остается таким же, как и без него. Если метрики назначения дорожек не совпадают, необходимо увеличить размер элемента грубого расчета. Следующее показывает, что отслеживание все еще является идеальным, как это было в предыдущем разделе, но каждый шаг обработки занимает меньше времени.
assignmentMetricsSummary(trkSummary,truSummary)
Track assignment metrics summary:
TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength
______________ ______________ ____________ __________________ ___________________
900 0 0 0 0
Truth assignment metrics summary:
TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount
______________ ________________ ______________________ _____________
900 0 1 0
Другой способ управления временем, которое требуется для расчета присвоения затрат, заключается в использовании собственного расчета затрат на присвоение вместо значения по умолчанию, используемого трекером.
При расчете внешних затрат могут учитываться атрибуты, которые не являются частью состояния дорожки и ожидаемого измерения. Он также может использовать различные метрики расстояния, например евклидову норму вместо нормированного расстояния. Выбор применяемого расчета стоимости зависит от специфики задачи, пространства измерения и способа определения состояния и измерения.
Для использования внешнего расчета затрат деблокируйте трекер и установите его HasCostMatrixInput свойство имеет значение true. Необходимо передать собственную матрицу затрат в качестве дополнительного ввода с каждым обновлением в трекер. См. вспомогательную функцию runTracker для получения дополнительной информации.
release(tracker); tracker.HasCostMatrixInput = true; [trkSummary,truSummary] = runTracker(platforms,tracker,positionSelector,tp,zoomedtp); assignmentMetricsSummary(trkSummary,truSummary)
Tracker set up time: 6.559 Step 1 time: 3.4394 Step 2 time: 1.7852 Step 3 time: 1.474 Step 4 time: 1.5312 Step 5 time: 1.5152
![]()
All steps from now are without detections.
Step 6 time: 0.60809
Step 7 time: 0.61374
Step 8 time: 0.616
Step 9 time: 0.63798
Step 10 time: 0.22762
Scenario done. All tracks are now deleted.
Track assignment metrics summary:
TotalNumTracks NumFalseTracks MaxSwapCount MaxDivergenceCount MaxDivergenceLength
______________ ______________ ____________ __________________ ___________________
900 0 0 0 0
Truth assignment metrics summary:
TotalNumTruths NumMissingTruths MaxEstablishmentLength MaxBreakCount
______________ ________________ ______________________ _____________
900 0 1 0
Как и ожидалось, время обработки еще меньше при использовании внешней функции расчета затрат.
Другим вариантом является использование другого алгоритма назначения GNN, который может быть более эффективным в поиске назначения путем изменения Assignment свойство трекера.
release(tracker)
tracker.Assignment = 'Jonker-Volgenant';
tracker.HasCostMatrixInput = true;
runTracker(platforms,tracker,positionSelector,tp,zoomedtp);
Tracker set up time: 6.494 Step 1 time: 3.5346 Step 2 time: 1.894 Step 3 time: 3.1192 Step 4 time: 3.1212 Step 5 time: 3.1458
![]()
All steps from now are without detections. Step 6 time: 0.61109 Step 7 time: 0.62456 Step 8 time: 0.61849 Step 9 time: 0.60604 Step 10 time: 0.22303 Scenario done. All tracks are now deleted.
Алгоритм Йонкера-Волгенера выполняет назначение на втором шаге быстрее относительно алгоритма Манкра по умолчанию.
Если требуется выполнить несколько сценариев без изменения настроек трекера, нет необходимости вызывать release способ. Вместо этого, просто позвоните reset способ очистки информации предыдущей дорожки от трекера. Таким образом, вы экономите время, необходимое для создания экземпляров всех дорожек. Обратите внимание на приведенное ниже «Tracker setup up time» относительно предыдущих запусков.
reset(tracker) runTracker(platforms,tracker,positionSelector,tp,zoomedtp);
Tracker set up time: 0.097531 Step 1 time: 3.4684 Step 2 time: 1.6592 Step 3 time: 3.1429 Step 4 time: 3.1274 Step 5 time: 3.0994
![]()
All steps from now are without detections. Step 6 time: 0.63232 Step 7 time: 0.61857 Step 8 time: 0.61433 Step 9 time: 0.60698 Step 10 time: 0.25301 Scenario done. All tracks are now deleted.
В этом примере показано, как отслеживать большое количество объектов. При отслеживании многих объектов трекер тратит большую часть времени на обработку при вычислении назначения затрат для каждой комбинации дорожки и обнаружения. Было показано, как использовать порог расчета затрат для увеличения времени, затрачиваемого на расчет затрат на присвоение. Кроме того, в примере показано, как использовать расчет внешних затрат, который может быть разработан для повышения вычислительной эффективности для конкретной проблемы отслеживания.
Можно уменьшить порог присвоения затрат или использовать внешний расчет затрат для повышения скорости trackerJPDA и trackerTOMHT также.
createPlatforms
Эта функция создает платформы в сетке 20x20 с платформами 2x2 на ячейку сетки.
function [platforms,tp,zoomedtp] = createPlatforms % This is a helper function to run the tracker and display the results. It % may be removed in the future. nh = 15; % Number of horizontal grid cells nv = 15; % Number of vertical grid cells nsq = 2; % 2x2 platforms in a grid cell nPl = nh*nv*nsq^2; % Overall number of platforms 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)]; % The following creates an array of struct for the platforms, which are % used later for track assignment metrics. vel = [3 1 0]; % Platform velocity platforms = repmat(struct('PlatformID', 1, 'Position', [0 0 0], 'Velocity', vel),nPl,1); for i = 1:nPl platforms(i).PlatformID = i; platforms(i).Position(:) = pos(i,:); end % Visualization f = figure('Position',[1 1 1425 700]); movegui center; h1 = uipanel(f,'FontSize',12,'Position',[.01 .01 .48 .98],"Title","Scene View"); a1 = axes(h1,'Position',[0.05 0.05 0.9 0.9]); tp = theaterPlot('Parent', a1, 'XLimits',[0 nh*100], 'YLimits',[0 nv*100]); set(a1,'XTick',0:100:nh*100) set(a1,'YTick',0:100:nv*100) grid on pp = trackPlotter(tp,'Tag','Truth','Marker','^','MarkerEdgeColor','k','MarkerSize',4,'HistoryDepth',10); plotTrack(pp,reshape([platforms.Position],3,[])'); trackPlotter(tp, 'Tag','Tracks','MarkerEdgeColor','b','MarkerSize',6,'HistoryDepth',10); c = get(a1.Parent,'Children'); for i = 1:numel(c) if isa(c(i),'matlab.graphics.illustration.Legend') set(c(i),'Visible','off') end end h2 = uipanel(f,'FontSize',12,'Position',[.51 .01 .48 .98],'Title','Zoomed View'); a2 = axes(h2,'Position',[0.05 0.05 0.9 0.9]); zoomedtp = theaterPlot('Parent', a2, 'XLimits',[400 500], 'YLimits',[400 500]); set(a2,'XTick',400:100:500) set(a2,'YTick',400:100:500) grid on zoomedpp = trackPlotter(zoomedtp,'DisplayName','Truth','Marker','^','MarkerEdgeColor','k','MarkerSize',6,'HistoryDepth',10); plotTrack(zoomedpp,reshape([platforms.Position],3,[])'); trackPlotter(zoomedtp, 'DisplayName','Tracks','MarkerEdgeColor','b','MarkerSize',8,'HistoryDepth',10,'ConnectHistory','on','FontSize',1); end
runTracker
Эта функция запускает трекер, обновляет плоттеры и собирает метрики назначения дорожек.
function [trkSummary,truSummary,info] = runTracker(platforms,tracker,positionSelector,tp,zoomedtp) % This is a helper function to run the tracker and display the results. It % may be removed in the future. pp = findPlotter(tp,'Tag','Truth'); trp = findPlotter(tp, 'Tag','Tracks'); zoomedpp = findPlotter(zoomedtp,'DisplayName','Truth'); zoomedtrp = findPlotter(zoomedtp, 'DisplayName','Tracks'); % To save time, pre-allocate all the detections and assign them on the fly. nPl = numel(platforms); det = objectDetection(0,[0;0;0]); dets = repmat({det},[nPl,1]); % Define a track assignment metrics object. tam = trackAssignmentMetrics; % Bring the visualization back. set(tp.Parent.Parent.Parent,'Visible','on') hasExternalCostFunction = tracker.HasCostMatrixInput; % Measure the time it takes to set the tracker up. tic if ~isLocked(tracker) if hasExternalCostFunction setup(tracker,dets,0,0); else setup(tracker,dets,0); end end reset(tracker) disp("Tracker set up time: " + toc); % Run 5 steps with detections for all the platforms. for t = 1:5 for i = 1:nPl dets{i}.Time = t; dets{i}.Measurement = platforms(i).Position(:); end tic if hasExternalCostFunction if isLocked(tracker) % Use predictTracksToTime to get all the predicted tracks. allTracks = predictTracksToTime(tracker,'all',t); else allTracks = []; end costMatrix = predictedEuclidean(allTracks,dets,positionSelector); [tracks,~,~,info] = tracker(dets,t,costMatrix); else [tracks,~,~,info] = tracker(dets,t); end trPos = getTrackPositions(tracks, positionSelector); trIDs = string([tracks.TrackID]'); disp("Step " + t + " time: " + toc) % Update the plot. plotTrack(pp,reshape([platforms.Position],3,[])'); plotTrack(trp,trPos); plotTrack(zoomedpp,reshape([platforms.Position],3,[])'); plotTrack(zoomedtrp,trPos,trIDs); drawnow % Update the track assignment metrics object. if nargout [trkSummary, truSummary] = tam(tracks,platforms); end % Update the platform positions. for i = 1:nPl platforms(i).Position = platforms(i).Position + platforms(i).Velocity; end end snapnow % Run steps with no detections until the tracker deletes all the tracks. disp("All steps from now are without detections.") while ~isempty(tracks) t = t+1; tic if hasExternalCostFunction allTracks = predictTracksToTime(tracker,'all',t); costMatrix = predictedEuclidean(allTracks,{},positionSelector); tracks = tracker({},t,costMatrix); else tracks = tracker({},t); end disp("Step " + t + " time: " + toc) % Update the position of the tracks to plot. trPos = getTrackPositions(tracks,positionSelector); trIDs = string([tracks.TrackID]'); % Update the plot. plotTrack(pp,reshape([platforms.Position],3,[])'); plotTrack(trp,trPos); plotTrack(zoomedpp,reshape([platforms.Position],3,[])'); plotTrack(zoomedtrp,trPos,trIDs); drawnow % Update the platform positions. for i = 1:nPl platforms(i).Position = platforms(i).Position + platforms(i).Velocity; end end disp("Scenario done. All tracks are now deleted." + newline) clearData(pp) clearData(trp) clearData(zoomedpp) clearData(zoomedtrp) set(tp.Parent.Parent.Parent,'Visible','off') % Prevent excessive snapshots drawnow end
predictedEuclidean
Функция вычисляет евклидово расстояние между измеренными позициями от обнаружений и предсказанными позициями от дорожек.
function euclidDist = predictedEuclidean(tracks,detections,positionSelector) % This is a helper function to run the tracker and display the results. It % may be removed in the future. if isempty(tracks) || isempty(detections) euclidDist = zeros(numel(tracks),numel(detections)); return end predictedStates = [tracks.State]; predictedPositions = positionSelector * predictedStates; dets = [detections{:}]; measuredPositions = [dets.Measurement]; euclidDist = zeros(numel(tracks),numel(detections)); for i = 1:numel(detections) diffs = bsxfun(@minus, predictedPositions',measuredPositions(:,i)'); euclidDist(:,i) = sqrt(sum((diffs .* diffs),2)); end end
assignmentMetricsSummary
Функция отображает метрики назначения ключей в табличной форме.
function 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("Track assignment metrics summary:") disp(trkTable) disp("Truth assignment metrics summary:") disp(truTable) end