В этом примере показано, как выполнить автоматическое обнаружение и основанное на движении отслеживание движущихся объектов в видео. Он упрощает пример Motion-Based Сопровождения нескольких объектов и использует
доступно в Automated Driving Toolbox™.multiObjectTracker
Обнаружение движущихся объектов и отслеживание движения являются важными компонентами многих приложений компьютерного зрения, включая распознавание активности, мониторинг трафика и безопасность автомобилей. Задача отслеживания объектов на основе движения может быть разделена на две части:
Обнаружение движущихся объектов в каждой системе координат
Отслеживание движущихся объектов из системы координат в систему координат
Для обнаружения движущихся объектов используется алгоритм вычитания фона, основанный на смешанных гауссовских моделях. Морфологические операции применяются к полученной маске переднего плана для устранения шума. Наконец, анализ больших двоичных объектов обнаруживает группы связанных пикселей, которые, вероятно, соответствуют движущимся объектам.
Отслеживание движущихся объектов из системы координат в систему координат осуществляется multiObjectTracker
объект, который отвечает за следующее:
Назначение обнаружений трекам.
Инициализация новых дорожек на основе неназначенных обнаружений. Все дорожки инициализируются следующим 'Tentative'
, с учетом возможности того, что они стали результатом ложного обнаружения.
Подтверждение дорожек, если им назначено больше M обнаружений в N системах координат.
Обновление существующих треков на основе назначенных обнаружений.
Покрутка (прогнозирование) существующих неназначенных треков.
Удаление треков, если они оставались неназначенными (покрытыми) слишком долго.
Назначение обнаружений тому же объекту основано исключительно на движении. Движение каждой дорожки оценивается фильтром Калмана. Фильтр предсказывает местоположение дорожки в каждой системе координат и определяет вероятность назначения каждого обнаружения каждой дорожке. Чтобы инициализировать фильтр, который вы проектируете, используйте FilterInitializationFcn
свойство multiObjectTracker
.
Для получения дополнительной информации см. раздел Сопровождения нескольких объектов.
Этот пример является функцией с основным телом в верхней части и стандартными программами в виде вложенных функций ниже. Для получения дополнительной информации см. раздел Вложенные функции.
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
: Вероятные модели движения и измерения. В этом случае ожидается, что объекты будут иметь постоянное движение скорости. The initDemoFilter
функция конфигурирует линейный фильтр Калмана, чтобы отслеживать движение. Для получения дополнительной информации см. раздел «Определение фильтра Калмана».
AssignmentThreshold
: Как далеко могут падать обнаружения. Значение по умолчанию для этого параметра является 30. Если есть обнаружения, которые не назначены трекам, но должны быть, увеличьте это значение. Если есть обнаружения, которые назначаются трекам, которые находятся слишком далеко, уменьшите это значение.
DeletionThreshold
: Как долго дорожка сохраняется перед удалением. В этом случае, поскольку видео имеет 30 системы координат в секунду, разумное значение составляет около 0,75 секунд (22 системы координат).
ConfirmationThreshold
: Параметры, управляющие подтверждением дорожки. Дорожка инициализируется с каждым неназначенным обнаружением. Некоторые из этих обнаружений могут быть ложными, поэтому первоначально все треки 'Tentative'
. Чтобы подтвердить дорожку, она должна быть обнаружена, по крайней мере, M из N систем координат. Выбор M и N зависит от видимости объектов. Этот пример принимает видимость 6 из 10 систем координат.
tracker = multiObjectTracker(... 'FilterInitializationFcn', @initDemoFilter, ... 'AssignmentThreshold', 30, ... 'DeletionThreshold', 22, ... 'ConfirmationThreshold', [6 10] ... );
При определении фильтра отслеживания для движения выполните следующие шаги:
Шаг 1: Задайте модель движения и состояние
В этом примере используйте модель постоянной скорости в 2-D прямоугольной системе координат.
Состояние задано [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
The detectObjects
функция возвращает центроиды и ограничительные рамки обнаруженных объектов в виде списка objectDetection
объекты. Вы можете предоставить этот список как вход в multiObjectTracker
. The 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
The displayTrackingResults
функция рисует ограничивающий прямоугольник и идентификатор метки для каждой дорожки в видеокадре и маске переднего плана. Затем он отображает систему координат и маску в соответствующих видеоплеерах.
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
.
multiObjectTracker
| objectDetection
| trackingEKF
| trackingKF
| trackingUKF
| VideoReader
| vision.VideoPlayer