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

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

Обзор

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

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

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

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

  1. Для каждой пары последовательных изображений найдите набор соответствий точек. Этот пример обнаруживает процентные точки, используя detectSURFFeatures function, извлекает дескрипторы функций с помощью extractFeatures functions, и находит совпадения используя 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.

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

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

[2] R. Hartley, A. Zisserman, «Multiple View Geometry in Компьютерное Зрение», Cambridge University Press, 2003.

[3] Б. Триггеры; П. Маклаучлан; Р. Хартли; А. Фицгиббон (1999). Bundle Adjustment: A Modern Synthesis (неопр.) (недоступная ссылка). Материалы Международного практикума по алгоритмам видения. Springer-Verlag. с. 298-372.

Для просмотра документации необходимо авторизоваться на сайте