exponenta event banner

Сшивание панорамного изображения на основе элементов

В этом примере показано, как автоматически создавать панораму с помощью методов регистрации изображений на основе функций.

Обзор

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

Шаг 1 - Загрузить изображения

Набор изображений, используемый в этом примере, содержит изображения здания. Их брали с помощью некалиброванной камеры смартфона, сметая камеру слева направо вдоль горизонта, захватывая все части здания.

Как видно ниже, на изображения относительно не влияет какое-либо искажение объектива, поэтому калибровка камеры не требовалась. Однако при наличии искажения объектива камера должна быть откалибрована, а изображения не искажены до создания панорамы. Вы можете использовать Приложение «Калибратор камеры» для калибровки камеры при необходимости.

% Load images.
buildingDir = fullfile(toolboxdir('vision'),'visiondata','building');
buildingScene = imageDatastore(buildingDir);

% Display images to be stitched.
montage(buildingScene.Files)

Figure contains an axes. The axes contains an object of type image.

Шаг 2 - Регистрация пар изображений

Чтобы создать панораму, начните с регистрации последовательных пар изображений с помощью следующей процедуры:

  1. Обнаружение и согласование функций между I (n) и I (n-1).

  2. Оцените геометрическое преобразование T (n), которое отображает I (n) в I (n-1).

  3. Вычислите преобразование, отображающее I (n) в панорамное изображение как T (n) * T (n-1) *... * T (1).

% Read the first image from the image set.
I = readimage(buildingScene,1);

% Initialize features for I(1)
grayImage = im2gray(I);
points = detectSURFFeatures(grayImage);
[features, points] = extractFeatures(grayImage,points);

% Initialize all the transforms to the identity matrix. Note that the
% projective transform is used here because the building images are fairly
% close to the camera. Had the scene been captured from a further distance,
% an affine transform would suffice.
numImages = numel(buildingScene.Files);
tforms(numImages) = projective2d(eye(3));

% Initialize variable to hold image sizes.
imageSize = zeros(numImages,2);

% Iterate over remaining image pairs
for n = 2:numImages
    
    % Store points and features for I(n-1).
    pointsPrevious = points;
    featuresPrevious = features;
        
    % Read I(n).
    I = readimage(buildingScene, n);
    
    % Convert image to grayscale.
    grayImage = im2gray(I);    
    
    % Save image size.
    imageSize(n,:) = size(grayImage);
    
    % Detect and extract SURF features for I(n).
    points = detectSURFFeatures(grayImage);    
    [features, points] = extractFeatures(grayImage, points);
  
    % Find correspondences between I(n) and I(n-1).
    indexPairs = matchFeatures(features, featuresPrevious, 'Unique', true);
       
    matchedPoints = points(indexPairs(:,1), :);
    matchedPointsPrev = pointsPrevious(indexPairs(:,2), :);        
    
    % Estimate the transformation between I(n) and I(n-1).
    tforms(n) = estimateGeometricTransform2D(matchedPoints, matchedPointsPrev,...
        'projective', 'Confidence', 99.9, 'MaxNumTrials', 2000);
    
    % Compute T(n) * T(n-1) * ... * T(1)
    tforms(n).T = tforms(n).T * tforms(n-1).T; 
end

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

Начните с использования projective2d outputLimits для поиска пределов вывода для каждого преобразования. Пределы вывода затем используются для автоматического поиска изображения, которое находится примерно в центре сцены.

% Compute the output limits for each transform.
for i = 1:numel(tforms)           
    [xlim(i,:), ylim(i,:)] = outputLimits(tforms(i), [1 imageSize(i,2)], [1 imageSize(i,1)]);    
end

Затем вычислите средние пределы X для каждого преобразования и найдите изображение в центре. Здесь используются только пределы X, поскольку известно, что сцена горизонтальна. Если используется другой набор изображений, то для поиска центрального изображения может потребоваться использовать пределы X и Y.

avgXLim = mean(xlim, 2);
[~,idx] = sort(avgXLim);
centerIdx = floor((numel(tforms)+1)/2);
centerImageIdx = idx(centerIdx);

Наконец, примените обратное преобразование центрального изображения ко всем остальным.

Tinv = invert(tforms(centerImageIdx));
for i = 1:numel(tforms)    
    tforms(i).T = tforms(i).T * Tinv.T;
end

Шаг 3 - Инициализация панорамы

Теперь создайте начальную пустую панораму, на которую будут отображены все изображения.

Используйте outputLimits метод вычисления минимального и максимального пределов вывода для всех преобразований. Эти значения используются для автоматического вычисления размера панорамы.

for i = 1:numel(tforms)           
    [xlim(i,:), ylim(i,:)] = outputLimits(tforms(i), [1 imageSize(i,2)], [1 imageSize(i,1)]);
end

maxImageSize = max(imageSize);

% Find the minimum and maximum output limits. 
xMin = min([1; xlim(:)]);
xMax = max([maxImageSize(2); xlim(:)]);

yMin = min([1; ylim(:)]);
yMax = max([maxImageSize(1); ylim(:)]);

% Width and height of panorama.
width  = round(xMax - xMin);
height = round(yMax - yMin);

% Initialize the "empty" panorama.
panorama = zeros([height width 3], 'like', I);

Шаг 4 - Создание панорамы

Использовать imwarp для отображения изображений на панораму и использования vision.AlphaBlender чтобы наложить изображения вместе.

blender = vision.AlphaBlender('Operation', 'Binary mask', ...
    'MaskSource', 'Input port');  

% Create a 2-D spatial reference object defining the size of the panorama.
xLimits = [xMin xMax];
yLimits = [yMin yMax];
panoramaView = imref2d([height width], xLimits, yLimits);

% Create the panorama.
for i = 1:numImages
    
    I = readimage(buildingScene, i);   
   
    % Transform I into the panorama.
    warpedImage = imwarp(I, tforms(i), 'OutputView', panoramaView);
                  
    % Generate a binary mask.    
    mask = imwarp(true(size(I,1),size(I,2)), tforms(i), 'OutputView', panoramaView);
    
    % Overlay the warpedImage onto the panorama.
    panorama = step(blender, panorama, warpedImage, mask);
end

figure
imshow(panorama)

Figure contains an axes. The axes contains an object of type image.

Заключение

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

Ссылки

[1] Мэтью Браун и Дэвид Г. Лоу. 2007. Автоматическое сшивание панорамных изображений с использованием инвариантных элементов. Инт. Дж. Компут. Видение 74, 1 (август 2007 года), 59-73.