B03 - 图像处理 - 几何变换

图像的几何变换,主要理解仿射变换的原理及仿射变换矩阵的作用

什么是几何变换?

  • 又称为图像空间变换,是各种图像处理算法的基础。它是在不改变图像内容的情况 下,对图像像素进行空间几何变换的处理方式。它将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置,其实质是改变像素的空间位置,估算新空间位置上的像素值
  • 几何变换的可以分为等距变换、相似变换、仿射变换和投影变换。在很多书籍中把等距变换、相似变换都称为仿射变换,常见的仿射变换包括平移、旋转、缩放、翻转、斜切等方法

什么是等距变换?

  • 等距变换:图像中的长度、面积不变,典型的等距变换是 平移、旋转

什么是相似变换

  • 相似变换:图像中的长度比、夹角、虚圆点不变,相似变换是在等距变换的基础上进行了缩放,典型的相似变换是 缩放

什么是仿射变换?

  • 仿射变换:图像中的平行关系、面积比、共线线段或平行线段的长度比、矢量的线性组合不变,仿射变换是旋转和非均匀缩放的复合,典型的仿射变换是 斜切,OpenCV 使用 cv: : warpAffine 实现仿射变换
    1
    2
    3
    4
    5
    6
    img = cv.imread('./img/messi.jpg', 0)
    rows, cols = img.shape
    pts1 = np.float32([[50,50], [200,50], [50,200]])
    pts2 = np.float32([[10,100], [200,50], [100,250]])
    M = cv.getAffineTransform(pts1, pts2)
    dst = cv.warpAffine(img, M, (cols, rows))

什么是投影变换?

  • 投影变换:图像中的共点、共线、相交、相切、拐点的关系不变,,投影变换是在仿射变换基础上进行的非线性缩放,典型的投影变换是 透视

什么是线性变换?

  • 如果在一个向量空间中,一个变换将直线映射为直线或者原点,而原点却保持不变,那么我们就 称这个变换为线性变换。简单理解,线性变换就是变换前后坐标原点保持不变、平行线还是平行、不同直线之间的比例保持不变的变换

什么是刚体变换?

  • 平移和旋转两者的组合不改变图像的大小和形状,只有图像的位置 (平移变换) 和朝向 (旋转 变换) 发生改变,称之为欧式变换( Euclidean transformation)或刚体变换( rigid transformation),刚性变换是最一般的变换

什么是旋转变换?

  • 定义旋转矩阵,然后使用 cv.warpAffine 进行仿射变换
    1
    2
    3
    4
    5
    6
    7
    8
    img = cv.imread('pic/rabbit500x333.jpg')
    beta = np.pi/4
    #旋转矩阵
    M = np.array([
    [np.cos(beta),np.sin(beta),0],
    [-np.sin(beta),np.cos(beta),0]
    ],dtype=np.float32)
    img2 = cv.warpAffine(img,M,(633,300))

什么是平移变换?

  • 定义矩阵,然后使用 cv.warpAffine 进行仿射变换
    1
    2
    3
    4
    img = cv.imread('./img/messi.jpg', 0)
    rows, cols = img.shape
    M = np.float32([[1,0,100], [0,1,50]])
    dst = cv.warpAffine(img, M, (cols, rows))

什么是缩放变换?

  • 对图片进行缩小或放大处理,OpenCV 使用 cv: : resize 实现图片的缩放
    1
    2
    3
    4
    5
    6
    7
    #放大缩小
    #cv.resize(img,dsize,[interpolation]) dsize表示大小,[interpolation]是插值方法,可选,有默认值
    img2 = cv.resize(img,(500,400)) #放大为宽500高400
    #使用定义插值方法
    #一般来说放大地话选择LINEAR方法,缩小选择AREA方法
    img3 = cv.resize(img,(500,400),interpolation=cv.INTER_NEAREST)
    show(np.hstack([img2,img3]))

什么是错切变换?

  • 错切是保持图形上个点的某一坐标值不变,而另一坐标值关于该保持不变坐标值进行线性变换。 坐标不变的轴称为 依赖轴,其余坐标轴称为 方向轴。因此错切分为 水平错切和垂直错切
    1
    2
    3
    4
    5
    6
    img = cv.imread('pic/rabbit500x333.jpg')
    M = np.array([
    [1,0.2,0],
    [0,1,0]
    ],dtype=np.float32)
    img3 = cv.warpAffine(img,M,(533,500))

什么是镜像变换?

  • 定义矩阵,然后使用 cv.warpAffine 进行仿射变换
    1
    2
    3
    4
    5
    6
    img = cv.imread('pic/rabbit500x333.jpg')
    Mx = np.array([
    [-1,0,333],
    [0,1,0]
    ],dtype = np.float32)
    img2 = cv.warpAffine(img,Mx,(333,500))

