exponenta event banner

Как эффективно отслеживать большое количество объектов

В этом примере показано, как использовать 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 рассчитываются точно. Расчет грубых затрат показан на рисунке ниже. Обнаружение представлено его измерительным$z$ и измерительным шумом. $R$Две дорожки предсказываются на время обнаружения и проецируются на измерительное пространство, изображаемое точками$z_{e_1}$ и. $z_{e_2}$Заметим, что неопределенность дорожки не проецируется на пространство измерения, что позволяет векторизировать грубый расчет. Это грубая оценка, потому что учитывается только неопределенность вокруг обнаружения. В изображенном примере первая дорожка падает за пределы стробированного логического элемента вычисления, в то время как вторая дорожка падает внутри него. Таким образом, точное вычисление стоимости выполняется только для комбинации этого обнаружения и второй дорожки.

Для использования грубого расчета затрат деблокируйте трекер и измените его 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

Другим вариантом является использование другого алгоритма назначения 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