Main Content

특징 기반 파노라마 영상 이어 붙이기

이 예제에서는 특징 기반 영상 정합 기법을 사용하여 파노라마를 자동으로 만드는 방법을 보여줍니다.

개요

특징 검출과 특징 매칭은 영상 정합, 추적, 객체 검출 등 많은 컴퓨터 비전 응용 분야에서 사용되는 강력한 기법입니다. 이 예제에서는 특징 기반 기법을 사용하여 영상 세트를 자동으로 이어 붙입니다. 영상을 이어 붙이는 절차는 특징 기반 영상 정합의 확장입니다. 단일 영상 쌍을 정합하는 대신 여러 영상 쌍이 서로를 기준으로 연속적으로 정합되어 파노라마를 형성합니다.

1단계 - 영상 불러오기

이 예제에서 사용된 영상 세트에는 건물 사진이 포함되어 있습니다. 이 영상 세트는 가로 방향을 따라 왼쪽에서 오른쪽으로 무보정 스마트폰 카메라를 스윕하여 건물의 모든 부분을 캡처한 것입니다.

아래에서 볼 수 있듯이 이 영상은 상대적으로 렌즈 왜곡의 영향을 받지 않으므로 카메라 보정이 필요하지 않습니다. 그러나 렌즈 왜곡이 있는 경우 파노라마를 만들기 전에 카메라를 보정하고 왜곡 영상을 제거해야 합니다. 필요한 경우 카메라 보정기 앱을 사용하여 카메라를 보정할 수 있습니다.

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

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

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

2단계 - 여러 영상 쌍 정합하기

파노라마를 만들려면 먼저 다음 절차에 따라 연속된 여러 영상 쌍을 정합합니다.

  1. I(n)I(n-1) 간의 특징을 검출하고 매칭시킵니다.

  2. I(n)I(n-1)에 매핑하는 기하 변환 T(n)을 추정합니다.

  3. I(n)을 파노라마 영상에 T(1)*T(2)*...*T(n-1)*T(n)으로 매핑하는 변환을 계산합니다.

% 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 transformations to the identity matrix. Note that the
% projective transformation is used here because the building images are fairly
% close to the camera. For scenes captured from a further distance, you can use
% affine transformations.
numImages = numel(buildingScene.Files);
tforms(numImages) = projtform2d;

% 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) = estgeotform2d(matchedPoints, matchedPointsPrev,...
        'projective', 'Confidence', 99.9, 'MaxNumTrials', 2000);
    
    % Compute T(1) * T(2) * ... * T(n-1) * T(n).
    tforms(n).A = tforms(n-1).A * tforms(n).A; 
end

이 단계에서 tforms의 모든 변환은 첫 번째 영상을 기준으로 합니다. 그러면 모든 영상을 순차적으로 처리할 수 있기 때문에 영상 정합 절차를 손쉽게 코딩할 수 있습니다. 그러나 첫 번째 영상을 파노라마의 시작으로 사용하면 파노라마를 형성하는 대부분의 영상이 왜곡될 수 있기 때문에 가장 보기 좋은 파노라마를 만들 수 없습니다. 장면의 중심이 가장 덜 왜곡되도록 변환을 수정하면 더 멋진 파노라마를 만들 수 있습니다. 이렇게 하려면 장면의 중심이 되는 영상에 대한 변환을 반전하고 그 변환을 모든 다른 영상에 적용하면 됩니다.

먼저, projtform2d outputLimits 메서드를 사용하여 각 변환에 대한 출력 제한을 구합니다. 그런 다음 출력 제한을 사용하여 대략적으로 장면의 중심이 되는 영상을 자동으로 찾습니다.

% Compute the output limits for each transformation.
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).A = Tinv.A * tforms(i).A;
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 object. The axes object contains an object of type image.

결론

이 예제에서는 특징 기반 영상 정합 기법을 사용하여 파노라마를 자동으로 만드는 방법을 다루었습니다. 추가 기법을 이 예제에 적용하여 파노라마 영상의 혼합과 정렬을 개선할 수 있습니다[1].

참고 문헌

[1] Matthew Brown and David G. Lowe. 2007. Automatic Panoramic Image Stitching using Invariant Features. Int. J. Comput. ion 74, 1 (August 2007), 59-73.