圖像拼接
參考自 https://blog.csdn.net/m0_37565736/article/details/79865990 並修改了其中錯誤的地方,添加自己的講解或者看法。
我要拼接的是一副畫卷,如下(大小一樣的,都是3000*4000像素)
首先,就是讀取圖像
clear all clc file1='G:/picture/a.jpg'; file2='G:/picture/b.jpg'; I1=imread(file1);%讀取圖片 I2=imread(file2); imgs=[I1,I2]; figure,imshow(imgs);%並排顯示兩幅待拼接圖像 title('待拼接圖像');
但是,讀出來的圖像在imshow中被旋轉了一下,出來是這個樣子的
這樣就這樣吧。。不影響操作
下一步將其灰度化,並提取SURF特征點。
img1=rgb2gray(I1); img2=rgb2gray(I2); imageSize=size(img1); p1=detectSURFFeatures(img1); p2=detectSURFFeatures(img2);%檢測SURF特征點
然后提取特征向量並加以匹配
[img1Features, p1] = extractFeatures(img1, p1);%使用64維向量表示特征描述子, %第一個返回的參數即為每個特征點對應的特征描述子,第二個參數是特征點 [img2Features, p2] = extractFeatures(img2, p2); boxPairs = matchFeatures(img1Features, img2Features);%特征描述子匹配 matchedimg1Points = p1(boxPairs(:, 1));%第二個參數:可以不加,因為其為n行1列的結構體數組 matchedimg2Points = p2(boxPairs(:, 2));
這時我們可以看到,匹配成功的特征點密密麻麻的,甚至籃圈里面的特征點匹配還有問題,怎么可能匹配上嘛。
所以,我們接下來要去除誤匹配點,進行MSAC算法實現。另外,通過特征點匹配還得到了第二幅圖的變換矩陣tform,第二幅圖要經過變換矩陣變成和第一幅圖的坐標一致
[tform, inlierimg2Points, inlierimg1Points] = ... estimateGeometricTransform(matchedimg2Points, matchedimg1Points, 'projective');%射影變換,tfrom映射點對1內點到點對2內點 %該函數使用隨機樣本一致性(RANSAC)算法的變體MSAC算法實現,去除誤匹配點 %The returned geometric transformation matrix maps the inliers in matchedPoints1 %to the inliers in matchedPoints2.返回的幾何映射矩陣映射第一參數內點到第二參數內點 showMatchedFeatures(I1, I2, inlierimg1Points, ... inlierimg2Points, 'montage'); title('Matched Points (Inliers Only)');
好,精確匹配之后,看到匹配的總體就好多了,看上去很准確。把兩幅圖共有的部分都匹配上了。
下一步進行圖像合並,tform是變換矩陣,以第一幅圖像為基准坐標,第二幅圖要進行變換與其對應,
Rfixed就是第一幅圖的世界二維坐標。
Rfixed = imref2d(size(I1)); [registered2, Rregistered] = imwarp(I2, tform); %[registered1, Rregistered1] = imwarp(I1, tform); figure() imshowpair(I1,Rfixed,registered2,Rregistered,'blend'); title('圖像差異');
按照特征點直接來拼接,是這個樣子滴,看到第二幅圖經過變換矩陣后稍微傾斜了一下,然后特征點匹配后會出現兩條明顯的邊緣,在y=0和y=1500的地方。
下面的操作就是要消除這兩個邊緣。讓其完美的融入。
我用的是參考博客上的漸入漸出的原理。大家有好的方法歡迎給博主分享。
漸入漸出融合
所謂漸入漸出就是將兩幅圖重合的區域按照距離兩幅圖的距離按照一定的權重重新分配重合部分圖畫的三原色權重。比如最中間的就是0.5 0.5的比例。
那么,下一步就是找到他們重疊區域了,也就是相同掩模區。
先確定一下整體的像素大小以及兩幅圖的實際具體位置。
[xlim, ylim] = outputLimits(tform, [1 imageSize(2)], [1 imageSize(1)]);%輸出坐標范圍 x:23.8~4334 y:-1844~1447 % 找到輸出空間限制的最大最小值 xMin = min([1; xlim(:)]);%1 xMax = max([imageSize(2); xlim(:)]);%4334 yMin = min([1; ylim(:)]);%-1844 yMax = max([imageSize(1); ylim(:)]);%3000 % 全景圖的寬高 width = round(xMax - xMin); height = round(yMax - yMin); %創建2D空間參考對象定義全景圖尺寸 xLimits = [xMin xMax]; yLimits = [yMin yMax]; panoramaView = imref2d([height width ], xLimits, yLimits); % 變換圖片到全景圖. unwarpedImage = imwarp(I1,projective2d(eye(3)), 'OutputView', panoramaView); warpedImage = imwarp(I2, tform, 'OutputView', panoramaView);
以第一幅圖為基准找到重疊區域(掩模區)
第三張圖就是兩幅圖的共同區域了。我們在這個區域里面對兩幅圖像色彩的權重進行重新的分配,然后顯示圖像。
這幅圖就是 第一張圖的權重分配,理他近的邊緣權重為1,離他最遠的重合位置邊緣權重為0.為了避免使用for循環增加計算時間,我只能將整個x軸范圍都采用了權重再分配,而不是那個精確的重疊區域不規則圖形。
% % %%%%%%%%%%%%%%%%%%%%%%%%%%漸入漸出融合%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % MAKE MASKS FOR BOTH IMAGES % warpedImage(isnan(warpedImage))=0; % newImage = zeros(size(warpedImage)); % newImage(1:size(I1,1), 1: size(I1,2)+100,:) = I1; newImage=unwarpedImage; newImage=double(newImage); balck1=(warpedImage(:,:,1)==0 & warpedImage(:,:,2)==0 & warpedImage(:,:,3)==0); balck2=(newImage(:,:,1)==0 & newImage(:,:,2)==0 & newImage(:,:,3)==0); black=and(balck1,balck2); black=~black; maskA = (warpedImage(:,:,1)>0 |warpedImage(:,:,2)>0 | warpedImage(:,:,3)>0);%變換圖像掩膜 mask1 = (newImage(:,:,1)>0 | newImage(:,:,2)>0 | newImage(:,:,3)>0);%非變換圖像掩膜 mask1 = and(maskA, mask1);%重疊區掩膜 % figure,imshow(mask1)
[row,col] = find(mask1==1); left = min(col); right = max(col);%獲得重疊區左右范圍 up=min(row); down=max(row); mask = ones(size(mask1)); % figure() % imshow(mask) %mask(:,left:right) = repmat(linspace(0,1,right-left+1),size(mask,1),1);%復制平鋪矩陣 mask(up:down,:) = repmat(linspace(1,0,down-up+1)',1,size(mask,2));%復制平鋪矩陣 % BLEND EACH CHANNEL warpedImage=double(warpedImage); % figure() % warpedImage=uint8(warpedImage); % imshow(warpedImage) % figure() % imshow(mask) warpedImage(:,:,1) = warpedImage(:,:,1).*mask; warpedImage(:,:,2) = warpedImage(:,:,2).*mask; warpedImage(:,:,3) = warpedImage(:,:,3).*mask; % REVERSE THE ALPHA VALUE %mask(:,left:right) = repmat(linspace(1,0,right-left+1),size(mask,1),1); mask(up:down,:) = repmat(linspace(0,1,down-up+1)',1,size(mask,2));%復制平鋪矩陣 newImage(:,:,1) = newImage(:,:,1).*mask; newImage(:,:,2) = newImage(:,:,2).*mask; newImage(:,:,3) = newImage(:,:,3).*mask; newImage(:,:,1) = warpedImage(:,:,1) + newImage(:,:,1); newImage(:,:,2) = warpedImage(:,:,2) + newImage(:,:,2); newImage(:,:,3) = warpedImage(:,:,3) + newImage(:,:,3); % newImage(:,:,1) = newImage(:,:,1).*black; % newImage(:,:,2) = newImage(:,:,2).*black; % newImage(:,:,3) = newImage(:,:,3).*black; newImage=uint8(newImage); figure() imshow(newImage); title('漸入漸出融合');
看出,效果還是不錯的,沒有一點點邊緣的痕跡。但是最下方有書本的陰影出現,我猜想是我對重疊區域的處理不夠准確引起的。大家可以試試准確的處理這個不規則重疊區域的權重再分配。
歡迎大家向博主分享,一同學習。