Этот пример показывает, как выполнить автоматическое обнаружение и основанное на движении отслеживание перемещения объектов в видео. Это упрощает пример, Основанный на движении Несколько Объект, Отслеживающий (Computer Vision Toolbox), и использует
, доступный в Automated Driving Toolbox™.multiObjectTracker
Обнаружение перемещения объектов и основанного на движении отслеживания является важными компонентами многих приложений компьютерного зрения, включая распознавание действия, контроль трафика и автомобильную безопасность. Проблема основанного на движении объектного отслеживания может быть разделена на две части:
Обнаружение движущихся объектов в каждом кадре
Отслеживание движущихся объектов от кадра до кадра
Обнаружение перемещения объектов использует фоновый алгоритм вычитания на основе Гауссовых моделей смеси. Морфологические операции применяются к получившейся приоритетной маске, чтобы устранить шум. Наконец, анализ блоба обнаруживает группы связанных пикселей, которые, вероятно, будут соответствовать перемещению объектов.
Отслеживание перемещения объектов от кадра до кадра сделано объектом multiObjectTracker
, который ответственен за следующее:
Присвоение обнаружений к дорожкам.
Инициализация новых треков на основе неприсвоенных обнаружений. Все дорожки инициализируются как 'Tentative'
, составляя возможность, что они следовали из ложного обнаружения.
Подтверждение дорожек, если у них есть больше, чем M, присвоило обнаружения в кадрах N.
Обновление существующих дорожек на основе присвоенных обнаружений.
Курсирующий (предсказывая) существующие неприсвоенные дорожки.
Удаление дорожек, если они остались неприсвоенными (курсировало) слишком долго.
Присвоение обнаружений к тому же объекту базируется только на движении. Движение каждой дорожки оценивается Фильтром Калмана. Фильтр предсказывает местоположение дорожки в каждом кадре и определяет вероятность каждого обнаружения, присваиваемого каждой дорожке. Чтобы инициализировать фильтр, который вы разрабатываете, используйте свойство FilterInitializationFcn
multiObjectTracker
.
Для получения дополнительной информации смотрите Несколько Объект, Отслеживающий (Computer Vision Toolbox).
Этим примером является функция с основной частью наверху и стандартными программами помощника в форме вложенных функций ниже. Смотрите Вложенные функции (MATLAB) для получения дополнительной информации.
function MultipleObjectTrackingExample()
% Create objects used for reading video and displaying the results. videoObjects = setupVideoObjects('atrium.mp4'); % Create objects used for detecting objects in the foreground of the video. minBlobArea = 400; % Minimum blob size, in pixels, to be considered as a detection detectorObjects = setupDetectorObjects(minBlobArea);
При создании multiObjectTracker
рассмотрите следующее:
FilterInitializationFcn
: вероятное движение и модели измерения. В этом случае объекты, как ожидают, будут иметь движение постоянной скорости. Функция initDemoFilter
конфигурирует линейный Фильтр Калмана, чтобы отследить движение. Смотрите раздел 'Define a Kalman filter' для деталей.
AssignmentThreshold
: Как далеко обнаружения могут упасть от дорожек. Значение по умолчанию для этого параметра равняется 30. Если существуют обнаружения, которые не присвоены дорожкам, но должны быть, увеличить это значение. Если существуют обнаружения, которые присвоены дорожкам, которые слишком далеки, уменьшают это значение.
NumCoastingUpdates
: Сколько времени дорожка сохраняется перед удалением. В этом случае, поскольку видео имеет 30 кадров в секунду, рыночная стоимость составляет приблизительно 0,75 секунды (22 кадра).
ConfirmationParameters
: параметры, управляющие подтверждением дорожки. Дорожка инициализируется с каждым неприсвоенным обнаружением. Некоторые из этих обнаружений могут быть ложными, так первоначально, всеми дорожками является 'Tentative'
. Чтобы подтвердить дорожку, это должно быть обнаружено, по крайней мере, M из кадров N. Выбор M и N зависит от видимости объектов. Этот пример принимает видимость 6 из 10 кадров.
tracker = multiObjectTracker(... 'FilterInitializationFcn', @initDemoFilter, ... 'AssignmentThreshold', 30, ... 'NumCoastingUpdates', 22, ... 'ConfirmationParameters', [6 10] ... );
При определении фильтра отслеживания для движения завершите следующие шаги:
Шаг 1: Задайте модель движения и состояние
В этом примере используйте постоянную скоростную модель в 2D прямоугольном кадре.
Состоянием является [x;vx;y;vy]
.
Матрицей модели изменения состояния является A = [1 dt 0 0; 0 1 0 0; 0 0 1 dt; 0 0 0 1]
.
Примите тот dt = 1
.
Шаг 2: Задайте шум процесса
Шум процесса представляет части процесса, которые не учтены в модели. Например, в постоянной скоростной модели, ускорением пропускают.
Шаг 3: Задайте модель измерения
В этом примере только измеряется положение ([x;y]
). Так, моделью измерения является H = [1 0 0 0; 0 0 1 0]
.
Примечание: Чтобы предварительно сконфигурировать эти параметры, задайте свойство 'MotionModel'
как '2D Constant Velocity'
.
Шаг 4: Инициализируйте вектор состояния на основе измерения датчика
В этом примере, потому что измерением является [x;y]
и состояние, [x;vx;y;vy]
, инициализирование вектора состояния является прямым. Поскольку нет никакого измерения скорости, инициализируйте vx
и компоненты vy
к 0.
Шаг 5: Задайте ковариацию начального состояния
В этом примере, измерения являются довольно шумными, поэтому задают ковариацию начального состояния, чтобы быть довольно большим: stateCov = diag([50, 50, 50, 50])
Шаг 6: Создайте правильный фильтр
В этом примере все модели линейны, так trackingKF
использования как фильтр отслеживания.
function filter = initDemoFilter(detection) % Initialize a Kalman filter for this example. % Define the initial state. state = [detection.Measurement(1); 0; detection.Measurement(2); 0]; % Define the initial state covariance. stateCov = diag([50, 50, 50, 50]); % Create the tracking filter. filter = trackingKF('MotionModel', '2D Constant Velocity', ... 'State', state, ... 'StateCovariance', stateCov, ... 'MeasurementNoise', detection.MeasurementNoise(1:2,1:2) ... ); end
Следующий цикл запускает видеоклип, обнаруживает движущиеся объекты в видео и отслеживает их через кадры видео.
% Count frames to create a sense of time. frameCount = 0; while hasFrame(videoObjects.reader) % Read a video frame and detect objects in it. frameCount = frameCount + 1; % Promote frame count frame = readFrame(videoObjects.reader); % Read frame [detections, mask] = detectObjects(detectorObjects, frame); % Detect objects in video frame % Run the tracker on the preprocessed detections. confirmedTracks = updateTracks(tracker, detections, frameCount); % Display the tracking results on the video. displayTrackingResults(videoObjects, confirmedTracks, frame, mask); end
Создайте объекты, используемые для чтения и отображения кадров видео.
function videoObjects = setupVideoObjects(filename) % Initialize video I/O % Create objects for reading a video from a file, drawing the tracked % objects in each frame, and playing the video. % Create a video file reader. videoObjects.reader = VideoReader(filename); % Create two video players: one to display the video, % and one to display the foreground mask. videoObjects.maskPlayer = vision.VideoPlayer('Position', [20, 400, 700, 400]); videoObjects.videoPlayer = vision.VideoPlayer('Position', [740, 400, 700, 400]); end
Создайте объекты, используемые для обнаружения основных объектов. Используйте minBlobArea
, чтобы задать размер блоба в пикселях, который считается обнаружением.
Увеличьте minBlobArea
, чтобы не обнаруживать маленькие блобы, которые, более вероятно, будут ложными обнаружениями, или если несколько обнаружений создаются для того же объекта из-за частичного поглощения газов.
Уменьшите minBlobArea
, если объекты обнаруживаются слишком поздно или нисколько.
function detectorObjects = setupDetectorObjects(minBlobArea) % Create System objects for foreground detection and blob analysis % The foreground detector segments moving objects from the % background. It outputs a binary mask, where the pixel value of 1 % corresponds to the foreground and the value of 0 corresponds to % the background. detectorObjects.detector = vision.ForegroundDetector('NumGaussians', 3, ... 'NumTrainingFrames', 40, 'MinimumBackgroundRatio', 0.7); % Connected groups of foreground pixels are likely to correspond to % moving objects. The blob analysis System object finds such % groups (called 'blobs' or 'connected components') and computes % their characteristics, such as their areas, centroids, and the % bounding boxes. detectorObjects.blobAnalyzer = vision.BlobAnalysis('BoundingBoxOutputPort', true, ... 'AreaOutputPort', true, 'CentroidOutputPort', true, ... 'MinimumBlobArea', minBlobArea); end
Функция detectObjects
возвращает центроиды и ограничительные рамки обнаруженных объектов как список объектов objectDetection
. Можно предоставить этот список как вход к multiObjectTracker
. Функция detectObjects
также возвращает бинарную маску, которая имеет тот же размер как входной кадр. Пиксели со значением 1 соответствуют переднему плану. Пиксели со значением 0 соответствуют фону.
Функция выполняет сегментацию движения с помощью приоритетного детектора. Это затем выполняет морфологические операции на получившейся бинарной маске, чтобы удалить шумные пиксели и заполнить дыры в остающихся блобах.
При создании списка objectDetection
frameCount
служит входом времени, и центроиды обнаруженных блобов служат измерением. Список также имеет две дополнительных пары "имя-значение":
MeasurementNoise
- Обнаружение блоба является шумным, и этот пример задает большое значение шума измерения.
ObjectAttributes
- Обнаруженные ограничительные рамки, которые передаются отображению дорожки, добавляются к этому аргументу.
function [detections, mask] = detectObjects(detectorObjects, frame) % Expected uncertainty (noise) for the blob centroid. measurementNoise = 100*eye(2); % Detect foreground. mask = detectorObjects.detector.step(frame); % Apply morphological operations to remove noise and fill in holes. mask = imopen(mask, strel('rectangle', [6, 6])); mask = imclose(mask, strel('rectangle', [50, 50])); mask = imfill(mask, 'holes'); % Perform blob analysis to find connected components. [~, centroids, bboxes] = detectorObjects.blobAnalyzer.step(mask); % Formulate the detections as a list of objectDetection objects. numDetections = size(centroids, 1); detections = cell(numDetections, 1); for i = 1:numDetections detections{i} = objectDetection(frameCount, centroids(i,:), ... 'MeasurementNoise', measurementNoise, ... 'ObjectAttributes', {bboxes(i,:)}); end end
Функция displayTrackingResults
чертит ограничительную рамку и метку ID для каждой дорожки на кадре видео и приоритетной маске. Это затем отображает кадр и маску в их соответствующих видеоплеерах.
function displayTrackingResults(videoObjects, confirmedTracks, frame, mask) % Convert the frame and the mask to uint8 RGB. frame = im2uint8(frame); mask = uint8(repmat(mask, [1, 1, 3])) .* 255; if ~isempty(confirmedTracks) % Display the objects. If an object has not been detected % in this frame, display its predicted bounding box. numRelTr = numel(confirmedTracks); boxes = zeros(numRelTr, 4); ids = zeros(numRelTr, 1, 'int32'); predictedTrackInds = zeros(numRelTr, 1); for tr = 1:numRelTr % Get bounding boxes. boxes(tr, :) = confirmedTracks(tr).ObjectAttributes{1}{1}; % Get IDs. ids(tr) = confirmedTracks(tr).TrackID; if confirmedTracks(tr).IsCoasted predictedTrackInds(tr) = tr; end end predictedTrackInds = predictedTrackInds(predictedTrackInds > 0); % Create labels for objects that display the predicted rather % than the actual location. labels = cellstr(int2str(ids)); isPredicted = cell(size(labels)); isPredicted(predictedTrackInds) = {' predicted'}; labels = strcat(labels, isPredicted); % Draw the objects on the frame. frame = insertObjectAnnotation(frame, 'rectangle', boxes, labels); % Draw the objects on the mask. mask = insertObjectAnnotation(mask, 'rectangle', boxes, labels); end % Display the mask and the frame. videoObjects.maskPlayer.step(mask); videoObjects.videoPlayer.step(frame); end
end
В этом примере вы создали основанную на движении систему для обнаружения и отслеживания нескольких движущихся объектов. Попытайтесь использовать различное видео, чтобы видеть, можно ли обнаружить и отслеживаемые объекты. Попытайтесь изменить параметры multiObjectTracker
.
Отслеживание в этом примере базировалось только на движении, учитывая, что все объекты перемещаются в прямую линию с постоянной скоростью. Когда движение объекта значительно отклоняется от этой модели, пример может произвести ошибки отслеживания. Заметьте ошибку в отслеживании человека, закрытого деревом.
Можно уменьшать вероятность отслеживания ошибок при помощи более комплексной модели движения, таких как постоянное ускорение или постоянный поворот. Чтобы сделать это, попытайтесь задать различный фильтр отслеживания, такой как trackingEKF
или trackingUKF
.
VideoReader
| multiObjectTracker
| objectDetection
| trackingEKF
| trackingKF
| trackingUKF
| vision.VideoPlayer