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

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

Обзор

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

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

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

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

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

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

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

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

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

  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 объект создал использование Camera Calibrator.

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.

Вычислите плотную реконструкцию

Пройдите изображения снова. На этот раз обнаружьте плотный набор углов и отследите их через все представления usingvision.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). "SBA: пакет программного обеспечения для типовой разреженной корректировки пакета". Транзакции ACM на математическом программном обеспечении (ACM) 36 (1): 1-30.

[2] Р. Хартли, А. Зиссермен, "Несколько просматривают геометрию в компьютерном зрении", издательство Кембриджского университета, 2003.

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