1. 程式人生 > >影象仿射變換及影象扭曲(Image Warping)

影象仿射變換及影象扭曲(Image Warping)

空間影象幾何變換包括兩個主要步驟:

(1) 空間座標變換

(2)變換座標的賦值、插值運算

空間座標變換一般可以表達為如下式子:


對於用得普遍的仿射變換,可以表達為如下式子:


(x, y)為變換後的座標,(v, w)為變換前的座標。通過變換矩陣T,可以進行影象的縮放,旋轉,平移等。有了座標的變換,下面一步就是進行畫素灰度級的賦值了。從原始影象對映到變換影象,賦值的時候需要進行插值運算。通常情況下有三種插值運算:最鄰近插值法、雙線性插值法、雙三次插值法。

在仿射變換的一般表示式中,有兩種基本的變換方法。第一種是forward mapping, 第二種 是inverse mapping(backward mapping)。在inverse mapping 中,(v, w) = T¬-1(x, y)。一般情況下,inverse mapping 比forward mapping更有效。仿射變換的原始座標中,首先將原座標變換為齊次座標)。並且經過仿射變換後,你有了

影象插值的基礎,這樣你就可以學習Image Warping了。姑且翻譯為影象扭曲吧。Image Warping 同時也分為 Forward Warping 和 Backward Warping。下面一一介紹:

Image Warping:



和Mapping一樣,都是從原始影象向目標影象對映。其中(x’,y’)= T(x,y),x,y為原始影象座標。同理,作為Backward Warping則為相反的方向。



其中,(x,y) =inverse(T (x’,y’))。就是從目標影象向原始影象進行映射了。

對於這兩種方法,那麼哪一種的效果比較好呢?如果實驗一下,就會知道,Backward Warping效果比Forward Warping效果好。Forward Warping容易產生空洞及畫素的重疊,使其結果不理想。

我想原理還是不難理解的。但是如果我們真正要動手去實現這個個東西,仔細想想,還是缺點什麼?那就是缺少變換函式(變換矩陣),就像文章前面提到的仿射變換需要變換矩陣T,那麼我們這裡需要的是變換矩陣H,英文叫Homography,單應矩陣。如果已經有幅影象,只需要找到原始影象中的任意四個點座標(其中至少三個點不在同一條直線上),並且指定目標影象中的四個點,這樣通過這八個點,就能求出變換矩陣H。由於樓主只實驗了Backward Warping,所以下面以Backward Warping為例子進行說明,Forward Warping與其類似,但是變換方向不一樣,自然H的方向就不一樣。具體過程如下:


變換矩陣H

是3X3,根據對其次座標的理解,H的最後一個元素始終為1,又由於只需要各四個點,所以可以看到最後只取到了h32。並且x,y全部已知,可以通過最小二乘方法求取H


最後,再在得到的H中,根據齊次座標的概念,求得最終對映的座標點:



注意,h33 = 1。

下面貼出Backward Warping的Matlab程式碼:

%Backward warping
I = imread('X.jpg');  %reference image
I=rgb2gray(I);
 
I_r = imread('original.jpg');
I_r = rgb2gray(I_r);
[Rows Cols d1] = size(I_r);
figure(1)
imshow(I_r);
title('original image');

figure(2)
imshow(I);
title('reference image');

changeCoordinates=[36,39;618,43;616,285;39,288];
originalCoordinates=[27,13;546,101;550,294;28,330];

A=[];
A1=[originalCoordinates(1,1),originalCoordinates(1,2),1,0,0,0,(-1)*originalCoordinates(1,1)*changeCoordinates(1,1),(-1)*originalCoordinates(1,2)*changeCoordinates(1,1)];
A2=[0,0,0,originalCoordinates(1,1),originalCoordinates(1,2),1,(-1)*originalCoordinates(1,1)*changeCoordinates(1,2),(-1)*originalCoordinates(1,2)*changeCoordinates(1,2)];

A3=[originalCoordinates(2,1),originalCoordinates(2,2),1,0,0,0,(-1)*originalCoordinates(2,1)*changeCoordinates(2,1),(-1)*originalCoordinates(2,2)*changeCoordinates(2,1)];
A4=[0,0,0,originalCoordinates(2,1),originalCoordinates(2,2),1,(-1)*originalCoordinates(2,1)*changeCoordinates(2,2),(-1)*originalCoordinates(2,2)*changeCoordinates(2,2)];

A5=[originalCoordinates(3,1),originalCoordinates(3,2),1,0,0,0,(-1)*originalCoordinates(3,1)*changeCoordinates(3,1),(-1)*originalCoordinates(3,2)*changeCoordinates(3,1)];
A6=[0,0,0,originalCoordinates(3,1),originalCoordinates(3,2),1,(-1)*originalCoordinates(3,1)*changeCoordinates(3,2),(-1)*originalCoordinates(3,2)*changeCoordinates(3,2)];

A7=[originalCoordinates(4,1),originalCoordinates(4,2),1,0,0,0,(-1)*originalCoordinates(4,1)*changeCoordinates(4,1),(-1)*originalCoordinates(4,2)*changeCoordinates(4,1)];
A8=[0,0,0,originalCoordinates(4,1),originalCoordinates(4,2),1,(-1)*originalCoordinates(4,1)*changeCoordinates(4,2),(-1)*originalCoordinates(4,2)*changeCoordinates(4,2)];
A=[A1;A2;A3;A4;A5;A6;A7;A8];

bv=[changeCoordinates(1,:),changeCoordinates(2,:),changeCoordinates(3,:),changeCoordinates(4,:)]';% b 
h=pinv(A)*bv; % pinv(A) = (A'A)`A' A'=A^T X`=X^(-1) % Least Square Method
%h=((A'*A)^-1)*A'*bv;
% H=[h(1),h(2),h(3);h(4),h(5),h(6);h(7),h(8),1];
H=[h(1),h(2),h(3);h(4),h(5),h(6);h(7),h(8),1]
H=inv(H);

img_final=[];
M=zeros(Rows,Cols);
X=zeros(3,1);
for j=1:Rows 
    for i=1:Cols  
        X = H*[i;j;1];
        X=X/X(3);
        original_x=X(1);
        original_y=X(2);
 
        original_x = round(original_x); 
        original_y = round(original_y);
        
        if original_x<1 || original_y<1 || original_x >Cols || original_y>Rows
            continue;
        end
        M(j,i) = I_r(original_y, original_x);
          
    end
end

% M = uint8(M);
for j=1:Rows %y
    for i=1:Cols %x
%         b1=M(0,0);
%         b2=M(1,0)-M(0,0);
%         b3=M(0,1)-M(0,0);
%         b4=M(0,0)-M(1,0)-M(0,1)+M(1,1);
% %       M(j,i)=b1+b2*i+b3*j+b4*j*i;
X1 = H*[i;j;1];
X1=X1/X1(3);

if X1(1)<1 || X1(1)>Rows || X1(2)<1 || X1(2)>Cols	
    continue; 
end

b = fix(X1);
k=X1-b;
val=M(b(1), b(2))*(1-k(1))*(1-k(2)) ...
+ M(b(1), b(2)+1)*k(2)*(1-k(1)) ...
+ M(b(1)+1, b(2))*(1-k(2))*k(1) ...
+ M(b(1)+1, b(2)+1)*k(1)*k(2);
X1=fix(X1);
img_final(i,j) = val;

    end
end

img_final=uint8(img_final);
figure(3)
imshow(img_final);
程式碼最後做了雙線性內插的,保證得到的影象更平滑。實驗圖片的來源起始很簡單,就是用手機在一個建築物面前正面照一張,手機橫向側著照一張。然後,分別找出建築物四個相同特徵分別在兩幅圖中的位置,這樣就得到了八個點的座標。

同時,用OpenCV裡面的Warping函式試了一下,測試程式碼和結果如下:(VS2010 + OpenCV2.4.9.0)

#include <iostream>
#include "cv.h"
#include "highgui.h"

using namespace std;
using namespace cv;

int main(int argc, char**argv)
{
	char* source_window = "Source Image";
	char* warp_window = "Warp Image";
	char* warp_rotate_window = "Warp + Rotate";

	Mat src = imread("lena.jpg");
	Point2f srcTri[3];
	Point2f dstTri[3];
	Mat rotMat(2,3,CV_32FC1);
	Mat warpMat(2,3,CV_32FC1);
	Mat warpDst,warpRotateDst;

	warpDst = Mat::zeros(src.rows,src.cols,src.type());

	srcTri[0] = Point2f(0, 0);
	srcTri[1] = Point2f(src.cols - 1, 0);
	srcTri[2] = Point2f(0, src.rows - 1);

	dstTri[0] = Point2f(src.cols * 0.0, src.rows * 0.33);
	dstTri[1] = Point2f(src.cols * 0.85, src.rows * 0.25);
	dstTri[2] = Point2f(src.cols * 0.15, src.rows * 0.7);

	warpMat = getAffineTransform(srcTri,dstTri);
	warpAffine(src,warpDst,warpMat,warpDst.size());

	Point center = Point(warpDst.cols/2,warpDst.rows/2);
	double angle = -90.0;	//negative - clock-wise
	double scale = 0.6;

	rotMat = getRotationMatrix2D(center,angle,scale);
	warpAffine(warpDst,warpRotateDst,rotMat,warpDst.size(),INTER_CUBIC);

	namedWindow(source_window,CV_WINDOW_AUTOSIZE);
	imshow(source_window,src);

	namedWindow(warp_window,CV_WINDOW_AUTOSIZE);
	imshow(warp_window,warpDst);

	namedWindow(warp_rotate_window,CV_WINDOW_AUTOSIZE);
	imshow(warp_rotate_window,warpRotateDst);

	waitKey(0);
	return 0;
}
原始影象:

Warping結果:

Warping + Rotation結果:



其實突然發現Affine Transform 和Warping的原理好類似,甚至感覺是一個東西,都可以稱之為Mapping。只是變換矩陣的不同而已,Warping中還是用了Least Square Method等,但他們都是以齊次座標理論為基礎的。在學習Warping的時候,還看見了一種叫Morphing的東東,它是以Warping為基礎的影象變形。那是後話了。。。