opencv-python(七):几何变换

0. 图像几何变换

图像几何变换是指对图像进行缩放、平移、旋转、仿射变换、偏移变换等。首先明确一点,图像是以矩阵存储的,所以对图像的操作即是对矩阵的操作,对图像的平移、旋转、变换等就是对矩阵的平移、旋转、变换。
我们知道在线性代数中,要使得矩阵X变换到矩阵Y,需要一个变换矩阵设为M,偏移量设为B,可以用公式表示: Y = M ⋅ X T + B Y=M·X^T+B Y=MXT+B
一下为常用的变换矩阵M(有可能和其他地方给出的矩阵不太一样,这取决于是 M ⋅ X T M·X^T MXT还是 X T ∗ M X^T*M XTM):opencv-python(七):几何变换_第1张图片

1. 扩展缩放

当图像放大时,会有更多的屏幕点来表示图像,产生的新的点的像素值怎么办?就需要图像内插的方法
图像内插:用已知数据来估计未知位置的数值的处理。放大、收缩、旋转和几何校正等任务。基本的三种内插方法(放大图像像素增加)

  • a. 最邻近内插法:四个近邻的像素放大后产生田字区域,每个口中的像素值取该口顶点的值,将明显产生马赛克感觉
    opencv-python(七):几何变换_第2张图片

  • b. 双线性内插:用4领域估计给定位置灰度值用
    opencv-python(七):几何变换_第3张图片

  • a. 双三次内插,8邻域opencv-python(七):几何变换_第4张图片

来看openCV关于图像缩放的函数

  • cv2.resize(img,dsize,fx,fy,interpolation):图像缩放函数
  • dsize:将图像缩放到什么尺寸,比如(500,500)即将img缩放到(500,500)
  • fx和fy:行和列的缩放比例因子,比如fx=2,fy=2即将img长宽各放大2倍
  • interpolation:插值方法,效果越好,速度越慢
插值方法 插值方法
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)

opencv-python(七):几何变换_第5张图片

2. 平移

如果沿(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矩阵做运算即可,在这里我们使用:

  • cv2.warpAffine(img1,M,dsize):对img矩阵做M矩阵变换,并设定输出图像的尺寸dsize

如何定义矩阵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)

3. 旋转

如果旋转角度为θ,则变换矩阵应该为:
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]

  • warpAffine(img,M,dsize):使用万能公式
    一下程序涉及的和三角函数计算参考:numpy系列(4)-数学函数、算数、代数运算
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)

opencv-python(七):几何变换_第6张图片
使用openCV提供的函数来定义矩阵M:

  • M=cv2.getRotationMatrix2D(center,theta,flag):定义矩阵M
  • center:旋转中心,比如(cols/2,rows/2)代表以图像中心为选择点
  • theta:旋转角度,比如60代表旋转60°
  • flag:缩放因子,比如0.6代表旋转后图像缩到0.6倍
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)

opencv-python(七):几何变换_第7张图片

4. 仿射变换

什么是仿射变换?仿射变换后的图像中,原来是平行的两条线现在任然是平行的。
opencv-python(七):几何变换_第8张图片
由于透视效果,原本两队边应该平行,但拍摄出来不平行,所以仿射矫正后两队边依然不平行,但是已经有比较好的效果了(如果要做到极致当然需要其他方法)
现在假设我们有原图A图像和标准图B图像,那么如果通过仿射变换将A图转换为B图?

  • 通过A和B的关系,求出变换矩阵M
  • 通过A和M做运算得到B
    如何求矩阵M?比如上图的二维码中,三个角的方块角位置探测图像,原图和结果图都有三个位置探测图像,那么通过原图和结果图的位置探测图像是一一对应的,也就能列举三个方程,从而解出矩阵M。当然OpenCV提供了这些方法
  • M=cv2.getAffineTransform(pts1,pts2):根据pts计算获取矩阵M
  • pts1:代表原图的三个点
  • pts2:代表结果图的三个点
  • dst=cv2.warpAffine(img,M,dsize):根据M变换img
  • img:原图
  • M:变换矩阵
  • dsize:输出图的大小
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()

5. 透视变换

未完待续

你可能感兴趣的:(opencv-python,opencv,计算机视觉,python)