图像变换(缩放、裁剪、仿射变换)

OpenCV C++教程目录
1.在Windows Visual Studio中安装OpenCV C++版本
2.图像的基本操作
3.颜色空间转换
4.阈值分割
5.图像变换(缩放、裁剪、仿射变换)
6.图像滤波
7.Canny边缘检测
8.轮廓检测
9.透视变换(perspective transform)
10.光流

本文介绍了使用OpenCV进行图像的变换操作:

  • 缩放
  • 裁剪
  • 仿射变换

1.缩放

OpenCV支持两种图像缩放方式。一种是指定输出图像的长和宽,另一种是分别指定长和宽的缩放参数,输出图像的长/宽 = 等于原始长/宽 * 缩放参数。对图像进行缩放操作通常是通过插值方式实现的,在使用resize()函数进行图像缩放时,我们可以指定不同的插值算法。不同的插值算法适用于不同的场景,对于缩小图像,一般推荐使用INTER_AREA。对于放大图像,则推荐使用INTER_LINEAR

  1. 指定输出分辨率
    Mat image = imread("Lena.png"); //512x512
    // downscale
    int down_width = 300;
    int down_height = 300;
    Mat downscaled;
    resize(image, downscaled, Size(down_width, down_height),  0, 0, INTER_AREA);
    // upscale
    int up_width = 600;
    int up_height = 600;
    Mat upscaled;
    resize(image, upscaled, Size(up_width, up_height), 0, 0, INTER_LINEAR);

  1. 指定缩放比例
    //resize with factor
    Mat factorScaled;
    resize(image, factorScaled, Size(), 1.5, 0.8, INTER_LINEAR);

2.裁剪

对于图像裁剪,OpenCV没有提供独立的API。我们可以使用Mat()的构造函数,通过Range()来指定裁剪的区域。

    Mat img = imread("Lena.png");
    cout << "Width : " << img.size().width << endl; // -> 512
    cout << "Height: " << img.size().height << endl; // ->512
    // Crop image
    Mat cropped_image = img(Range(80,280), Range(150,330));
    cout << "Width : " << cropped_image.size().width << endl; // 330 - 150 = 180
    cout << "Height: " << cropped_image.size().height << endl; // 280 - 80 = 200

这里的第一个Range()指定了裁剪的起始和终止行数。第二个Range()指定了裁剪的起始和终止列数。

3.仿射变换

仿射变换,是指在一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。类似的定义可以延伸至对图像的操作。

仿射变换可以由以下矩阵乘法表示:

其中A是一个2x2的矩阵,代表线性变换操作,T是一个2x1的矩阵,代表平移操作。

典型的仿射变换包括:旋转,镜像,缩放,平移,错移等等。

可以看到,仿射变换实际上代表了两张图片之间的位置关系,即A' = M * A,这里的M就是上面提到的变换矩阵。通常我们有两种应用场景:

  • a. 我们已经知道了A和A', 需要求出变换矩阵M。
  • b. 我们已经知道了A和M, 需要求解经过变换后的矩阵A'。

下面的代码演示了如何用OpenCV根据已知的矩阵A和求出的矩阵M, 计算出变换后的矩阵A'。前面我们说过,变换矩阵M代表了两张图片之前的位置关系。这里我们用一种典型的的方法求出M, 假设我们知道了A和A'中对应的三个点的坐标,就可以根据OpenCV提供的getAffineTransform()函数求出变换矩阵M。再用M和原始矩阵A相乘,就得到了变换后的矩阵A'。

下面代码中的srcTri[3] 和 dstTri[3]就是上面提到的已知的三个点(1,2,3):

    Mat src = imread("Lena.png");

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

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

    Mat warp_mat = getAffineTransform( srcTri, dstTri );
    Mat warp_dst = Mat::zeros( src.rows, src.cols, src.type() );
    warpAffine( src, warp_dst, warp_mat, warp_dst.size() );

    imshow( "Source image", src );
    imshow( "Warp", warp_dst );
    waitKey();

下面是原图片和经过仿射变换之后的结果:
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容