快捷搜索:  汽车  科技

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换平移操作如下式所示,其中(tx ty)T 是平移向量。仿射变换通过一系列原子变换复合实现,具体包括:平移(Translation)、缩放(Scale)、旋转(Rotation)、翻转(Flip)和错切(Shear)。对应的齐次坐标矩阵表示形式为:式3. 仿射变换的齐次坐标形式仿射变换保持了图像的“平直性”(直线经仿射变换后依然为直线)和“平行性”(直线之间的相对位置关系保持不变,平行线经仿射变换后依然为平行线,且直线上点的位置顺序不会发生变化)。非共线的三对对应点确定一个唯一的仿射变换。

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(1)

式1. 仿射变换基本公式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(2)

式2: 仿射变换矩阵形式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(3)

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

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

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

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(4)

式4. 平移变换公式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(5)

式5. 缩放操作变换公式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(6)

式6. 旋转操作变换公式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(7)

式7. 翻转操作变换公式

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(8)

式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); }

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

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(9)

原图像

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(10)

第1种仿射变换结果

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(11)

第2种仿射变换结果

opencv图像的采样和量化过程,OpenCV对数字图像进行仿射变换(12)

第3种仿射变换结果

猜您喜欢: