仿射变换代表的是两幅图像之间的映射关系。
仿射变换是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。它保持了二维图形的“平直性”(即:直线经过变换之后依然是直线)和“平行性”(即:二维图形之间的相对位置关系保持不变,平行线依然是平行线,且直线上点的位置顺序不变)。
一个任意的仿射变换都能表示为乘以一个矩阵(线性变换)接着再加上一个向量(平移)的形式
仿射变换三种常见的变换形式:
旋转,rotation (线性变换)
平移,translation(向量加)
缩放,scale(线性变换)
通常使用2 x 3的矩阵来表示仿射变换:
仿射变换的求法:
使用场景:
<1> 已知 X和T,而且我们知道他们是有联系的,求出矩阵 M
<2> 已知 M和X,求 T。用算式T = M·X. 对于这种联系的信息可以用矩阵 M 清晰的表达 (即给出明确的2×3矩阵) 或者也可以用两幅图片点之间几何关系来表达。
矩阵M 联系着两幅图片,就以 其表示两图中各三 点直接的联系为例。
图中,点1, 2,3与image2中的点一 一映射。
void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar())对图像做放射变换。
dst(x, y) = src(M11x + M12y + M13, M21x + M22y + M23)
参数1,InputArray类型的src,源图像,Mat类的对象。
参数2,运算结果,需和源图片有一样的尺寸和类型。
参数3,InputArray类型的M,2×3的变换矩阵。
参数4,Size类型的dsize,表示输出图像的尺寸。
参数5,int类型的flags,插值方法的标识符。参数有默认值INTER_LINEAR(线性插值),可选的插值方式如下:
INTER_NEAREST 最近邻插值
INTER_LINEAR 线性插值(默认值)
INTER_AREA 区域插值
INTER_CUBIC 三次样条插值
INTER_LANCZOS4 Lanczos插值
WARP_FILL_OUTLIERS 填充所有输出图像的象素。 如果部分象素落在输入图像的边
界外,那么它们的值设定为 fillval.
WARP_INVERSE_MAP 表示M为输出图像到输入图像的反变换,即 因此可以直接用
来做象素插值。否则, warpAffine函数从M矩阵得到反变换。
参数6,int类型的borderMode,边界像素模式,默认值为BORDER_CONSTANT。
参数7,在恒定的边界情况下取的值,默认值为Scalar(),即0。
计算二维旋转变换矩阵。变换会将旋转中心映射到它自身:
Mat getRotationMatrix2D(Point2f center, double angle, double scale)
参数1,表示源图像的旋转中心。
参数2,旋转角度。角度为正值表示向逆时针旋转(坐标原点是左上角)。
参数3,缩放系数。
计算二维三角变换矩阵
Mat getAffineTransform( InputArray src, InputArray dst );
参数1,InputArray类型的src,原来三个点的坐标;
参数2,OutputArray类型的dst,映射后三个点的坐标;
//定义两组点,代表两个三角形 Point2f srcTriangle[3]; Point2f dstTriangle[3]; //定义一些Mat变量 Mat rotMat(2, 3, CV_32FC1); Mat warpMat(2, 3, CV_32FC1); Mat srcImage, dstImage_warp, dstImage_warp_rotate; //加载源图像并作一些初始化 srcImage = imread("1.jpg", 1); dstImage_warp = Mat::zeros(srcImage.rows, srcImage.cols, srcImage.type()); //设置源图像和目标图像上的三组点以计算仿射变换 srcTriangle[0] = Point2f(0, 0); srcTriangle[1] = Point2f(static_cast<float>(srcImage.cols - 1), 0); srcTriangle[2] = Point2f(0, static_cast<float>(srcImage.rows - 1)); dstTriangle[0] = Point2f(static_cast<float>(srcImage.cols*0.0), static_cast<float> (srcImage.rows*0.33)); dstTriangle[1] = Point2f(static_cast<float>(srcImage.cols*0.65), static_cast<float>(srcImage.rows*0.35)); dstTriangle[2] = Point2f(static_cast<float>(srcImage.cols*0.15), static_cast<float>(srcImage.rows*0.6)); //求得仿射变换 warpMat = getAffineTransform(srcTriangle, dstTriangle); //对源图像应用求得的仿射变换 warpAffine(srcImage, dstImage_warp, warpMat, dstImage_warp.size()); //对图像进行缩放后再旋转 // 计算绕图像中点顺时针旋转50度缩放因子为0.6的旋转矩阵 Point center = Point(dstImage_warp.cols / 2, dstImage_warp.rows / 2); double angle = -30.0; double scale = 0.8; // 通过上面的旋转细节信息求得旋转矩阵 rotMat = getRotationMatrix2D(center, angle, scale); // 旋转已缩放后的图像 warpAffine(dstImage_warp, dstImage_warp_rotate, rotMat, dstImage_warp.size());