图像几何变换是指对图像进行缩放、平移、旋转、仿射变换、偏移变换等。首先明确一点,图像是以矩阵存储的,所以对图像的操作即是对矩阵的操作,对图像的平移、旋转、变换等就是对矩阵的平移、旋转、变换。
我们知道在线性代数中,要使得矩阵X变换到矩阵Y,需要一个变换矩阵设为M,偏移量设为B,可以用公式表示: Y = M ⋅ X T + B Y=M·X^T+B Y=M⋅XT+B
一下为常用的变换矩阵M(有可能和其他地方给出的矩阵不太一样,这取决于是 M ⋅ X T M·X^T M⋅XT还是 X T ∗ M X^T*M XT∗M):
当图像放大时,会有更多的屏幕点来表示图像,产生的新的点的像素值怎么办?就需要图像内插的方法
图像内插:用已知数据来估计未知位置的数值的处理。放大、收缩、旋转和几何校正等任务。基本的三种内插方法(放大图像像素增加)
来看openCV关于图像缩放的函数
插值方法 | 插值方法 |
---|---|
cv2.INTER_NEAREST | 最近邻插值 |
cv2.INTER_LINEAR | 双线性插值(默认) |
cv2.INTER_CUBIC | 双线性插值 |
cv2.INTER_AREA | 使用像素区域关系重新采样(推荐) |
import cv2
img=cv2.imread("color.jpg")
# 长*0.7,宽*0.7
img_small=cv2.resize(img,None,fx=0.7,fy=0.7,interpolation=cv2.INTER_AREA)
# 直接缩放到(256,256)
img_256=cv2.resize(img,(256,256),interpolation=cv2.INTER_AREA)
cv2.imshow("img",img)
cv2.imshow("img_small",img_small)
cv2.imshow("img_256",img_256)
cv2.waitKey(0)
如果沿(x,y)方向移动,移动的距离是 ( t x , t y ) (t_x,t_y) (tx,ty),则变换矩阵为:
M = [ 1 0 t x 0 1 t y ] M=\left[ \begin{matrix} 1 & 0 & t_x\\0 & 1 & t_y\end{matrix} \right] M=[1001txty]
我们只需要将img矩阵和M矩阵做运算即可,在这里我们使用:
如何定义矩阵M?使用numpy:
M = np.array([[1, 0, 100], [0, 1, 100]],dtype=np.float32)
import cv2
import numpy as np
img = cv2.imread("color.jpg")
size=img.shape[0:2] # 获取 图像的宽高
# 定义t_x=100 t_y=100的变换矩阵
M = np.array([[1, 0, 100], [0, 1, 100]],dtype=np.float32)
# 传入img和变换矩阵,定义输出图像的尺寸为size(size就是上面定义的原图大小)
res = cv2.warpAffine(img, M, size)
cv2.imshow("",res)
cv2.waitKey(0)
如果旋转角度为θ,则变换矩阵应该为:
M = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 ] M=\left[ \begin{matrix} cosθ & -sinθ & 0\\sinθ & cosθ & 0\end{matrix} \right] M=[cosθsinθ−sinθcosθ00]
import cv2
import numpy as np
img = cv2.imread("color.jpg")
size=img.shape[0:2]
# np.pi:兀
theta=np.pi/3 # 60°
sin=np.sin(theta)
cos=np.cos(theta)
M = np.array([[cos, -sin,0], [sin, cos,0]],dtype=np.float32)
print(M)
res = cv2.warpAffine(img, M, size)
cv2.imshow("img",img)
cv2.imshow("res",res)
cv2.waitKey(0)
import cv2
import numpy as np
img = cv2.imread("color.jpg")
rows,cols=img.shape[0:2]
# 定义一个以图像中心为旋转点,旋转45°,缩放0.6倍的变换矩阵M
M=cv2.getRotationMatrix2D((rows/2,cols/2),45,0.6)
res = cv2.warpAffine(img, M,(rows,cols))
cv2.imshow("img",img)
cv2.imshow("res",res)
cv2.waitKey(0)
什么是仿射变换?仿射变换后的图像中,原来是平行的两条线现在任然是平行的。
由于透视效果,原本两队边应该平行,但拍摄出来不平行,所以仿射矫正后两队边依然不平行,但是已经有比较好的效果了(如果要做到极致当然需要其他方法)
现在假设我们有原图A图像和标准图B图像,那么如果通过仿射变换将A图转换为B图?
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("QR.JPG") # 二维码原图像
rows, cols = img.shape[0:2] # 获取图像宽高
# 分别代表原图中三个位置探测图像的坐标
pts1 = np.float32([[132, 378], [83, 195], [256, 92]])
# 分别代表标准二维码中三个位置探测图像的坐标
pts2 = np.float32([[34, 395], [34, 34], [395, 34]])
M = cv2.getAffineTransform(pts1, pts2) #计算原图到标准图的变换矩阵M
# 根据矩阵M将img转变到标准图像(但由于透视效果,原本两队边应该平行,但拍摄
# 出来不平行,所以仿射矫正后两队边依然不平行,但是已经有比较好的效果了)
res = cv2.warpAffine(img, M, (rows*2, cols*2))
plt.rcParams['font.sans-serif']=['SimHei']
plt.subplot(121),plt.imshow(img),plt.title('原图像')
plt.subplot(122),plt.imshow(res),plt.title('结果图')
plt.show()
未完待续