仿射變換(warpAffine)

所謂的仿射轉換,包括旋轉、移動、放大縮小,除了remap()之外,OpenCV提供運用更廣泛的函式warpAffine(),來處理仿射變換,除了透視轉換之外,像放大、縮小、旋轉、左右反轉、扭曲、透視轉換等操作,皆可透過warpAffine()函式得到新的影像。

如果使用warpAffine()得到仿射轉換後的圖,必須輸入仿射矩陣,OpenCV提供getAffineTransform()和getRotationMatrix2D()函式,getAffineTransform()透過變換前後三個點來得到目標矩陣,getRotationMatrix2D()透過旋轉中心、旋轉角度和放大倍率來得到目標矩陣。


仿射矩陣是一個2×3的矩陣,每個輸入點(x,y)都可以得到一個輸出點:

仿射矩陣

共有六個未知數,所以至少需知道三個點,x、y位置共六個參數,在轉換前後的值,這時帶入解聯立方程式,就可以得到a00、a10、a01、a11、b00、b10的解,可以參考以下圖示,只要知道三個點,就可得到這個仿射矩陣。

仿射矩陣

OpenCV仿射矩陣

Mat getAffineTransform(const Point2f src[], const Point2f dst[])

  • src:包含3個點的陣列。
  • dst:包含3個點的陣列,。
  • dst和src的點需相對的,也就是src[0]轉換後的點為dst[0],src1轉換後的點為dst1,返回一個2×3的矩陣,即為仿射矩陣。

我們可以透過另一個函式getRotationMatrix2D(),來得到仿射矩陣。

OpenCV仿射矩陣

Mat getRotationMatrix2D(Point2f center, double angle, double scale)

  • center:輸入圖的旋轉中心。
  • angle:旋轉角度,正值代表順時針旋轉,左上角設為原點。
  • scale:放大比率 輸出一個2×3的矩陣,即為仿射矩陣。

得到仿射矩陣後,對於每個像素位置(x,y),計算後都可得到新像素位置,對影像所有像素進行計算,就可以得到仿射轉換後的影像了。

OpenCV仿射轉換

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())

  • src:輸入圖。
  • dst:輸出圖,尺寸、型態和輸入圖相同。
  • M:2×3的轉換矩陣。
  • flags:線性差值,假設使用WARP_INVERSE_MAP,代表M是反矩陣, (dst->src)
  • borderType:邊緣型態。
  • borderValue:邊界外推的強度值,預設為0。

以下示範兩種仿射轉換的使用,分別是以轉換前後的三個點當基準,以及給定旋轉中心、選轉角度和縮放比例這兩個方式,來得到轉換矩陣,呼叫warpAffine()輸入轉換矩陣,輸出圖就是仿射轉換的結果:

#include <cstdio>
#include <opencv2/opencv.hpp>
using namespace cv;

int main(){
    Mat src = imread("lena.jpg");
    Mat dst1 = Mat::zeros(src.rows, src.cols, src.type());
    Mat dst2 = Mat::zeros(src.rows, src.cols, src.type());

    //選定幾何轉換前後相對的三個點
    Point2f srcTri[3];
    srcTri[0] = Point2f(0, 0);
    srcTri[1] = Point2f(src.cols-1, 0);
    srcTri[2] = Point2f(0, src.rows-1);

    Point2f dstTri[3];
    dstTri[0] = Point2f(0, src.rows*0.3);
    dstTri[1] = Point2f(src.cols*0.8, 0);
    dstTri[2] = Point2f(src.cols*0.1, src.rows*0.9);

    Mat warp_mat = getAffineTransform(srcTri, dstTri);
    warpAffine(src, dst1, warp_mat, dst1.size());


    //設定旋轉中心、旋轉角度和縮放倍率
    Point center = Point(dst2.cols/2, dst2.rows/2);
    double angle = 30.0;
    double scale = 0.8;

    Mat rot_mat = getRotationMatrix2D(center, angle, scale);
    warpAffine(src, dst2, rot_mat, dst2.size());

    imshow("origin", src);
    imshow("Affine_1", dst1);
    imshow("Affine_2", dst2);
    waitKey(0);

    return 0;
}

warpAffine

warpAffine

warpAffine

回到首頁

回到OpenCV教學


參考資料:

OpenCV 教程