OpenCV3入門(九)圖像幾何變換


1、圖像縮放

假設圖像x軸的縮放因子Sx, y軸方向的縮放因子Sy,相應的變換表達式為:

 

函數原型為:

CV_EXPORTS_W void resize( InputArray src, OutputArray dst,
                          Size dsize, double fx = 0, double fy = 0,
                          int interpolation = INTER_LINEAR );

示例程序如下。

img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
imshow("原圖", img);
resize(img, img2, Size(), 0.5, 0.5);
imshow("縮放圖1", img2);
resize(img, img3, Size(), 0.8, 0.5);
imshow("縮放圖2", img3);

運行效果如下圖。

 

 resize(img, img2, Size(), 1.2, 1.2);

 

2、圖像平移

假設圖像x軸的平移量Tx, y軸方向的平移量Ty,相應的變換表達式為:

 

仿射變換的原理為:

dst(x,y)=src(M11x+M12y+M13,M21x+M22y+M23)

平移操作可以使用OpenCV的仿射變換函數來實現,使用的變換矩陣為:

 

函數原型為:

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

圖像平移示例。

img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp", IMREAD_GRAYSCALE);
imshow("原圖", img);

// x軸平移20,y軸平移10, 2 * 3矩陣
Mat M = Mat::zeros(2, 3, CV_32FC1);
M.at<float>(0, 0) = 1;
M.at<float>(0, 2) = 20;
M.at<float>(1, 1) = 1;
M.at<float>(1, 2) = 10;
warpAffine(img, img2, M, img.size());
imshow("平移圖", img2);

3、圖像旋轉

假設點P0(x0,y0),角度為a,令L=|OP|=sqrt(x*x + y*y).

P0旋轉b度到P1(x1,y1),則

x1=L*cos(a+b)=L* cos(a)*cos(b) – L*sin(a)*sin(b) = x0*cos(b) - y0*sin(b)

y1=L*sin(a+b)=L* sin(a)*cos(b) + L*cos(a)*sin(b) = y0*cos(b) + x0*sin(b)

OpenCV內置仿射變換的旋轉函數,支持任意點為中心的圖像旋轉,函數原型為:

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

示例代碼如下。

img = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
imshow("原圖", img);

Point center = Point(img.cols / 2, img.rows / 2);
Mat m1= getRotationMatrix2D(center, 30, 1.0);
Mat m2 = getRotationMatrix2D(center, 30, 0.7);
Mat m3 = getRotationMatrix2D(center, 30, 1.2);
warpAffine(img, img1, m1, img.size());
warpAffine(img, img2, m2, img.size());
warpAffine(img, img3, m3, img.size());
imshow("img1", img1);
imshow("img2", img2);
imshow("img3", img3);

修改旋轉角度效果如下圖。

Mat m1= getRotationMatrix2D(center, 180, 1.0);

Mat m2 = getRotationMatrix2D(center, 270, 0.7);

 

如果旋轉點的坐標原點不在圖片中心,則圖片繞着指定點旋轉。

Point center = Point(0, 0);

Mat m1= getRotationMatrix2D(center, 30, 1.0);

Mat m2 = getRotationMatrix2D(center,-45, 1.0);

對應的矩陣為:

m1=

[0.8660254037844387, 0.4999999999999999, 0;

 -0.4999999999999999, 0.8660254037844387, 0]

m2=

[0.7071067811865476, -0.7071067811865476, 0;

 0.7071067811865476, 0.7071067811865476, 0]

輸出效果如下圖。

4、圖像重映射

重映射就是把一個圖像中一個為之的像素放置到另一個圖片指定位置過程。由於映射后的圖像在原圖中可能沒有對應的整數坐標點像素,所以為了完成重映射需要做一些插值作為非整數像素坐標。我們通過重映射來表達每個像素的位置(x, y):g(x, y)=f(h(x,y))

OpenCV使用remap函數完成重映射功能,函數原型為:

CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
                         InputArray map1, InputArray map2,
                         int interpolation, int borderMode = BORDER_CONSTANT,
                         const Scalar& borderValue = Scalar());

測試代碼如下。

void update_map(int ind, Mat &map_x, Mat &map_y)
{
    for (int i = 0; i < map_x.rows; i++)
    {
        for (int j = 0; j < map_x.cols; j++)
        {
            switch (ind)
            {
            case 0:
                if (j > map_x.cols*0.25 && j < map_x.cols*0.75 && i > map_x.rows*0.25 && i < map_x.rows*0.75)
                {
                    map_x.at<float>(i, j) = 2 * (j - map_x.cols*0.25f) + 0.5f;
                    map_y.at<float>(i, j) = 2 * (i - map_x.rows*0.25f) + 0.5f;
                }
                else
                {
                    map_x.at<float>(i, j) = 0;
                    map_y.at<float>(i, j) = 0;
                }
                break;
            case 1:
                map_x.at<float>(i, j) = (float)j;
                map_y.at<float>(i, j) = (float)(map_x.rows - i);
                break;
            case 2:
                map_x.at<float>(i, j) = (float)(map_x.cols - j);
                map_y.at<float>(i, j) = (float)i;
                break;
            case 3:
                map_x.at<float>(i, j) = (float)(map_x.cols - j);
                map_y.at<float>(i, j) = (float)(map_x.rows - i);
                break;
            default:
                break;
            } // end of switch
        }
    }
}

int main() {
    Mat src = imread("D:\\WORK\\5.OpenCV\\LeanOpenCV\\pic_src\\pic9.bmp");
    imshow("原圖", src);

    Mat dst(src.size(), src.type());
    Mat map_x(src.size(), CV_32FC1);
    Mat map_y(src.size(), CV_32FC1);

    update_map(0, map_x, map_y);
    remap(src, img1, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow("img1", img1);

    update_map(1, map_x, map_y);
    remap(src, img2, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow("img2", img2);

    update_map(2, map_x, map_y);
    remap(src, img3, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow("img3", img3);

    update_map(3, map_x, map_y);
    remap(src, img4, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
    imshow("img4", img4);

    waitKey();
}

輸入圖像:

代碼實現四種remap效果。

 

remap后的圖像:

 

例子2:x軸不壓縮,y軸按照一元二次曲線進行壓縮,對稱抽為src.rows / 2。當y= src.rows / 2,對應變換前的圖坐標src.rows,所以圖像被壓縮。當y=[ src.rows / 2,src.rows]時,y軸被反轉。

for (int i = 0; i < src.rows; i++)
{
    for (int j = 0; j < src.cols; j++)
    {
        map_x.at<float>(i, j) = j;
        map_y.at<float>(i, j) = (float)((-1 * pow(i- src.rows / 2, 2) / pow(src.rows / 2, 2)) + 1) * src.rows;
    }
}

5、參考文獻

1、《OpenCV3 編程入門》,電子工業出版社,毛星雨著

2、《學習OpenCV》,清華大學出版社,Gary Bradski, Adrian kaehler著

3、Remapping

https://docs.opencv.org/3.4/d1/da0/tutorial_remap.html

4、OpenCV圖像旋轉

https://www.cnblogs.com/konglongdanfo/p/9135501.html

 

技術博客,轉載請注明。

https://www.cnblogs.com/pingwen/p/12329168.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM