当前位置:   article > 正文

opencv-python(七):几何变换_图像几何矫正 python

图像几何矫正 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):在这里插入图片描述

1. 扩展缩放

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

  • a. 最邻近内插法:四个近邻的像素放大后产生田字区域,每个口中的像素值取该口顶点的值,将明显产生马赛克感觉
    在这里插入图片描述

  • b. 双线性内插:用4领域估计给定位置灰度值用
    在这里插入图片描述

  • a. 双三次内插,8邻域在这里插入图片描述

来看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)

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

2. 平移

如果沿(x,y)方向移动,移动的距离是 ( t x , t y ) (t_x,t_y) (tx,ty),则变换矩阵为:
M = [ 1 0 t x 0 1 t y ] M=\left[

10tx01ty
\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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

3. 旋转

如果旋转角度为θ,则变换矩阵应该为:
M = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 ] M=\left[

cosθsinθ0sinθcosθ0
\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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

在这里插入图片描述
使用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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

在这里插入图片描述

4. 仿射变换

什么是仿射变换?仿射变换后的图像中,原来是平行的两条线现在任然是平行的。
在这里插入图片描述
由于透视效果,原本两队边应该平行,但拍摄出来不平行,所以仿射矫正后两队边依然不平行,但是已经有比较好的效果了(如果要做到极致当然需要其他方法)
现在假设我们有原图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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

5. 透视变换

未完待续

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/100438
推荐阅读
相关标签
  

闽ICP备14008679号