当前位置:   article > 正文

OpenCV 透视变换

opencv 透视变换


1. 简介

汽车的360度全景影像,从拍照视角变成鸟瞰图

在这里插入图片描述
这种变换常常用到透视变换
在了解透视变换前,需要了解一下其他的变换,包括 平移,旋转,放缩,错切,以及仿射变换


2. 仿射变换


2.1. 平移

对每一个像素点坐标平移
可以让每一个像素点的 x , y x, y x,y 坐标都加一个变量 T T T

矩阵形式表示:
[ 1 0 T x 0 1 T y 0 0 1 ] [ X Y 1 ] = [ X + T x Y + T y 1 ] \left[ 10Tx01Ty001

\right] \left[ XY1
\right] = \left[X+TxY+Ty1
\right] 100010TxTy1XY1=X+TxY+Ty1

等式左边 [ X , Y , 1 ] [X,Y,1] [X,Y,1]是像素坐标的齐次形式
等式右边是平移之后的坐标


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 平移变量
T_x, T_y = 10, 20 

# 构造移动矩阵H 2*3
H = np.float32([[1, 0, T_x],
                [0, 1, T_y]])

# 平移变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Translate img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2.2. 旋转

对每一个像素点坐标旋转
假设初始旋转角度为 ϕ \phi ϕ,可以用 ( 1 , 0 ) (1, 0) (1,0) ( 0 , 1 ) (0, 1) (0,1)基向量旋转理解
在这里插入图片描述

矩阵形式表示:
[ c o s ϕ − s i n ϕ 0 s i n ϕ c o s ϕ 0 0 0 1 ] [ X Y 1 ] = [ c o s ϕ X − s i n ϕ Y s i n ϕ X + c o s ϕ Y 1 ] \left[ cosϕsinϕ0sinϕcosϕ0001

\right] \left[ XY1
\right] = \left[ cosϕXsinϕYsinϕX+cosϕY1
\right] cosϕsinϕ0sinϕcosϕ0001XY1=cosϕXsinϕYsinϕX+cosϕY1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 旋转变量 30°
sin_phi, cos_phi = 0.5, 0.866

# 构造旋转矩阵H 2*3
H = np.float32([[cos_phi, -sin_phi, 0],
                [sin_phi, cos_phi, 0]])

# 平移变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Rotate img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2.3. 放缩

进行放缩,就是将矩形(图像)放缩n倍,也就是长宽各乘一个变量

矩阵形式表示:
[ N x 0 0 0 N y 0 0 0 1 ] [ X Y 1 ] = [ N x X N y Y 1 ] \left[ Nx000Ny0001

\right] \left[ XY1
\right] = \left[NxXNyY1
\right] Nx000Ny0001XY1=NxXNyY1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 缩放变量
N_x, N_y = 0.9, 0.8

# 构造缩放矩阵H 2*3
H = np.float32([[N_x, 0, 0],
                [0, N_y, 0]])

# 缩放变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2.4. 错切

错切是在某方向上,按照一定的比例对图形的每个点到某条平行于该方向的直线的有向距离做放缩得到的平面图形

在这里插入图片描述
X轴上的错切:
[ 1 t a n θ 0 0 1 0 0 0 1 ] [ X Y 1 ] = [ X + t a n θ Y Y 1 ] \left[ 1tanθ0010001

\right] \left[ XY1
\right] = \left[X+tanθYY1
\right] 100tanθ10001XY1=X+tanθYY1
Y轴上的错切:
[ 1 0 0 t a n φ 1 0 0 0 1 ] [ X Y 1 ] = [ X Y + t a n φ X 1 ] \left[ 100tanφ10001
\right] \left[ XY1
\right] = \left[XY+tanφX1
\right]
1tanφ0010001XY1=XY+tanφX1

整合起来即:
[ 1 t a n θ 0 t a n φ 1 0 0 0 1 ] [ X Y 1 ] = [ X + t a n θ Y Y + t a n φ X 1 ] \left[ 1tanθ0tanφ10001
\right] \left[ XY1
\right] = \left[X+tanθYY+tanφX1
\right]
1tanφ0tanθ10001XY1=X+tanθYY+tanφX1


