В этом примере показано, как оценить производительность обнаружения контура маршрута против известной основной истины. В этом примере вы охарактеризуете производительность алгоритма обнаружения контура маршрута на основе на систему координат путем вычисления меры качества подгонки. Эта мера может использоваться, чтобы точно определить, визуализировать, и изучить типы отказа в базовом алгоритме.
С возрастающим интересом к основанным на видении решениям автоматизированных ведущих проблем способность оценить и проверить точность алгоритмов обнаружения стала очень важной. Проверка точности особенно важна в алгоритмах обнаружения, которые имеют несколько параметров, которые могут быть настроены, чтобы достигнуть результатов, которые удовлетворяют предопределенным требованиям к уровню качества. Этот пример идет через один такой рабочий процесс, где контуры маршрута могут быть измерены для их уровня точности. Этот рабочий процесс помогает точно определить типы отказа в этих алгоритмах на основе на систему координат, а также охарактеризовать его общую производительность. Этот рабочий процесс также помогает вам визуально, и количественно изучите производительность алгоритма. Можно затем использовать это понимание, чтобы настроить базовый алгоритм, чтобы улучшать его производительность.
Набор данных, используемый в этом примере, является видеофайлом от фронтальной камеры на транспортном средстве, проезжающем улица. Основная истина для контуров маршрута была вручную отмечена на видео с приложением Ground Truth Labeler, использование ROI Линии пометило "LaneBoundary". Это видео составляет 8 секунд или 250 систем координат долго. Это имеет три перекрестных пересечения, несколько транспортных средств (припаркованный и перемещающийся), и контуры маршрута (двойная линия, одна, и подчеркнутая штриховой линией). Чтобы создать набор данных контура маршрута основной истины для вашего собственного видео, можно использовать приложение Ground Truth Labeler.
% Load MAT file with ground truth data loaded = load('caltech_cordova1_laneAndVehicleGroundTruth.mat');
loaded
структура содержит три поля:
groundTruthData
, расписание с двумя столбцами: LaneBoundaries
и Vehicles
. LaneBoundaries
содержит точки основной истины для контуров маршрута эго (левых и правых), представленных как массив ячеек точек XY, формирующих poly линию. Vehicles
содержит ограничительные рамки основной истины для транспортных средств в поле зрения камеры, представленном как массивы M-4 [x, y, ширина, высота].
sensor
, monoCamera
объект со свойствами о калиброванной камере, смонтированной на транспортном средстве. Этот объект позволяет вам оценить реальные расстояния между транспортным средством и объектами перед ним.
videoName
, символьный массив, содержащий имя файла видео, где системы координат хранятся.
Из данных в этой структуре откройте видеофайл при помощи VideoReader
циклично выполняться через системы координат. VideoReader
возразите использует helperMonoSensor
объект обнаружить маршруты и объекты в видеокадре, с помощью настройки камеры, сохраненной в sensor
. timetable
переменная сохранена в gtdata
содержит достоверные данные. Эта переменная содержит данные на систему координат, которые используются в анализе позже.
% Create a VideoReader object to read frames of the video. videoName = loaded.videoName; fileReader = VideoReader(videoName); % The ground truth data is organized in a timetable. gtdata = loaded.groundTruthData; % Display the first few rows of the ground truth data. head(gtdata)
ans = 8x2 timetable Time Vehicles LaneBoundaries ____________ ____________ ______________ 0 sec {6x4 double} {2x1 cell} 0.033333 sec {6x4 double} {2x1 cell} 0.066667 sec {6x4 double} {2x1 cell} 0.1 sec {6x4 double} {2x1 cell} 0.13333 sec {6x4 double} {2x1 cell} 0.16667 sec {6x4 double} {2x1 cell} 0.2 sec {6x4 double} {2x1 cell} 0.23333 sec {5x4 double} {2x1 cell}
gtdata
расписание имеет столбцы Vehicles
и LaneBoundaries
. В каждой метке времени, Vehicles
столбец содержит массив M-4 ограничительных рамок транспортного средства и LaneBoundaries
столбец содержит двухэлементный массив ячеек левых и правых граничных точек маршрута.
Во-первых, визуализируйте загруженные достоверные данные для фрейма изображения.
% Read the first frame of the video. frame = readFrame(fileReader); % Extract all lane points in the first frame. lanePoints = gtdata.LaneBoundaries{1}; % Extract vehicle bounding boxes in the first frame. vehicleBBox = gtdata.Vehicles{1}; % Superimpose the right lane points and vehicle bounding boxes. frame = insertMarker(frame, lanePoints{2}, 'X'); frame = insertObjectAnnotation(frame, 'rectangle', vehicleBBox, 'Vehicle'); % Display ground truth data on the first frame. figure imshow(frame)
Используя видеокадры и monoCamera
параметры, можно автоматически оценить местоположения контуров маршрута. Для рисунка, processFrame
метод helperMonoSensor
класс используется здесь, чтобы обнаружить контуры маршрута (как parabolicLaneBoundary
объекты) и транспортные средства (как [x, y, ширина, высота] матрицы ограничительной рамки). В целях этого примера это - алгоритм "обнаружения контура маршрута под тестом". Можно использовать тот же шаблон в оценке пользовательского алгоритма обнаружения контура маршрута, где processFrame
заменяется пользовательской функцией обнаружения. Точки основной истины в координатах транспортного средства также хранятся в LanesInVehicleCoord
столбец gtdata
расписание. Тем путем они могут визуализироваться в отображении Вида с высоты птичьего полета позже. Во-первых, сконфигурируйте helperMonoSensor
объект с sensor
. helperMonoSensor
класс собирает все необходимые шаги, требуемые запускать алгоритм обнаружения контура маршрута.
% Set up monoSensorHelper to process video. monoCameraSensor = loaded.sensor; monoSensorHelper = helperMonoSensor(monoCameraSensor); % Create new timetable with same Time vector for measurements. measurements = timetable(gtdata.Time); % Set up timetable columns for holding lane boundary and vehicle data. numFrames = floor(fileReader.FrameRate*fileReader.Duration); measurements.LaneBoundaries = cell(numFrames, 2); measurements.VehicleDetections = cell(numFrames, 1); gtdata.LanesInVehicleCoord = cell(numFrames, 2); % Rewind the video to t = 0, and create a frame index to hold current % frame. fileReader.CurrentTime = 0; frameIndex = 0; % Loop through the videoFile until there are no new frames. while hasFrame(fileReader) frameIndex = frameIndex+1; frame = readFrame(fileReader); % Use the processFrame method to compute detections. % This method can be replaced with a custom lane detection method. detections = processFrame(monoSensorHelper, frame); % Store the estimated lane boundaries and vehicle detections. measurements.LaneBoundaries{frameIndex} = [detections.leftEgoBoundary ... detections.rightEgoBoundary]; measurements.VehicleDetections{frameIndex} = detections.vehicleBoxes; % To facilitate comparison, convert the ground truth lane points to the % vehicle coordinate system. gtPointsThisFrame = gtdata.LaneBoundaries{frameIndex}; vehiclePoints = cell(1, numel(gtPointsThisFrame)); for ii = 1:numel(gtPointsThisFrame) vehiclePoints{ii} = imageToVehicle(monoCameraSensor, gtPointsThisFrame{ii}); end % Store ground truth points expressed in vehicle coordinates. gtdata.LanesInVehicleCoord{frameIndex} = vehiclePoints; end
Теперь, когда вы обработали видео с алгоритмом обнаружения маршрута, проверьте, что точки основной истины правильно преобразовываются в систему координат транспортного средства. Первая запись в LanesInVehicleCoord
столбец gtdata
расписание содержит координаты транспортного средства для первой системы координат. Постройте эти точки основной истины на первой системе координат в Виде с высоты птичьего полета.
% Rewind video to t = 0. fileReader.CurrentTime = 0; % Read the first frame of the video. frame = readFrame(fileReader); birdsEyeImage = transformImage(monoSensorHelper.BirdsEyeConfig, frame); % Extract right lane points for the first frame in Bird's-Eye View. firstFrameVehiclePoints = gtdata.LanesInVehicleCoord{1}; pointsInBEV = vehicleToImage(monoSensorHelper.BirdsEyeConfig, firstFrameVehiclePoints{2}); % Superimpose points on the frame. birdsEyeImage = insertMarker(birdsEyeImage, pointsInBEV, 'X', 'Size', 6); % Display transformed points in Bird's-Eye View. figure imshow(birdsEyeImage)
Вычисление ошибок в обнаружении контура маршрута является существенным шагом в проверке производительности нескольких нисходящих подсистем. Такие подсистемы включают системы предупреждения о сходе с полосы, которые зависят от точности подсистемы обнаружения маршрута.
Можно оценить эту точность путем измерения качества подгонки. С точками основной истины и вычисленными оценками, можно теперь сравнить и визуализировать их, чтобы узнать, как хорошо алгоритмы обнаружения выполняют.
Качество подгонки может быть измерено или на уровне на систему координат или для целого видео. Статистические данные на систему координат предоставляют подробную информацию об определенных сценариях, таких как поведение в дорожных поворотах, где производительность алгоритма обнаружения может варьироваться. Глобальные статистические данные обеспечивают большую оценку изображения количества маршрутов, которые пропустили обнаружение.
Используйте evaluateLaneBoundaries
функционируйте, чтобы возвратить глобальную статистику обнаружения и assignments
массив. Этот массив соответствует, предполагаемые объекты контура маршрута с соответствующей основной истиной указывает.
Пороговый параметр в evaluateLaneBoundaries
функция представляет максимальное боковое расстояние в координатах транспортного средства, чтобы квалифицировать как соответствие с предполагаемыми параболическими контурами маршрута.
threshold = 0.25; % in meters [numMatches, numMisses, numFalsePositives, assignments] = ... evaluateLaneBoundaries(measurements.LaneBoundaries, ... gtdata.LanesInVehicleCoord, ... threshold); disp(['Number of matches: ', num2str(numMatches)]); disp(['Number of misses: ', num2str(numMisses)]); disp(['Number of false positives: ', num2str(numFalsePositives)]);
Number of matches: 316 Number of misses: 129 Number of false positives: 27
Используя assignments
массив, можно вычислить полезные метрики на маршрут, такие как среднее боковое расстояние между оценками и точками основной истины. Такие метрики указывают, как хорошо алгоритм выполняет. Чтобы вычислить среднюю метрику расстояния, используйте функцию помощника helperComputeLaneStatistics
, который задан в конце этого примера.
averageDistance = helperComputeLaneStatistics(measurements.LaneBoundaries, ... gtdata.LanesInVehicleCoord, ... assignments, @mean); % Plot average distance between estimates and ground truth. figure stem(gtdata.Time, averageDistance) title('Average Distance Between Estimates and Ground Truth') grid on ylabel('Distance in Meters') legend('Left Boundary','Right Boundary')
У вас теперь есть количественное понимание точности алгоритма обнаружения маршрута. Однако не возможно полностью изучить отказы только на основе графика в предыдущем разделе. Смотрение видео и визуализация ошибок на основе на систему координат поэтому крайне важны для идентификации определенных типов отказа, которые могут быть улучшены путем совершенствования алгоритма.
Можно использовать приложение Ground Truth Labeler в качестве инструмента визуализации, чтобы смотреть видео, содержащее достоверные данные и предполагаемые контуры маршрута.
класс обеспечивает интерфейс, чтобы присоединить пользовательские инструменты визуализации к Ground Truth Labeler.driving.connector.Connector
Используйте parabolicLaneBoundary
массив и достоверные данные, чтобы вычислить транспортное средство координируют местоположения предполагаемых точек. parabolicLaneBoundary
массив задает линию, и достоверным данным отметили дискретные точки на дороге. helperGetCorrespondingPoints
функционируйте оценочные точки на предполагаемых линиях, которые соответствуют тому же расстоянию Оси Y от транспортного средства. Эта функция помощника задана в конце примера.
Точки основной истины и предполагаемые точки теперь включены в новый timetable
визуализироваться в приложении Ground Truth Labeler. Созданный groundTruth
объект затем хранится как файл MAT.
% Compute the estimated point locations using the monoCamera. [estVehiclePoints, estImagePoints] = helperGetCorrespondingPoints(monoCameraSensor, ... measurements.LaneBoundaries, ... gtdata.LanesInVehicleCoord, ... assignments); % Add estimated lanes to the measurements timetable. measurements.EstimatedLanes = estImagePoints; measurements.LanesInVehicleCoord = estVehiclePoints; % Create a new timetable with all the variables needed for visualization. names = {'LanePoints'; 'DetectedLanePoints'}; types = labelType({'Line'; 'Line'}); labelDefs = table(names, types, 'VariableNames', {'Name','Type'}); visualizeInFrame = timetable(gtdata.Time, ... gtdata.LaneBoundaries, ... measurements.EstimatedLanes, ... 'VariableNames', names); % Create groundTruth object. dataSource = groundTruthDataSource(videoName); dataToVisualize = groundTruth(dataSource, labelDefs, visualizeInFrame); % Save all the results of the previous section in distanceData.mat in a % temporary folder. dataToLoad = [tempdir 'distanceData.mat']; save(dataToLoad, 'monoSensorHelper', 'videoName', 'measurements', 'gtdata', 'averageDistance');
helperCustomUI
класс создает график и Виды с высоты птичьего полета с помощью данных, загруженных из файла MAT, как тот, который вы только создали. Интерфейс Connector приложения Ground Truth Labeler взаимодействует с helperCustomUI
класс через helperUIConnector
класс, чтобы синхронизировать видео со средним графиком расстояния и Видом с высоты птичьего полета. Эта синхронизация позволяет вам анализировать результаты на систему координат и аналитически и визуально.
Выполните эти шаги, чтобы визуализировать результаты как показано в изображениях, которые следуют:
Перейдите к временной директории где distanceData.mat
сохранено, и откройте приложение Ground Truth Labeler. Затем запустите приложение Ground Truth Labeler с указателем коннектора, заданным как helperUIConnector
использование следующих команд:
>> origdir = pwd;
>> cd(tempdir)
>> groundTruthLabeler(dataSource, 'ConnectorTargetHandle', @helperUIConnector);
Метки импорта: Визуализируйте маркеры маршрута основной истины и предполагаемые маршруты в координатах изображений. От панели инструментов приложения нажмите Import Labels. Затем выберите Из опции Рабочей области и загрузите dataToVisualize
основная истина в приложение. Окно главного приложения теперь содержит аннотации для маркеров маршрута.
Можно теперь перейти через видео и исследовать ошибки. Чтобы возвратиться назад к исходной директории, можно ввести:
>> cd(origdir)
От этой визуализации можно сделать несколько выводов об алгоритме и качестве достоверных данных.
Левая точность маршрута последовательно хуже, чем правильная точность маршрута. После более близкого наблюдения в отображении Вида с высоты птичьего полета достоверные данные отмечены как внешняя граница двойной линии, тогда как предполагаемый контур маршрута обычно лежит в центре двойного маркера линии. Это указывает, что левая оценка маршрута, вероятно, более точна, чем числа изображают, и что ясно заданный набор данных основной истины крайне важен для таких наблюдений.
Обнаружение разрывает приблизительно 2,3 секунды, и 4 секунды соответствуют пересечениям на дороге, которым предшествуют переходы. Это указывает, что алгоритм не выполняет хорошо в присутствии переходов.
Приблизительно 6,8 секунд, когда транспортное средство приближается к третьему пересечению, маршрут эго, отличаются в лево-единственный маршрут и прямой маршрут. Здесь также, алгоритму не удается получить левый маршрут точно, и достоверные данные также не содержат информации для пяти систем координат.
Этот пример показал, как измерить точность алгоритма обнаружения контура маршрута и визуализировать ее с помощью приложения Ground Truth Labeler. Можно расширить эту концепцию к другим пользовательским алгоритмам, чтобы упростить эти рабочие процессы и расширить функциональность приложения для пользовательских измерений.
helperComputeLaneStatistics
Эта функция помощника вычисляет статистику для обнаружений контура маршрута по сравнению с точками основной истины. Это берет в указателе на функцию, который может использоваться, чтобы обобщить статистическую величину, которая должна быть вычислена, включая @mean и @median.
function stat = helperComputeLaneStatistics(estModels, gtPoints, assignments, fcnHandle) numFrames = length(estModels); % Make left and right estimates NaN by default to represent lack of % data. stat = NaN*ones(numFrames, 2); for frameInd = 1:numFrames % Make left and right estimates NaN by default. stat(frameInd, :) = NaN*ones(2, 1); for idx = 1:length(estModels{frameInd}) % Ignore false positive assignments. if assignments{frameInd}(idx) == 0 continue; end % The kth boundary in estModelInFrame is matched to kth % element indexed by assignments in gtPointsInFrame. thisModel = estModels{frameInd}(idx); thisGT = gtPoints{frameInd}{assignments{frameInd}(idx)}; thisGTModel = driving.internal.piecewiseLinearBoundary(thisGT); if mean(thisGTModel.Points(:,2)) > 0 % left lane xPoints = thisGTModel.Points(:,1); yDist = zeros(size(xPoints)); for index = 1:numel(xPoints) gtYPoints = thisGTModel.computeBoundaryModel(xPoints(index)); testYPoints = thisModel.computeBoundaryModel(xPoints(index)); yDist(index) = abs(testYPoints-gtYPoints); end stat(frameInd, 1) = fcnHandle(yDist); else % right lane xPoints = thisGTModel.Points(:,1); yDist = zeros(size(xPoints)); for index = 1:numel(xPoints) gtYPoints = thisGTModel.computeBoundaryModel(xPoints(index)); testYPoints = thisModel.computeBoundaryModel(xPoints(index)); yDist(index) = abs(testYPoints-gtYPoints); end stat(frameInd, 2) = fcnHandle(yDist); end end end end
helperGetCorrespondingPoints
Эта функция помощника создает транспортное средство и точки координаты изображений в местоположениях Оси X, которые совпадают с точками основной истины.
function [vehiclePoints, imagePoints] = helperGetCorrespondingPoints(monoCameraSensor, estModels, gtPoints, assignments) numFrames = length(estModels); imagePoints = cell(numFrames, 1); vehiclePoints = cell(numFrames, 1); for frameInd = 1:numFrames if isempty(assignments{frameInd}) imagePointsInFrame = []; vehiclePointsInFrame = []; else estModelInFrame = estModels{frameInd}; gtPointsInFrame = gtPoints{frameInd}; imagePointsInFrame = cell(length(estModelInFrame), 1); vehiclePointsInFrame = cell(length(estModelInFrame), 1); for idx = 1:length(estModelInFrame) % Ignore false positive assignments. if assignments{frameInd}(idx) == 0 imagePointsInFrame{idx} = [NaN NaN]; continue; end % The kth boundary in estModelInFrame is matched to kth % element indexed by assignments in gtPointsInFrame. thisModel = estModelInFrame(idx); thisGT = gtPointsInFrame{assignments{frameInd}(idx)}; xPoints = thisGT(:, 1); yPoints = thisModel.computeBoundaryModel(xPoints); vehiclePointsInFrame{idx} = [xPoints, yPoints]; imagePointsInFrame{idx} = vehicleToImage(monoCameraSensor, [xPoints yPoints]); end end vehiclePoints{frameInd} = vehiclePointsInFrame; imagePoints{frameInd} = imagePointsInFrame; % Make imagePoints [] instead of {} to comply with groundTruth object. if isempty(imagePoints{frameInd}) imagePoints{frameInd} = []; end if isempty(vehiclePoints{frameInd}) vehiclePoints{frameInd} = []; end end end