B03 - 图像处理 - 几何变换
图像的几何变换,主要理解仿射变换的原理及仿射变换矩阵的作用
什么是几何变换?
- 又称为图像空间变换,是各种图像处理算法的基础。它是在不改变图像内容的情况 下,对图像像素进行空间几何变换的处理方式。它将一幅图像中的坐标位置映射到另一幅图像中的新坐标位置,其实质是改变像素的空间位置,估算新空间位置上的像素值
- 几何变换的可以分为等距变换、相似变换、仿射变换和投影变换。在很多书籍中把等距变换、相似变换都称为仿射变换,常见的仿射变换包括平移、旋转、缩放、翻转、斜切等方法
什么是等距变换?
- 等距变换:图像中的长度、面积不变,典型的等距变换是 平移、旋转
什么是相似变换
- 相似变换:图像中的长度比、夹角、虚圆点不变,相似变换是在等距变换的基础上进行了缩放,典型的相似变换是 缩放
什么是仿射变换?
- 仿射变换:图像中的平行关系、面积比、共线线段或平行线段的长度比、矢量的线性组合不变,仿射变换是旋转和非均匀缩放的复合,典型的仿射变换是 斜切,OpenCV 使用 cv: : warpAffine 实现仿射变换
1
2
3
4
5
6img = 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
8img = 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
4img = 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
6img = 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
6img = 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
6img = 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 速度较快,效果一般,其会抑制图像信号中的高频分量(即图像边缘会变模糊)。对于要求不高的场景,可以考虑此算法,但是如果需要最大限度的保留图像中的边缘与其他特征(如角点等),且对程序的效率要求并不是很苛刻,则不建议优先使用此算法
参考:
- OpenCV 中使用 getRotationMatrix2D () 和 getAffineTransform () 进行仿射变换的区别_吾廿有四而志于学的博客 - CSDN 博客
- 【opencv 实践】仿射变换和透视变换 - 知乎
- 【OpenCV 例程 200 篇】24. 图像的仿射变换(cv2.warpAffine)_opencv cv2.warpaffine_youcans_的博客 - CSDN 博客
- OpenCV-Python – Image Pyramids (图像金子塔)_图像金子谈会有损失么_X_Imagine 的博客 - CSDN 博客
- OpenCV: Image Pyramids
- 图像金字塔的几种用途 - 知乎