在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 错切变量 10° 20°
tan_theta, tan_varphi = 0.176, 0.364

# 构造错切矩阵H 2*3
H = np.float32([[1, tan_theta, 0],
                [tan_varphi, 1, 0]])

# 错切变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

2.5. 仿射变换

在这里插入图片描述
[ a 0 a 1 b 0 a 2 a 3 b 1 0 0 1 ] [ X Y 1 ] = [ X t Y t 1 ] \left[ a0a1b0a2a3b1001

\right] \left[ XY1
\right] = \left[XtYt1
\right] a0a20a1a30b0b11XY1=XtYt1

仿射变换矩阵,是由原图像平移,旋转,放缩,错切之后得来的,即

如果用2*2的矩阵和2D坐标表示,无法将平移和其他操作一起运算,那么需要“升维”
引入“齐次坐标”,将图像从平面2D坐标变成3D坐标
把缩放,旋转,平移等变换都统一起来,都表示成一连串的矩阵相乘的形式,保证了形式上的线性一致性
目的主要是合并矩阵运算中的乘法和加法

[ 1 t a n θ 0 t a n φ 1 0 0 0 1 ] [ N x 0 0 0 N y 0 0 0 1 ] [ c o s ϕ − s i n ϕ 0 s i n ϕ c o s ϕ 0 0 0 1 ] [ 1 0 T x 0 1 T y 0 0 1 ] = [ a 0 a 1 b 0 a 2 a 3 b 1 0 0 1 ] \left[ 1tanθ0tanφ10001

\right] \left[ Nx000Ny0001
\right] \left[ cosϕsinϕ0sinϕcosϕ0001
\right] \left[ 10Tx01Ty001
\right] = \left[ a0a1b0a2a3b1001
\right] 1tanφ0tanθ10001Nx000Ny0001cosϕsinϕ0sinϕcosϕ0001100010TxTy1=a0a20a1a30b0b11


将矩形变换成平行四边形(即变换后各边依旧平行)
在这里插入图片描述

上面公式里有六个变量,因此自然需要至少列六个等式才可计算出该矩阵
所以需要输入至少三对点集

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)


# 定义对应的点 原始1(书本的3个角落坐标)、变换2
pts1 = np.float32([[290, 9], [6, 348], [328, 353]])
pts2 = np.float32([[280, 0], [0, 350], [280, 350]])

# 计算得到转换矩阵 2*2
H = cv2.getAffineTransform(pts1, pts2)

# 错切变换
new_img = cv2.warpAffine(img, H, (img.shape[1], img.shape[0]))

cv2.imshow('Scale img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

3. 透视变换

在这里插入图片描述

常见的有文档矫正和汽车摄像头转成鸟瞰图,因为视角的原因,近处宽远处窄,呈不规则的四边形

在这里插入图片描述

仿射变换是单纯对图片进行平移,缩放,错切(倾斜)和旋转,而这几个操作都不会改变图片线之间的平行关系
仿射变换是在二维空间中,而透视变换则是在三维空间中视角的变化

在这里插入图片描述
T1为线性变换完成旋转,错切和放缩,T2完成平移操作,T3就是设了两个变量来表示映射关系


需要选取原图上的四个点以上的点集,并计算出该点集变换后的位置
在这里插入图片描述

from cv2 import cv2
import numpy as np


# 读取图片文件
demo_file_path = 'img.png'
img = cv2.imdecode(np.fromfile(demo_file_path, dtype=np.uint8), cv2.IMREAD_UNCHANGED)
cv2.imshow('origin img', img)

# 定义对应的点 原始1(书本的4个角落坐标)、变换2
pts1 = np.float32([[49, 14], [290, 9], [6, 348], [328, 353]])
pts2 = np.float32([[0, 0], [280, 0], [0, 350], [280, 350]])

# 计算得到转换矩阵 3*3
M = cv2.getPerspectiveTransform(pts1, pts2)

# 透视变换
new_img = cv2.warpPerspective(img, M, (280, 350))

cv2.imshow('perspective img', new_img)
cv2.waitKey(0)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

谢谢

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

闽ICP备14008679号