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。
- 指定输出分辨率
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);
- 指定缩放比例
//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' = 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();
下面是原图片和经过仿射变换之后的结果: