exponenta event banner

Структура из движения из нескольких видов

Структура из движения (SfM) - процесс оценки 3-D структуры сцены по набору 2-D видов. Он используется во многих приложениях, таких как навигация роботов, автономное вождение и дополненная реальность. В этом примере показано, как оценить позы калиброванной камеры по последовательности видов и восстановить 3-D структуру сцены до неизвестного масштабного коэффициента.

Обзор

В этом примере показано, как реконструировать сцену 3-D из последовательности видов 2-D, взятых с помощью камеры, откалиброванной с помощью калибратора камеры. В примере используется imageviewset объект для хранения и управления данными, связанными с каждым видом, например позицией камеры и точками изображения, а также совпадениями между точками из пар видов.

В примере для оценки положения камеры текущего вида относительно предыдущего вида используются парные совпадения точек. Затем он связывает парные совпадения в более длинные дорожки точек, охватывающие несколько видов, используя findTracks способ imageviewset объект. Эти дорожки затем служат в качестве входных данных для многозначной триангуляции с использованием triangulateMultiview функция и уточнение поз камеры и точек сцены 3-D с помощью bundleAdjustment функция.

Пример состоит из двух основных частей: оценка движения камеры и плотная реконструкция сцены. В первой части пример оценивает положение камеры для каждого вида с использованием разреженного набора точек, совпадающих по видам. Во второй части пример повторяется по последовательности представлений, используя vision.PointTrackerотслеживать плотный набор точек по видам, вычислять плотную 3-D реконструкцию сцены.

Алгоритм оценки движения камеры состоит из следующих этапов:

  1. Для каждой пары последовательных изображений найдите набор соответствий точек. В этом примере определяются процентные баллы с помощью detectSURFFeatures извлекает дескрипторы функций с помощью extractFeatures и находит совпадения с помощью matchFeatures функция. Можно также отслеживать точки на видах с помощью vision.PointTracker.

  2. Оценка относительного положения текущего вида, которое является ориентацией камеры и расположением относительно предыдущего вида. В примере используется вспомогательная функция helperEstimateRelativePose, который звонит estimateEssentialMatrix и relativeCameraPose.

  3. Преобразование относительного положения текущего вида в систему координат первого вида последовательности.

  4. Сохранение текущих атрибутов вида: позы камеры и точек изображения.

  5. Храните инкрементные совпадения между предыдущим и текущим представлением.

  6. Поиск дорожек точек по всем видам, обработанным до сих пор.

  7. Используйте triangulateMultiview функция для вычисления начальных местоположений 3-D, соответствующих дорожкам.

  8. Используйте bundleAdjustment функция для уточнения поз камеры и точек 3-D. Хранить улучшенные позы камеры в imageviewset объект.

Считывание последовательности входных изображений

Считывание и отображение последовательности изображений.

% Use |imageDatastore| to get a list of all image file names in a
% directory.
imageDir = fullfile(toolboxdir('vision'), 'visiondata', ...
      'structureFromMotion');
imds = imageDatastore(imageDir);

% Display the images.
figure
montage(imds.Files, 'Size', [3, 2]);

% Convert the images to grayscale.
images = cell(1, numel(imds.Files));
for i = 1:numel(imds.Files)
    I = readimage(imds, i);
    images{i} = im2gray(I);
end

title('Input Image Sequence');

Figure contains an axes. The axes with title Input Image Sequence contains an object of type image.

Загрузить параметры камеры

Загрузить cameraParameters объект, созданный с помощью калибратора камеры.

data = load(fullfile(imageDir, 'cameraParams.mat'));
cameraParams = data.cameraParams;

Создание набора видов, содержащего первый вид

Использовать imageviewset объект для хранения и управления точками изображения и позицией камеры, связанной с каждым видом, а также совпадениями точек между парами видов. После заполнения imageviewset объект, его можно использовать для поиска дорожек точек на нескольких видах и извлечения поз камеры, которые будут использоваться triangulateMultiview и bundleAdjustment функции.

% Get intrinsic parameters of the camera
intrinsics = cameraParams.Intrinsics;

% Undistort the first image.
I = undistortImage(images{1}, intrinsics); 

