索引地址:系列索引
几何操作仿射变换是指在向量空间中进行一次线性变换(乘以一个矩阵)并加上一个平移(加上一个向量),变换为另一个向量空间的过程。在有限维的情况下,每个仿射变换可以由一个矩阵A和一个向量b给出,它可以写作A和一个附加的列b。一个仿射变换对应于一个矩阵和一个向量的乘法,而仿射变换的复合对应于普通的矩阵乘法,只要加入一个额外的行到矩阵的底下,这一行全部是0除了最右边是一个1,而列向量的底下要加上一个1。
Affine Transform描述了一种二维仿射变换的功能,它是一种二维坐标之间的线性变换,保持二维图形的“平直性”(即变换后直线还是直线,圆弧还是圆弧)和“平行性”(其实是保持二维图形间的相对位置关系不变,平行线还是平行线,而直线上的点位置顺序不变,另特别注意向量间夹角可能会发生变化)。仿射变换可以通过一系列的原子变换的复合来实现包括:平移(Translation)、缩放(Scale)、翻转(Flip)、旋转(Rotation)和错切(Shear).
本篇文章使用的是仿射变换函数。
利用opencv实现仿射变换一般会涉及到warpAffine和getRotationMatrix2D两个函数,其中warpAffine可以实现一些简单的重映射,而getRotationMatrix2D可以获得旋转矩阵。
函数原型:
1 2 3 4 5 6 7 8 void cv::warpAffine ( InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar & borderValue = Scalar() )
src: 输入图像 dst: 输出图像,尺寸由dsize指定,图像类型与原图像一致 M: 2X3的变换矩阵 dsize: 指定图像输出尺寸 flags: 插值算法标识符,有默认值INTER_LINER 平移图像的平移也分为两步:首先定义好图像的平移矩阵,分别指定x方向和y方向上的平移量tx和ty,平移矩阵的形式如下:
M = [ 1 0 t x 0 1 t y ] M = \begin{bmatrix} 1 & 0 & t_{x} \\ 0 & 1 & t_{y} \end{bmatrix} M = [ 1 0 0 1 t x t y ]
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <opencv2/opencv.hpp> using namespace cv;int main () { cv::Mat src = cv::imread ("1.jpg" ); cv::Mat dst; cv::Size dst_sz = src.size (); cv::Mat t_mat = cv::Mat::zeros (2 , 3 , CV_32FC1); t_mat.at <float >(0 , 0 ) = 1 ; t_mat.at <float >(0 , 2 ) = 20 ; t_mat.at <float >(1 , 1 ) = 1 ; t_mat.at <float >(1 , 2 ) = 10 ; cv::warpAffine (src, dst, t_mat, dst_sz); cv::imshow ("image" , src); cv::imshow ("result" , dst); cv::waitKey (0 ); return 0 ; }
测试效果如图:
镜像在opencv2和opencv中,cv::flip()支持图像的翻转(上下翻转、左右翻转,以及同时均可)。
函数原型:
1 2 3 4 5 void cv::flip ( cv::InputArray src, cv::OutputArray dst, int flipCode = 0 ) ;
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #include <opencv2/opencv.hpp> using namespace cv;int main () { cv::Mat image = cv::imread ("1.jpg" ); cv::Mat image_fliped; cv::flip (image, image_fliped, -1 ); cv::imshow ("original" , image); cv::imshow ("fliped" , image_fliped); cv::waitKey (0 ); return 0 ; }
上下翻转效果:
旋转图像的旋转具体实现分为两步:先根据旋转角度和旋转中心获取旋转矩阵;然后根据旋转矩阵进行仿射变换,即可实现任意角度和任意中心的旋转效果。旋转矩阵的形式如下:
M = [ α β ( 1 − α ) c e n t e r . x β c e n t e r . y − β α β c e n t e r . x ( 1 − α ) c e n t e r . y ] M = \begin{bmatrix} \alpha & \beta & (1-\alpha) center.x & \beta center.y \\ -\beta & \alpha & \beta center.x & (1-\alpha) center.y \end{bmatrix} M = [ α − β β α ( 1 − α ) c e n t e r . x β c e n t e r . x β c e n t e r . y ( 1 − α ) c e n t e r . y ]
其中:
α = s c a l e c o s θ \alpha = scale \ cos{\theta} α = s c a l e c o s θ
β = s c a l e s i n θ \beta = scale \ sin{\theta} β = s c a l e s i n θ
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <opencv2/opencv.hpp> using namespace cv;int main () { cv::Mat src = cv::imread ("1.jpg" ); cv::Mat dst; double angle = 45 ; cv::Size src_sz = src.size (); cv::Size dst_sz (src_sz.height, src_sz.width) ; int len = std::max (src.cols, src.rows); cv::Point2f center (len / 2. , len / 2. ) ; cv::Mat rot_mat = cv::getRotationMatrix2D (center, angle, 1.0 ); cv::warpAffine (src, dst, rot_mat, dst_sz); cv::imshow ("image" , src); cv::imshow ("result" , dst); cv::waitKey (0 ); return 0 ; }
测试效果:
缩放函数原型:
1 2 3 void resize ( InputArray src, OutputArray dst, Size dsize, double fx = 0 , double fy = 0 , int interpolation = INTER_LINEAR ) ;
其中第一,二个参数是输入和输出的图像;
第三个参数为调整之后的图像尺寸;
第四个参数fx为x方向的缩放因子,若fx为0,fx = dsize.width/src.cols;
第五个参数fy为y方向的缩放因子,若fy为1,fy = dsize.height/src.rows;
第六个参数interpolation:这个是指定插值的方式,图像缩放之后,肯定像素要进行重新计算的,就靠这个参数来指定重新计算像素的方式,有以下几种:
INTER_NEAREST - 最邻近插值 INTER_LINEAR - 双线性插值,如果最后一个参数你不指定,默认使用这种方法 INTER_AREA - resampling using pixel area relation. It may be a preferred method for image decimation, as it gives moire’-free results. But when the image is zoomed, it is similar to the INTER_NEAREST method. INTER_CUBIC - 4x4像素邻域内的双立方插值 INTER_LANCZOS4 - 8x8像素邻域内的Lanczos插值 测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <opencv2/opencv.hpp> #include <iostream> using namespace cv;void Resize (const Mat &srcImage, Mat &destImage, int width) { int ncols = width; int nrows = srcImage.rows*width / srcImage.cols; resize (srcImage, destImage, cv::Size (nrows, ncols)); }int main () { cv::Mat srcImage = imread ("1.jpg" ); if (!srcImage.data) return -1 ; imshow ("srcImage" , srcImage); Mat destImage; double angle = 9.9 ; Resize (srcImage, destImage, 400 ); imshow ("dst" , destImage); waitKey (0 ); return 0 ; }
测试效果:
错切图像的错切变换实际上是平面景物在投影平面上的非垂直投影效果。图像错切变换也称为图像剪切、错位或错移变换。图像错切的原理就是保持图像上各点的某一坐标不变,将另一个坐标进行线性变换,坐标不变的轴称为依赖轴,坐标变换的轴称为方向轴。图像错切一般分为两种情况:水平方向错切和垂直方向错切。
水平方向的错切,即沿x轴方向关于y的错切,即x=x0+c*y0, y=y0
若c>0,则沿+x轴方向错切,反之,如果c<0,则沿-x轴方向错切.