Оценка и визуализация обнаружений контуров маршрута против основной истины

Этот пример показывает, как оценить эффективность обнаружения контуров маршрута по известной основной истине. В этом примере вы охарактеризуете эффективность алгоритма обнаружения контуров маршрута на основе кадров путем вычисления меры качества подгонки. Эта мера может использоваться, чтобы точно определить, визуализировать и понять типы отказа в базовом алгоритме.

Обзор

С увеличением интереса к основанным на зрении решениям проблем беспилотного вождения, способность оценивать и проверять точность алгоритмов обнаружения стала очень важной. Проверка точности особенно важна в алгоритмах обнаружения, которые имеют несколько параметров, которые можно настроить, чтобы достичь результатов, которые удовлетворяют предопределенным требованиям качества. Этот пример проходит через один из таких рабочих процессов, где контуры маршрута могут быть измерены для уровня их точности. Этот рабочий процесс помогает точно определить типы отказа в этих алгоритмах на основе отдельных кадров, а также охарактеризовать его общую эффективность. Этот рабочий процесс также помогает вам визуально и количественно понять эффективность алгоритма. Затем можно использовать это понимание для настройки базового алгоритма, чтобы улучшить его эффективность.

Загрузка Достоверных данных

Набор данных, используемый в этом примере, является видео- файлом с фронтальной камеры на транспортном средстве, движущейся по улице. Основная истина для контуров маршрута была вручную отмечена на видео приложением Ground Truth Labeler с помощью Line ROI, помеченного как «LaneBoundary». Это видео длится 8 секунд или 250 системы координат. Он имеет три пересечения, несколько транспортных средств (припаркованных и движущихся) и контуры маршрута (двойная линия, одинарная и штриховая). Чтобы создать основную истину набор данных о границах маршрута для собственного видео, можно использовать приложение Ground Truth Labeler.

% Load MAT file with ground truth data
loaded = load('caltech_cordova1_laneAndVehicleGroundTruth.mat');

The loaded структура содержит три поля:

  1. groundTruthData, расписание с двумя столбцами: LaneBoundaries и Vehicles. LaneBoundaries содержит основные истины точки для контуров ego lane (слева и справа), представленные как массив ячеек из точек XY, образующих поли- линию. Vehicles содержит ограничительные рамки основной истины для транспортных средств в поле зрения камеры, представленные M-by-4 массивами [x, y, ширина, высота].

  2. sensor, а monoCamera объект со свойствами о калиброванной камере, установленной на транспортном средстве. Этот объект позволяет вам оценить реальные расстояния между транспортным средством и объектами перед ним.

  3. videoName, символьный массив, содержащий имя файла видео, в котором хранятся системы координат.

Из данных этой структуры откройте файл видео при помощи VideoReader цикл через системы координат. The VideoReader объект использует helperMonoSensor объект для обнаружения полос движения и объектов в видеокадре, с помощью настройки камеры, сохраненной в sensor. A 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}  

The gtdata timetable имеет столбцы Vehicles и LaneBoundaries. В каждой временной метке Vehicles в столбец содержится M-by-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 timetable. Таким образом, они могут быть визуализированы на дисплее Bird 's-Eye View позже. Во-первых, сконфигурируйте helperMonoSensor объект со sensor. The 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: 321
Number of misses: 124
Number of false positives: 25

Использование assignments массив, можно вычислить полезные метрики по маршруту, такие как средние значения боковое расстояние между оценками и точками основной истины. Такие метрики указывают, насколько хорошо работает алгоритм. Чтобы вычислить метрику среднего расстояния, используйте функцию helper 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 в качестве инструмента визуализации, чтобы просмотреть видео, содержащее достоверные данные и предполагаемые контуры маршрута. The driving.connector.Connector класс предоставляет интерфейс для присоединения пользовательских инструментов визуализации к Ground Truth Labeler.

Используйте parabolicLaneBoundary массив и достоверные данные для вычисления транспортного средства координат предполагаемых точек. The parabolicLaneBoundary массив задает линию, и достоверные данные имеют дискретные точки, отмеченные на дороге. The 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');

The helperCustomUI класс создает представления графика и Bird 's-Eye Views с помощью данных, загруженных из MAT файла, подобного только что созданному. Интерфейс Connector приложения Ground Truth Labeler взаимодействует с helperCustomUI класс через helperUIConnector класс, чтобы синхронизировать видео со средним графиком расстояния и видом птичьего глаза. Эта синхронизация позволяет вам анализировать результаты по кадрам как аналитически, так и визуально.

Выполните следующие шаги, чтобы визуализировать результаты, как показано на следующих изображениях:

  • Перейдите во временную директорию, где distanceData.mat сохранен и открыть приложение Ground Truth Labeler. Затем запустите приложение Ground Truth Labeler с указанием указателя на коннектор следующим helperUIConnector с помощью следующих команд:

>> origdir = pwd;
>> cd(tempdir)
>> groundTruthLabeler(dataSource, 'ConnectorTargetHandle', @helperUIConnector);
  • Импортируйте метки: визуализируйте основную истину маркеры маршрута и предполагаемые полосы в координатах изображения. На панели инструментов приложения щелкните Импорт меток. Затем выберите опцию From Workspace и загрузите dataToVisualize основная истина в приложение. Главное окно приложения теперь содержит аннотации для маркеров маршрута.

Теперь можно перемещаться по видео и изучать ошибки. Чтобы вернуться назад в исходную директорию, можно ввести:

>> cd(origdir)

Из этой визуализации можно сделать несколько выводов об алгоритме и качестве достоверных данных.

  • Точность в левой полосе постоянно хуже точности в правой полосе. При ближайшем наблюдении в отображение Bird 's-Eye View достоверных данных помечается как внешний контур двойной линии, тогда как предполагаемый контур маршрута лежит в основном в центре маркера двойной линии. Это указывает, что оценка левого маршрута, вероятно, более точна, чем изображают числа, и что четко определенная основная истина имеет решающее значение для таких наблюдений.

  • Погрешности обнаружения около 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

См. также

Приложения

Функции

Объекты

Похожие темы