龙空技术网

OpenCV对数字图像进行仿射变换

klogin 73

前言:

眼前兄弟们对“写出二维图形几何变换矩阵的一般表示式”大体比较珍视,朋友们都想要知道一些“写出二维图形几何变换矩阵的一般表示式”的相关文章。那么小编在网上搜集了一些关于“写出二维图形几何变换矩阵的一般表示式””的相关资讯,希望朋友们能喜欢,兄弟们一起来了解一下吧!

仿射变换(Affine Transformation 或Affine Map)是一种二维坐标(x, y)到二维坐标 (u, v)的线性变换。图像处理中,可应用仿射变换对二维图像进行平移、缩放、旋转等操作。仿射变换的数学表达式如下:

式1. 仿射变换基本公式

写成矩阵形式如下式所示:

式2: 仿射变换矩阵形式

对应的齐次坐标矩阵表示形式为:

式3. 仿射变换的齐次坐标形式

仿射变换保持了图像的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。非共线的三对对应点确定一个唯一的仿射变换。

仿射变换通过一系列原子变换复合实现,具体包括:平移(Translation)、缩放(Scale)、旋转(Rotation)、翻转(Flip)和错切(Shear)。

平移操作如下式所示,其中(tx,ty)T 是平移向量。

式4. 平移变换公式

缩放操作如下式所示,其中Sx ,Sy 是缩放系数:

式5. 缩放操作变换公式

旋转操作公式如下式所示,其中 θ是旋转角度:

式6. 旋转操作变换公式

翻转操作将图像上下左右颠倒,如下式所示:

式7. 翻转操作变换公式

错切操作如下式所示,包含水平错切和垂直错切,常用于产生弹性物体的变形处理:

式8. 错切变换公式

基本的原子变换可以级联进行,连续多个变换可借助于矩阵的相乘最后用一个单独的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);}

程序运行结果如下列图像所示:

原图像

第1种仿射变换结果

第2种仿射变换结果

第3种仿射变换结果

标签: #写出二维图形几何变换矩阵的一般表示式