仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够保持图像的平直性和平行性。平直性是指图像经过仿射变换后,直线仍然是直线:平行性是指图像在完成仿射变换后,平行线仍然是平行线。
OpencV 中的仿射函数为 cv2.warpAffine() ,其通过一个变换矩阵(映射矩阵)M 实现变换,共体为:
dst(x, y)=src( x + y + , x + y + )
如图 5-2 所示,可以通过一个变换矩阵M,将原始图像O 变换为仿射图像R
因此,可以采用仿射函数 cv2.warpAffine() 实现对图像的旋转,该函数的语法格式如下
cv2. warpAffine(src, M, dsize[, flags[, borderMode[, bordervalue]]])
式中:
1.dst 代表仿射后的输出图像,该图像的类型和原始图像的类型相同。 dsize 决定输出图像的实际大小
2.src 代表要仿射的原始图像
3.M 代表一个 2×3 的变换矩阵。使用不同的变换矩阵,就可以实现不同的仿射变换
4.dsize 代表输出图像的尺寸大小
5.flags代表插值方法,默认INTER_LINEAR 当该值为 WARP_INVERSE_MAP时,意味着M 是逆变换类型,实现从目标图像 dst 到原始图像 src的逆变换,具体可选值参见表
- borderMode代表边类型,默认为 BORDER_CONSTANT,当该值为BORDER_TRANSPARENT时,意味着目标图像内的值不做改变,这些值对应原始图像内的异常值
- borlerValue 代表边界值,默认是0
通过以上分析可知,在 openCV 中使用函数 cv2. warpAffine() 实现仿射变换,忽略其数后的语法格式为
cv2. warpAffine(src, M, dsize)
其通过转换矩阵M 将原始图像 src 转换为目标图像 dst
dst(x, y)=src( x + y + , x + y + )
因此,进行何种形式的仿射变换完全取决于转换矩阵M.下面分别介绍通过不同的转换矩阵M 实现的不同的仿射变换
5.3.1 平移
通过转换矩阵M 实现将原始图像 src 转换为目标图像 dst:
dst(x, y)=src( x + y + , x + y + )
将原始图像src 向右侧移动 100 个像素、向下方移动 200 个像素,则其对应关系为
dst(x.y)=src(x+100,y+200)
将上述表达式补充完整,即:
dst(x.y)=src(1 · x + 0 · y + 100, 0 · x + 1 · y + 200)
根据上述表达式,可以确定对应的转换矩阵M 中各个元素的值为
=1
=0
=100
=0
=1
=200
将上述值代入转换矩阵M,得到
M =
在已知转换矩阵M 的情况下,可以直接利用转换矩阵M 调用函数 cv2. warpAffine() 完成图像的平移
【例 5.5】设计程序,利用自定义转换矩阵完成图像平移
import cv2
import numpy as np
img=cv2.imread("C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp")
height,width=img.shape[:2]
x=100
y=200
M = np.float32([[1, 0, x], [0, 1, y]])
move=cv2.warpAffine(img,M,(width,height))
cv2.imshow("original",img)
cv2.imshow("move",move)
cv2.waitKey()
cv2.destroyAllWindows()
5.3.2 旋转
在使用函数 cv2.warpAffine() 对图像进行旋转时,可以通过函数 cv2.getRotationMatrix2D()获取转换矩阵。该函数的语法格式为:
retval =cv2.getRotationMatrix2D(center,angle,scale)
式中
1.center 为旋转的中心点
2.angle 为旋转角度,正数表示逆时针旋转,负数表示顺时针旋转。
3.scale为变换尺度(缩放大小)
4.利用函数 cv2.getRotationMatrix2D() 可以直接生成要使用的转换矩阵M。例如,想要以图像中心为圆点,逆时针旋转 45°,并将目标图像缩小为原始图像的 0.6倍,则在调用函数cv2.getRotationMatrix2D() 生成转换矩阵M 时所使用的语句为:
M = cv2.getRotationMatrix2D((height/2,width/2),45,0.6)
【例 5.6】设计程序,完成图像旋转
根据题目要求,设计程序如下
import cv2
img=cv2.imread("lena.bmp")
height,width=img.shape[:2]
M=cv2.getRotationMatrix2D((width/2,height/2),45,0.6)
rotate=cv2.warpAffine(img,M,(width,height))
cv2.imshow("original",img)
cv2.imshow("rotation",rotate)
cv2.waitKey()
cv2.destroyAllWindows()
5.3.3 更复杂的仿射变换
5.3.1 节和 5.3.2 节讲的两种仿射变换都比较简单,对于更复杂仿射变换, OpenCV 提供了函数
cv2.getAffineTransform() 来生成仿射函数 c2.warpAfline() 所使用的转换矩阵M。该函数的语法格式为:
retval = cv2.getAffineTransform(src, dst )
式中:
- src 代表输入图像的三个点坐标
2.dst 代表输出图像的三个点坐标
在该函数中,其参数值 src和 dst 是包含三个二维数组(x,y)点的数组,上述参数通过函数cv2.getAffineTransform()定义了两个平行四边形,sre和 dst 中的三个点分别对应平行四边形的 左上角、右上角、左下角三个点。函数c2.warpAfline() 以函数 cv2.getAffineTransform()获取的转换矩阵M 为参数,将 src 中的点仿射到dst中,函数 cv2.getAffineTransform() 对所指定的点
完成映射后,将所有其他点的映射关系按照指定点的关系计算确定
【例 5.7】 设计程序,完成图像仿射
根据题目要求,设计程序如下:
import cv2
import numpy as np
img=cv2.imread('C:\\Users\\Administrator\\Desktop\\opencv\\lena.bmp')
rows,cols,ch=img.shape
p1=np.float32([[0,0],[cols-1,0],[0,rows-1]])
p2=np.float32([[0,rows*0.33],[cols*0.85,rows*0.25],[cols*0.15,rows*0.7]])
M=cv2.getAffineTransform(p1,p2)
dst=cv2.warpAffine(img,M,(cols,rows))
cv2.imshow("origianl",img)
cv2.imshow("result",dst)
cv2.waitKey()
cv2.destroyAllWindows()
在本例中,首先构造了两个三分量的点集合 p1和 p2,分别用来指代原始图像和目标图像内平行四边形的三个顶点(左上角、右上角、左下角)然后使用 M=cv2.getAffineTransform(p1,p2) 获取转换矩降M 接下来,dst=cv2.warpAffine(img,M,(cols,rows))完成了从原始图像到目标图像的仿射
运行程序,出现如图 5-5 所示的运行结果,其中左图是原始图像,右图是仿射结果图像