使用 opencv 求仿射矩阵的两种方法?

  • Matcv::getAffineTransform:提供选定的三个点生成仿射矩阵
  • Matcv::getRotationMatrix2D:提供一个旋转中心点,旋转角度和尺度因子对图像进行旋转。最终得到一副旋转、缩放并且扭曲的图像

仿射变换的变换矩阵含义?

  • 仿射变换矩阵通常为以下形式:$$\left [\begin {array}{l} x \ y \ 1 \end {array}\right]=\left [\begin {array}{ccc} a_{0} & a_{1} & a_{2} \ a_{3} & a_{4} & a_{5} \ 0 & 0 & 1 \end {array}\right]\left [\begin {array}{c} x_{0} \ y_{0} \ 1 \end {array}\right]$$

什么是透视变换?

  • 透视变换又称为投影变换,透视变换是将图片投影到一个新的视平面,它是二维( x,y)到三维 (X,Y,Z)、再到另一个二维 (x’,y’) 空间的映射
  • 利用透视中心、像点、目标点三点共线的条件,将一个平面通过一个投影矩阵投影到指定平面上,如下图左图透视变换到右图
    1
    2
    3
    4
    5
    6
    img = cv.imread('./img/sudoku.png', 0)
    rows, cols = img.shape
    pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
    pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
    M = cv.getPerspectiveTransform(pts1,pts2)
    dst = cv.warpPerspective(img,M,(300,300))

仿射变换与透视变换的区别?

  • 仿射映射:可以认为是透视变换的一种特殊情况,是透视变换的子集。是从二维空间到自身的映射,是指在几何中一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间。仿射变换不会改变图片线之间的平行关系
  • 透视变换:在三维空间中视角的变化

什么是组合变换?

  • 当一个图像变换处理不能通过一次基本的仿射变换(平移、旋转、错切、缩放)完成,而是需要 多次的仿射变换才能达到变换的效果,这样的变换过程就称为复合(组合)变换
  • 旋转、错切需要以原点或坐标轴进行变换,所以进行这些变换前,需要先平移图形,以便图片以原点为参考点,做完操作后,再反平移回去

绕指定点的旋转组合变换?

  • 绕指定点旋转进行组合变换时,先将图像进行平移,确保参考点 p 坐标变 为(0,0),再进行旋转 θ,旋转后再将结果图像平移到(m,n)

绕指定直线的错切变换?

  • 以 y=m(m≠0)直线进行水平错切变换处理时,先将图像及直线进行纵 向平移,使得平移后的直线 y=m 与 x 轴重合,再以 x 轴作为方向轴 y 轴作为 依赖轴进行基本的错切变换,错切变换后再将图像平移回原位置

什么是区域插值 (Area interpolation)?

  • 使用像素区域关系进行重采样。这最适合于减小图像的大小(缩小)。当用于放大图像时,它使用该方法
  • 如果要缩小图像,通常推荐使用 INTER_AREA 插值效果最好,而要放大图像,通常使用 INTER_CUBIC (速度较慢,但效果最好),或者使用 INTER_LINEAR (速度较快,效果还可以)
  • OpenCV 使用 cv: : resize 函数可以快速对图像进行区域插值
    1
    dst = cv2.resize(image,None,fx=0.5,fy=0.5,interpolation=cv2.INTER_AREA)

什么是 Lanczos4 插值 (Lanczos4 interpolation)?

  • 在 x,y 方向分别对相邻的八个点进行插值,也就是计算加权和
    1
    dst = cv2.resize(image,None,fx=0.5,fy=0.5,interpolation=cv2.INTER_LANCZOS4)

OpenCV 的 Resize 不同插值方式的区别?

  • 如果缩小图像,INTER_AREA 插值效果最好,而且可以有效防止产生波纹现象,如果放大图像,通常使用 INTER_CUBIC 或是 INTER_LANCZOS4,此两种方法速度较慢,但效果相对较好。尽管 INTER_NEAREST 算法相当快,但使其效果大打折扣,一般很少使用
  • INTER_LINEAR 速度较快,效果一般,其会抑制图像信号中的高频分量(即图像边缘会变模糊)。对于要求不高的场景,可以考虑此算法,但是如果需要最大限度的保留图像中的边缘与其他特征(如角点等),且对程序的效率要求并不是很苛刻,则不建议优先使用此算法

参考:

  1. OpenCV 中使用 getRotationMatrix2D () 和 getAffineTransform () 进行仿射变换的区别_吾廿有四而志于学的博客 - CSDN 博客
  2. 【opencv 实践】仿射变换和透视变换 - 知乎
  3. 【OpenCV 例程 200 篇】24. 图像的仿射变换(cv2.warpAffine)_opencv cv2.warpaffine_youcans_的博客 - CSDN 博客
  4. OpenCV-Python – Image Pyramids (图像金子塔)_图像金子谈会有损失么_X_Imagine 的博客 - CSDN 博客
  5. OpenCV: Image Pyramids
  6. 图像金字塔的几种用途 - 知乎