% Detect features. Increasing 'NumOctaves' helps detect large-scale
% features in high-resolution images. Use an ROI to eliminate spurious
% features around the edges of the image.
border = 50;
roi = [border, border, size(I, 2)- 2*border, size(I, 1)- 2*border];
prevPoints   = detectSURFFeatures(I, 'NumOctaves', 8, 'ROI', roi);

% Extract features. Using 'Upright' features improves matching, as long as
% the camera motion involves little or no in-plane rotation.
prevFeatures = extractFeatures(I, prevPoints, 'Upright', true);

% Create an empty imageviewset object to manage the data associated with each
% view.
vSet = imageviewset;

% Add the first view. Place the camera associated with the first view
% and the origin, oriented along the Z-axis.
viewId = 1;
vSet = addView(vSet, viewId, rigid3d, 'Points', prevPoints);

Добавление остальных видов

Пройдитесь по остальным изображениям. Для каждого изображения

  1. Совпадение точек между предыдущим и текущим изображением.

  2. Оценка положения камеры текущего вида относительно предыдущего вида.

  3. Вычислите положение камеры текущего вида в глобальной системе координат относительно первого вида.

  4. Триангулировать начальные точки мира 3-D.

  5. Используйте регулировку пучка для уточнения всех поз камеры и точек 3-D мира.

for i = 2:numel(images)
    % Undistort the current image.
    I = undistortImage(images{i}, intrinsics);
    
    % Detect, extract and match features.
    currPoints   = detectSURFFeatures(I, 'NumOctaves', 8, 'ROI', roi);
    currFeatures = extractFeatures(I, currPoints, 'Upright', true);    
    indexPairs   = matchFeatures(prevFeatures, currFeatures, ...
        'MaxRatio', .7, 'Unique',  true);
    
    % Select matched points.
    matchedPoints1 = prevPoints(indexPairs(:, 1));
    matchedPoints2 = currPoints(indexPairs(:, 2));
    
    % Estimate the camera pose of current view relative to the previous view.
    % The pose is computed up to scale, meaning that the distance between
    % the cameras in the previous view and the current view is set to 1.
    % This will be corrected by the bundle adjustment.
    [relativeOrient, relativeLoc, inlierIdx] = helperEstimateRelativePose(...
        matchedPoints1, matchedPoints2, intrinsics);
    
    % Get the table containing the previous camera pose.
    prevPose = poses(vSet, i-1).AbsolutePose;
    relPose  = rigid3d(relativeOrient, relativeLoc);
        
    % Compute the current camera pose in the global coordinate system 
    % relative to the first view.
    currPose = rigid3d(relPose.T * prevPose.T);
    
    % Add the current view to the view set.
    vSet = addView(vSet, i, currPose, 'Points', currPoints);

    % Store the point matches between the previous and the current views.
    vSet = addConnection(vSet, i-1, i, relPose, 'Matches', indexPairs(inlierIdx,:));
    
    % Find point tracks across all views.
    tracks = findTracks(vSet);

    % Get the table containing camera poses for all views.
    camPoses = poses(vSet);

    % Triangulate initial locations for the 3-D world points.
    xyzPoints = triangulateMultiview(tracks, camPoses, intrinsics);
    
    % Refine the 3-D world points and camera poses.
    [xyzPoints, camPoses, reprojectionErrors] = bundleAdjustment(xyzPoints, ...
        tracks, camPoses, intrinsics, 'FixedViewId', 1, ...
        'PointsUndistorted', true);

    % Store the refined camera poses.
    vSet = updateView(vSet, camPoses);

    prevFeatures = currFeatures;
    prevPoints   = currPoints;  
end

Отображение позиций камеры

Отображение улучшенных поз камеры и 3-D точек мира.

% Display camera poses.
camPoses = poses(vSet);
figure;
plotCamera(camPoses, 'Size', 0.2);
hold on

% Exclude noisy 3-D points.
goodIdx = (reprojectionErrors < 5);
xyzPoints = xyzPoints(goodIdx, :);

% Display the 3-D points.
pcshow(xyzPoints, 'VerticalAxis', 'y', 'VerticalAxisDir', 'down', ...
    'MarkerSize', 45);
grid on
hold off

% Specify the viewing volume.
loc1 = camPoses.AbsolutePose(1).Translation;
xlim([loc1(1)-5, loc1(1)+4]);
ylim([loc1(2)-5, loc1(2)+4]);
zlim([loc1(3)-1, loc1(3)+20]);
camorbit(0, -30);

title('Refined Camera Poses');

Figure contains an axes. The axes with title Refined Camera Poses contains 51 objects of type line, text, patch, scatter.

Вычислительная плотная реконструкция

Пройдитесь по изображениям еще раз. На этот раз определите плотный набор углов и отслеживайте их по всем видам с помощьюvision.PointTracker.

% Read and undistort the first image
I = undistortImage(images{1}, intrinsics); 

% Detect corners in the first image.
prevPoints = detectMinEigenFeatures(I, 'MinQuality', 0.001);

% Create the point tracker object to track the points across views.
tracker = vision.PointTracker('MaxBidirectionalError', 1, 'NumPyramidLevels', 6);

% Initialize the point tracker.
prevPoints = prevPoints.Location;
initialize(tracker, prevPoints, I);

% Store the dense points in the view set.

vSet = updateConnection(vSet, 1, 2, 'Matches', zeros(0, 2));
vSet = updateView(vSet, 1, 'Points', prevPoints);

% Track the points across all views.
for i = 2:numel(images)
    % Read and undistort the current image.
    I = undistortImage(images{i}, intrinsics); 
    
    % Track the points.
    [currPoints, validIdx] = step(tracker, I);
    
    % Clear the old matches between the points.
    if i < numel(images)
        vSet = updateConnection(vSet, i, i+1, 'Matches', zeros(0, 2));
    end
    vSet = updateView(vSet, i, 'Points', currPoints);
    
    % Store the point matches in the view set.
    matches = repmat((1:size(prevPoints, 1))', [1, 2]);
    matches = matches(validIdx, :);        
    vSet = updateConnection(vSet, i-1, i, 'Matches', matches);
end

% Find point tracks across all views.
tracks = findTracks(vSet);

% Find point tracks across all views.
camPoses = poses(vSet);

% Triangulate initial locations for the 3-D world points.
xyzPoints = triangulateMultiview(tracks, camPoses,...
    intrinsics);

% Refine the 3-D world points and camera poses.
[xyzPoints, camPoses, reprojectionErrors] = bundleAdjustment(...
    xyzPoints, tracks, camPoses, intrinsics, 'FixedViewId', 1, ...
    'PointsUndistorted', true);

Плотная реконструкция дисплея

Отображение поз камеры и плотного облака точек.

% Display the refined camera poses.
figure;
plotCamera(camPoses, 'Size', 0.2);
hold on

% Exclude noisy 3-D world points.
goodIdx = (reprojectionErrors < 5);

% Display the dense 3-D world points.
pcshow(xyzPoints(goodIdx, :), 'VerticalAxis', 'y', 'VerticalAxisDir', 'down', ...
    'MarkerSize', 45);
grid on
hold off

% Specify the viewing volume.
loc1 = camPoses.AbsolutePose(1).Translation;
xlim([loc1(1)-5, loc1(1)+4]);
ylim([loc1(2)-5, loc1(2)+4]);
zlim([loc1(3)-1, loc1(3)+20]);
camorbit(0, -30);

title('Dense Reconstruction');

Figure contains an axes. The axes with title Dense Reconstruction contains 51 objects of type line, text, patch, scatter.

Ссылки

[1] M.I.A. Луракис и А. А. Аргирос (2009). «Преимущества для малого бизнеса: пакет программного обеспечения для настройки общего разреженного пакета». Транзакции ACM по математическому программному обеспечению (ACM) 36 (1): 1-30.

[2] Р. Хартли, А. Зиссерман, «Геометрия множественного вида в компьютерном зрении», Cambridge University Press, 2003.

[3] B. Триггеры; П. Маклаухлан; Р. Хартли; А. Фицгиббон (1999). «Корректировка пучка: современный синтез». Материалы Международного рабочего совещания по алгоритмам видения. Спрингер-Верлаг. стр. 298-372.