前言:
眼前兄弟们对“写出二维图形几何变换矩阵的一般表示式”大体比较珍视,朋友们都想要知道一些“写出二维图形几何变换矩阵的一般表示式”的相关文章。那么小编在网上搜集了一些关于“写出二维图形几何变换矩阵的一般表示式””的相关资讯,希望朋友们能喜欢,兄弟们一起来了解一下吧!仿射变换(Affine Transformation 或Affine Map)是一种二维坐标(x, y)到二维坐标 (u, v)的线性变换。图像处理中,可应用仿射变换对二维图像进行平移、缩放、旋转等操作。仿射变换的数学表达式如下:
写成矩阵形式如下式所示:
对应的齐次坐标矩阵表示形式为:
仿射变换保持了图像的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。非共线的三对对应点确定一个唯一的仿射变换。
仿射变换通过一系列原子变换复合实现,具体包括:平移(Translation)、缩放(Scale)、旋转(Rotation)、翻转(Flip)和错切(Shear)。
平移操作如下式所示,其中(tx,ty)T 是平移向量。
缩放操作如下式所示,其中Sx ,Sy 是缩放系数:
旋转操作公式如下式所示,其中 θ是旋转角度:
翻转操作将图像上下左右颠倒,如下式所示:
错切操作如下式所示,包含水平错切和垂直错切,常用于产生弹性物体的变形处理:
基本的原子变换可以级联进行,连续多个变换可借助于矩阵的相乘最后用一个单独的3×3变换矩阵来表示,最后用到的实际上是3×3的前两行的2×3矩阵。
OpenCV中使用warpAffine()函数来进行仿射变换,其函数原型为:
void warpAffine( InputArray src, //输入图像 OutputArray dst, //输出图像,位深度与图像一致 InputArray M, //仿射变换矩阵 Size dsize, //输出图像大小 int flags = INTER_LINEAR, //像素插值方法,默认是双线性插值 int borderMode = BORDER_CONSTANT, //边界扩充方法,默认取常数 const Scalar& borderValue = Scalar() //边界填充值);
在warpAffine()函数当中,目标图像dst中的每个像素值都是从源图像中计算得到的,其计算公式如式(2)所示。一般来说,仿射变换之后得到的坐标值都不是整数,这就需设置 flags标记,对源图像相邻像素插值从而得到目标像素的值。若flags设置为cv::WARP_INVERSE_MAP,则表示从dst到src的反向仿射变换。
仿射变换的关键是确定仿射变换矩阵M,这里有几种方法可以确定。如果已知变换前后的多组特征点的坐标,矩阵M可以用cv::getAffineTransform()来确定,这里需要输入变换前后的3个点对;如果知道图像的旋转角度和缩放比例,则可以利用函数cv::getRotationMatrix2D()来确定;如果知道确切的仿射变换类型,则也可以根据式(4)到式(8)直接写出矩阵M。
cv::getAffineTransform()函数的原型为:
Mat getAffineTransform( const Point2f src[], //变换前3个点的坐标 const Point2f dst[] //变换后3个点的坐标);
cv::getRotationMatrix2D()函数的原型为:
Mat getRotationMatrix2D( Point2f center, //旋转中心 double angle, //旋转角度 double scale //缩放比例);
仿射变换实例
void ImageAffineTransform(){ //加载原图像 Mat src = imread("fruits.png", IMREAD_COLOR); cv::Point2f srcTri[] = { cv::Point2f(0, 0), //原图像左上角坐标 cv::Point2f(src.cols - 1, 0), //原图像右上角坐标 cv::Point2f(0, src.rows - 1) //原图像左下角坐标 }; cv::Point2f dstTri[] = { //目标图像左上角坐标 cv::Point2f(src.cols*0.f, src.rows*0.33f), //目标图像右上角坐标 cv::Point2f(src.cols*0.85f, src.rows*0.25f), //目标图像左下角坐标 cv::Point2f(src.cols*0.15f, src.rows*0.7f) }; //由3组点对得到仿射变换矩阵 cv::Mat m1 = cv::getAffineTransform(srcTri, dstTri); cv::Mat dst1; cv::warpAffine(src, dst1, m1, src.size());//第1种仿射变换 cv::imshow("Image1",dst1); float scale = 1.1; float angle = -15; float radian = (float)(angle / 180.0 * CV_PI); //将角度转换到弧度 //计算图像旋转之后包含图像的最大的矩形 float sinVal = abs(sin(radian))*scale; //sinθ float cosVal = abs(cos(radian))*scale; //cosθ //目标图像大小 int dstWidth = int(src.cols * cosVal + src.rows * sinVal); int dstHeight = int(src.cols * sinVal + src.rows * cosVal); //旋转中心位于目标图像中心 cv::Point2f center((float)(dstWidth / 2), (float)(dstHeight / 2)); //求得仿射变换矩阵 cv::Mat m2 = getRotationMatrix2D(center, angle, scale); int dx = (dstWidth - src.cols) / 2; int dy = (dstHeight - src.rows) / 2; cv::Mat dst2; //dst是旋转之后的图像 //将图像拷贝到目标图像中心,并扩大图像 copyMakeBorder(src, dst2, dy, dy, dx, dx, BORDER_CONSTANT); //就地执行仿射变换,第2种仿射变换 warpAffine(dst2, dst2, m2, Size(dstWidth, dstHeight)); imshow("image2", dst2); //仿射矩阵,由缩放操作和错切操作组成 cv::Matx23f m3(1.5,0.5,10,0.1,1,10); //直接用公式计算仿射变换后图像大小 int nDstWid3 = int(m3(0,0)*src.cols + m3(0,1)*src.rows + m3(0,2)); int nDstDep3 = int(m3(1,0)*src.cols + m3(1,1)*src.rows + m3(1,2)); Size dstSize3 = Size(nDstWid3, nDstDep3); Mat dst3; warpAffine(src, dst3, m3, dstSize3); //第3种仿射变换 imshow("image3", dst3); waitKey(0);}
程序运行结果如下列图像所示:
标签: #写出二维图形几何变换矩阵的一般表示式