В этом примере показано, как использовать trackerGNN
отслеживать большое количество целей. Подобные методы могут быть применены к trackerJPDA
и trackerTOMHT
также.
Во многих приложениях трекеры обязаны отслеживать сотни или тысячи объектов. Увеличение количества треков, поддерживаемых трекером, является проблемой, вызванной вычислительной сложностью алгоритма в основе каждого трекера. В частности, не легко масштабироваться два распространенных этапа на шаге обновления трекера: вычисление стоимости присвоения и выполнение присвоения. Расчет затрат на присвоение является общим для trackerGNN
, trackerJPDA
, и trackerTOMHT
и методы, показанные в этом примере, могут быть применены при использовании любого из этих трекеров. То, как каждый трекер выполняет назначение, является уникальным для каждого трекера и может потребовать индивидуальных решений для улучшения эффективности трекера, которые выходят за возможности этого примера.
Сценарий
В целях этого примера вы задаете сценарий, который содержит 900 платформ, организованных в сетку 15 на 15, с каждой сеткой камеры содержащей 4 платформы. Цель камер сетки состоит в том, чтобы продемонстрировать преимущества вычисления крупных затрат, объясненные ниже в примере.
Следующий код упорядочивает 900 объектов в камере сетки и создает визуализацию. Слева показан весь сценарий. Справа визуализация масштабируется на 4 камерах сетки. Обратите внимание, что каждая камера содержит 4 платформы.
[platforms,tp,zoomedtp] = createPlatforms;
В этом разделе показаны результаты отслеживания платформ, определенных выше, с помощью trackerGNN
с параметрами по умолчанию AssignmentThreshold
. The 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
метод для удаления предыдущей информации о трекере. Таким образом, вы экономите время, необходимое для создания экземпляров всех треков. Обратите внимание на «Время настройки трекера» ниже относительно предыдущих запусков.
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