當前位置: 妍妍網 > 碼農

OpenCV築基之影像的仿射變換

2024-03-18碼農


1. 幾何變換

影像的 幾何變換 是指將一幅影像中的座標位置對映到另一幅影像中的新座標位置,其實質是改變像素的空間位置,估算新空間位置上的像素值。幾何變換不改變影像的像素值,只是在影像平面上進行像素的重新安排。

以下是常用的幾種幾何變換:

  • 旋轉:將影像旋轉指定角度。

  • 縮放:按縮放因子調整影像大小,使其變大或變小。

  • 平移:將影像從當前位置移動到新位置。

  • 錯切:沿特定軸傾斜影像。

  • 仿射變換:一個更廣泛的類別,包括單個變換中的縮放、旋轉、錯切和平移。

  • 透視變換:此變換模擬 3D 空間中的透視效果,允許進行更復雜的操作,例如校正由攝影機角度引起的扭曲。

  • 幾何變換通常使用數學函式和變換矩陣來實作。這些矩陣定義了原始影像中的每個像素如何對映到轉換影像中的新位置。

    2. 仿射變換

    2.1 仿射變換

    影像處理中的 仿射變換 是指對影像進行一次線性變換和平移,將其對映到另一個影像空間的過程。仿射變換可以保持影像的「 平直性 」,即直線經過仿射變換後依然為直線,平行線經過仿射變換後依然為平行線。

    通常,使用 2x3 大小陣列 M 來進行仿射變換。陣列由兩個矩陣 A、B 組成,其中矩陣 A(大小為2x2)用於矩陣乘法,矩陣 B(大小為2x1)用於向量加法。

    原像素點座標(x,y),經過仿射變換後的點的座標是(u,v),則矩陣仿射變換基本演算法原理:

    其數學運算式如下:

    其中:

  • 和 代表縮放系數,控制影像在水平胡垂直方向上的縮放。

  • 和 代表錯切系數,控制影像的水平胡垂直錯切。

  • 和 代表平移系數,控制影像在水平胡垂直方向上的平移。

  • 由於縮放和旋轉是透過矩陣乘法來實作,平移是透過矩陣加法來實作的,將這幾個操作都用一個矩陣實作所以構造出上面的 2x3 矩陣 M。

    仿射變換是從二維座標到二維座標之間的線性變換,且為了保持二維影像的「平直性」和「平行性」。我們需要引入 齊次座標 的概念,最終得到的 齊次座標矩陣 表示形式為:

    2.2 齊次座標

    在數學裏,齊次座標(homogeneous coordinates),或投影座標(projective coordinates)是指一個用於投影幾何裏的座標系統,如同用於歐氏幾何裏的笛卡兒座標一般。齊次座標可讓包括無窮遠點的點座標以有限座標表示。使用齊次座標的公式通常會比用笛卡兒座標表示更為簡單,且更為對稱。

    引入齊次座標的目的是為了更好的表示無限遠(infinity)的座標的概念,在歐式空間中,無限大或者無限小的座標的並不存在,不能用數值表示。數學家 August Ferdinand Möbius(1) 提出了 齊次座標系 ,采用 N+1 個量來表示 N 維座標。

    例如,在二維齊次座標系中,我們引入一個量 w,將一個二維點 (x,y) 表示為 (X,Y,w) 的形式,其轉換關系為

    其中,w 可以為任意值。

    在笛卡爾座標系中以(1,2)為例,在齊次座標系中可以用(1,2,1)表示,也可以用(2,4,2)表示,還可以用 (4,8,4),(8,16,8)...表示,即 (k,2k,k),k∈ R 這些點都對映到歐式空間中的一點,即這些點具有 尺度不變性(Scale Invariant) ,是「齊性的」(同族的),所以稱之為 齊次座標

    「齊次座標表示是電腦圖形學的重要手段之一,它既能夠用來明確區分向量和點,同時也更易用於進行仿射(線性)幾何變換。」——出自【電腦圖形學(OpenGL版)】的作者 F.S. Hill Jr.

    透過齊次座標還可以證明兩條平行線可以相交,非常有意思。

    3. 仿射變換中常見的變換形式

    OpenCV 提供了 warpAffine() 函式實作仿射變換。它可以用於實作各種影像幾何變換,例如平移、縮放、旋轉、錯切等。

    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: 仿射變換矩陣,2x3 的浮點數矩陣。

    第四個參數 dsize: 輸出影像的大小。

    第五個參數 flags: 插值方式,預設值為 INTER_LINEAR,表示使用雙線性插值。

    第六個參數 borderMode: 邊界模式,預設值為BORDER_CONSTANT,表示使用常量值填充邊界。

    第七個參數 borderValue: 邊界填充值,預設值為0。

    3.1 平移

    影像平移的公式:

    下面的程式碼,分別實作了對影像沿著 x 軸、y 軸進行平移

    #include<opencv2/core.hpp>
    #include<opencv2/imgproc.hpp>
    #include<opencv2/opencv.hpp>
    usingnamespacestd;
    usingnamespace cv;
    intmain(){
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(23) <<10400010);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Shift along X-axis", dst);
    warp_matrix = (cv::Mat_<float>(23) <<10001400);
    cv::warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    cv::imshow("Shift along Y-axis", dst);
    waitKey(0);
    return0;
    }




    平移變換.png

    3.2 縮放

    影像縮放的公式:

    下面的程式碼,分別實作了對影像進行0.75和1.25倍的縮放。

    #include<opencv2/core.hpp>
    #include<opencv2/imgproc.hpp>
    #include<opencv2/opencv.hpp>
    usingnamespacestd;
    usingnamespace cv;
    intmain(){
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    // 設定縮放比例
    float scale = 0.75;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(23) <<scale, 000, scale, 0);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Scale 0.75", dst);
    scale = 1.25;
    warp_matrix = (cv::Mat_<float>(23) <<scale, 000, scale, 0);
    cv::warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    cv::imshow("Scale 1.25", dst);
    waitKey(0);
    return0;
    }





    縮放變換.png

    3.3 旋轉

    影像旋轉的公式:

    OpenCV 提供了更為簡潔的 getRotationMatrix2D() 函式用於生成一個 2x3 的仿射變換矩陣,該矩陣可以用於對影像進行旋轉操作。

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

    第一個參數 center: 影像旋轉中心,以像素為單位。

    第二個參數 angle: 旋轉角度,以度為單位。逆時針方向為正。

    第三個參數 scale: 旋轉後的影像縮放比例。

    下面的程式碼,展示了以影像的中心作為旋轉中心,並且逆時針方向旋轉45度。

    #include<opencv2/core.hpp>
    #include<opencv2/imgproc.hpp>
    #include<opencv2/opencv.hpp>
    usingnamespacestd;
    usingnamespace cv;
    intmain(){
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    Point center = Point(width / 2, height / 2);
    double angle = 45;
    double scale = 1.0;
    Mat dst;
    Mat warp_matrix = getRotationMatrix2D(center, angle, scale);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Rotate", dst);
    waitKey(0);
    return0;
    }



    旋轉變換.png

    3.4 錯切

    影像錯切的公式:

    其中,

  • , 時,沿 x 方向錯切。

  • , 時,沿 y 方向錯切。

  • 下面的例子,展示影像的錯切。

    #include<opencv2/core.hpp>
    #include<opencv2/imgproc.hpp>
    #include<opencv2/opencv.hpp>
    usingnamespacestd;
    usingnamespace cv;
    intmain(){
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    float a = 0.25;
    float b = 0.5;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(23) <<1, a, 0, b, 10);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Shearing", dst);
    waitKey(0);
    return0;
    }




    錯切變換.png

    4. 總結

    影像仿射變換是一種簡單而有效的影像幾何變換方法,在影像處理和電腦視覺領域有著廣泛的套用。它可以用於影像矯正、增強、配準、合成、目標辨識和跟蹤等多種任務。

    推薦閱讀

    掃碼檢視深度學習系統化學習路線圖