Этот пример показывает, как отследить большое количество объектов. Многочисленная стая птиц сгенерирована, и глобальное самое близкое соседнее мультиобъектное средство отслеживания, trackerGNN
, используется, чтобы оценить движение каждой птицы в скоплении.
Движение скопления моделируется с помощью поведенческой модели, предложенной Рейнольдсом [1]. В этом примере скопление состоит из 1 000 моделируемых птиц, названных boids, исходное положение которого и скорость были ранее сохранены. Они следуют трем правилам скапливания: предотвращение столкновения, скоростное соответствие и центрирование скопления. Каждое правило сопоставлено с весом, и полное поведение скопления появляется из относительного взвешивания каждого правила. В этом случае веса выбраны, которые заставляют скопление облетать вокруг определенного момента и создавать плотный центр. Другие настройки веса могут заставить различные поведения появляться.
Отслеживание такого многочисленного и плотного скопления представляет собой две проблемы:
Как эффективно отследить 1000 boids?
Как смочь отследить отдельный boids в такой плотной среде?
Следующий код моделирует поведение скопления для 100 шагов 0,1 секунд. График слева показывает скопление в целом, и график справа увеличен масштаб самая плотная часть в центре скопления.
s = rng; % Keep the current state of the random number generator rng(2019); % Set the random number generator for repeatable results load("initialFlock.mat","x","v"); flock = helperFlock("NumBoids",size(x,1),"CollisionAviodanceWeight",0.5,... "VelocityMatchingWeight",0.1,"FlockCenteringWeight",0.5,"Velocity",v,... "Position",x,"BoidAcceleration",1); truLabels = string(num2str((1:flock.NumBoids)')); bound = 20; flockCenter = mean(x,1); [tp1,tp2] = helperCreateDisplay(x,bound); % Simulate 100 steps of flocking numSteps = 100; allx = repmat(x,[1 1 numSteps]); dt = 0.1; for i = 1:numSteps [x,v] = move(flock,dt); allx(:,:,i) = x; plotTrack(tp1.Plotters(1),x) inView = findInView(x,-bound+flockCenter,bound+flockCenter); plotTrack(tp2.Plotters(1),x(inView,:),truLabels(inView)) drawnow end
Вы задаете средство отслеживания как показано в примере, Как Эффективно Отследить Большие количества Объектов.
Вы замечаете, что boids следуют за изогнутым контуром и выбирают постоянную модель поворота, заданную initctekf
.
Чтобы ограничить время, требуемое вычислить стоимость, вы уменьшаете крупный порог расчета стоимости в AssignmentThreshold
к низкой стоимости.
Далее, вы выбираете более эффективный Jonker-Volgenant
в качестве алгоритма присвоения вместо алгоритма Munkres
по умолчанию.
Вы хотите, чтобы дорожки были быстро подтверждены и удалены, и устанавливаете пороги подтверждения и удаления к [2 3] и [2 2], соответственно.
Наконец, вы знаете, что датчик сканирует только часть скопления на любом данном сканировании, и таким образом, вы устанавливаете HasDetectableTrackIDsInput
на true
мочь передать обнаруживаемые идентификаторы дорожки средству отслеживания.
Следующая строка показывает, как средство отслеживания сконфигурировано с вышеупомянутыми свойствами. Вы видите, как сгенерировать код для средства отслеживания в том, Как Сгенерировать код С для Средства отслеживания, и средство отслеживания для этого примера сохранено в функции flockTracker_kernel.m
% tracker = trackerGNN("FilterInitializationFcn",@initctekf,"MaxNumTracks",1500,... % "AssignmentThreshold",[50 800],"Assignment","Jonker-Volgenant",... % "ConfirmationThreshold",[2 3],"DeletionThreshold",[2 2],... % "HasDetectableTrackIDsInput",true);
Затем, вы запускаете сценарий и отслеживаете скопление.
Упрощенная модель датчика моделируется с помощью функции поддерживающего detectFlock
. Это моделирует датчик, который сканирует скопление слева направо и получает одну пятую промежутка скопления в оси X на каждом сканировании. Датчик имеет 0,98 вероятности обнаружения, и шум моделируется с помощью нормального распределения со стандартным отклонением 0,1 метров о каждом компоненте положения.
Датчик сообщает о своих границах currentScan
, которые используются, чтобы предоставить обнаруживаемые идентификаторы дорожки средству отслеживания.
clear flockTracker_kernel positionSelector = [1 0 0 0 0 0 0; 0 0 1 0 0 0 0; 0 0 0 0 0 1 0]; trackIDs = zeros(0,1,'uint32'); trax = zeros(0,3); bounds = inf(3,2); alltrax = zeros(size(allx)); allIDs = repmat({},1,numSteps); trup2 = tp2.Plotters(1); trap2 = tp2.Plotters(2); trup2.HistoryDepth = 2*trap2.HistoryDepth; clearPlotterData(tp1) clearPlotterData(tp2) for i = 1:numSteps t = i*dt; [detections, currentScan] = detectFlock(allx(:,:,i),t); bounds(1,:) = currentScan; tracksInScan = findInView(trax,bounds(:,1),bounds(:,2)); [tracks,info] = flockTracker_kernel(detections,t,trackIDs(tracksInScan,1)); trax = getTrackPositions(tracks,positionSelector); if ~isempty(tracks) trackIDs = uint32([tracks.TrackID]'); else trackIDs = zeros(0,1,'uint32'); end alltrax(1:size(trax,1),1:3,i) = trax; allIDs{i} = string(trackIDs); helperVisualizeDisplay(tp1,tp2,truLabels,allx,allIDs,alltrax,i) end rng(s); % Reset the random number generator to its previous state
Следующий GIF показывает производительность средства отслеживания в файле MEX.
Этот пример показал, как отследить большое количество объектов в реалистическом сценарии, где датчик сканирования только сообщает о части объектов на каждом сканировании. Пример показал, как настроить средство отслеживания для большого количества объектов и как использовать обнаруживаемый вход IDs дорожки, чтобы препятствовать тому, чтобы дорожки были удалены.
[1] Крэйг В. Рейнольдс, "Скопления, стада и школы: поведенческая модель", компьютерная графика, издание 21, номер 4, июль 1987.
helperCreateDisplay
Функция создает отображение в качестве примера и возвращает указатель на оба театральных графика.
function [tp1,tp2] = helperCreateDisplay(x,bound) f = figure("Visible", "off"); set(f,"Position",[1 1 1425 700]); movegui(f,"center") h1 = uipanel(f,"FontSize",12,"Position",[.01 .01 .48 .98],"Title","Flock View"); h2 = uipanel(f,"FontSize",12,"Position",[.51 .01 .48 .98],"Title","Flock Center"); flockCenter = mean(x,1); a1 = axes(h1,'Position',[0.05 0.05 0.9 0.9]); grid(a1,'on') tp1 = theaterPlot("Parent",a1); % Flock View (Truncated) halfspan = 250; tp1.XLimits = 100*round([-halfspan+flockCenter(1) halfspan+flockCenter(1)]/100); tp1.YLimits = 100*round([-halfspan+flockCenter(2) halfspan+flockCenter(2)]/100); tp1.ZLimits = 100*round([-halfspan+flockCenter(3) halfspan+flockCenter(3)]/100); trackPlotter(tp1,"DisplayName","Truth","HistoryDepth",0,"Marker","^","MarkerSize",4,"ConnectHistory","off"); set(findall(a1,"Type","line","Tag","tpTrackHistory_Truth"),"Color","k"); view(a1,3) legend('Location','NorthEast') % Flock center a2 = axes(h2,'Position',[0.05 0.05 0.9 0.9]); grid(a2,'on') tp2 = theaterPlot("Parent",a2); tp2.XLimits = 10*round([-bound+flockCenter(1) bound+flockCenter(1)]/10); tp2.YLimits = 10*round([-bound+flockCenter(2) bound+flockCenter(2)]/10); tp2.ZLimits = 10*round([-bound+flockCenter(3) bound+flockCenter(3)]/10); trackPlotter(tp2,"DisplayName","Truth","HistoryDepth",0,... "Marker","^","MarkerSize",6,"ConnectHistory","off","FontSize",1); set(findall(a2,"Type","line","Tag","tpTrackHistory_Truth"),"Color","k"); % Track plotters TrackColor = [0 0.4470 0.7410]; % Blue TrackLength = 50; trackPlotter(tp1,"DisplayName","Tracks","HistoryDepth",TrackLength,"ConnectHistory","off",... "Marker",".","MarkerSize",3,"MarkerEdgeColor",TrackColor,"MarkerFaceColor",TrackColor); set(findall(tp1.Parent,"Type","line","Tag","tpTrackHistory_Tracks"),... "Color",TrackColor,"MarkerSize",3,"MarkerEdgeColor",TrackColor); trackPlotter(tp2,"DisplayName","Tracks","HistoryDepth",TrackLength,"ConnectHistory","on",... "Marker","s","MarkerSize",8,"MarkerEdgeColor",TrackColor,"MarkerFaceColor","none","FontSize",1); set (findall(tp2.Parent,"Type","line","Tag","tpTrackPositions_Tracks"),"LineWidth",2); set(findall(tp2.Parent,"Type","line","Tag","tpTrackHistory_Tracks"),"Color",TrackColor,"LineWidth",1); view(a2,3) legend('Location','NorthEast') set(f,'Visible','on') end
detectFlock
Функция моделирует модель датчика. Это возвращает массив обнаружений и пределов сканирования датчика тока.
function [detections,scanLimits] = detectFlock(x,t) persistent sigma allDetections currentScan numScans numBoids = size(x,1); pd = 0.98; if isempty(sigma) sigma = 0.1; oneDet = objectDetection(0,[0;0;0],"MeasurementNoise",sigma,'ObjectAttributes',struct); allDetections = repmat(oneDet,numBoids,1); currentScan = 1; numScans = 5; end % Vectorized calculation of all the detections x = x + sigma*randn(size(x)); [allDetections.Time] = deal(t); y = mat2cell(x',3,ones(1,size(x,1))); [allDetections.Measurement] = deal(y{:}); % Limit the coverage area based on the number of scans flockXSpan = [min(x(:,1),[],1),max(x(:,1),[],1)]; spanPerScan = (flockXSpan(2)-flockXSpan(1))/numScans; scanLimits = flockXSpan(1) + spanPerScan * [(currentScan-1) currentScan]; inds = and(x(:,1)>=scanLimits(1), x(:,1)<=scanLimits(2)); % Add Pd draw = rand(size(inds)); inds = inds & (draw<pd); dets = allDetections(inds); detections = num2cell(dets); % Promote the scan count currentScan = currentScan+1; if currentScan > numScans currentScan = 1; end end
findInView
Функция возвращает логический массив для положений, которые находятся в пределах пределов minBound
и maxBound
.
function inView = findInView(x,minBound,maxBound) inView = false(size(x,1),1); inView(:) = (x(:,1)>minBound(1) & x(:,1)<maxBound(1)) & ... (x(:,2)>minBound(2) & x(:,2)<maxBound(2)) & ... (x(:,3)>minBound(3) & x(:,3)<maxBound(3)); end
helperVisualizeDisplay
Функция отображает скопление и дорожки после отслеживания.
function helperVisualizeDisplay(tp1,tp2,truLabels,allx,allIDs,alltrax,i) trup1 = tp1.Plotters(1); trap1 = tp1.Plotters(2); trup2 = tp2.Plotters(1); trap2 = tp2.Plotters(2); plotTrack(trup1,allx(:,:,i)) n = numel(allIDs{i}); plotTrack(trap1,alltrax(1:n,:,i)) bounds = [tp2.XLimits;tp2.YLimits;tp2.ZLimits]; inView = findInView(allx(:,:,i),bounds(:,1),bounds(:,2)); plotTrack(trup2,allx(inView,:,i),truLabels(inView)) inView = findInView(alltrax(1:n,:,i),bounds(:,1),bounds(:,2)); plotTrack(trap2,alltrax(inView,:,i),allIDs{i}(inView)) drawnow end