本书京东优惠购书链接:https://item.jd.com/14098452.html
本书CSDN独家连载专栏:https://blog.csdn.net/youcans/category_12418787.html
几何变换分为等距变换、相似变换、仿射变换和投影变换,是指对图像的位置、大小、形状和投影进行变换,将图像从原始平面投影到新的视平面。OpenCV图像的几何变换,本质上是将一个多维数组通过映射关系转换为另一个多维数组。
本章内容概要
透视变换(Perspective Transformation)是OpenCV中常用的投影变换,是指将图像投影到一个新的视平面。投影变换的特点是原始图像中的平行关系和比例关系都可以改变,但图像中的直线在投影变换后仍然能保持直线。
投影变换可以通过对三维空间中的物体旋转进行校正,主要用于图像拼接和校正透视投影导致的图像失真。
投影变换的方法是在原始图像上确定不共线的4个点,给定这4个点在变换图像中的位置,就确定了一个投影变换,其变换关系可以由如下的3×3矩阵来描述。
[ x ~ y ~ z ~ ] = M P [ x y z ] , M P = [ M 11 M 12 M 13 M 21 M 22 M 23 M 31 M 32 M 33 ] \begin{bmatrix} \tilde{x}\\ \tilde{y}\\ \tilde{z} \end{bmatrix} = M_P \begin{bmatrix} x\\ y\\ z \end{bmatrix} ,\hspace{1em} M_P= \begin{bmatrix} M_{11} &M_{12} &M_{13}\\ M_{21} &M_{22} &M_{23}\\ M_{31} &M_{32} &M_{33} \end{bmatrix} x~y~z~ =MP xyz ,MP= M11M21M31M12M22M32M13M23M33
仿射变换是在二维平面进行变换的,而投影变换是在三维坐标系进行变换的。仿射变换是3点变换,投影变换是4点变换。比较仿射变换与投影变换的描述公式,仿射变换可以被视为z轴不变的透视变换。
在OpenCV中,先由函数cv.getPerspectiveTransform计算投影变换矩阵 M P M_P MP,再由函数cv.warpPerspective根据投影变换矩阵 M P M_P MP 计算得到投影变换图像。
函数cv.getPerspectiveTransform能根据图像中不共线的4个点在变换前后的对应位置坐标,求解得到投影变换矩阵 M P M_P MP。
函数原型
cv.getPerspectiveTransform(src, dst[,solveMethod]) → MP
参数说明
注意问题
函数cv.warpPerspective可通过投影变换矩阵计算投影变换图像。
函数原型
cv.warpPerspective (src, M, dsize[, dst, flags, borderMode, borderValue]) → dst
由投影变换矩阵M计算投影变换图像的公式为
参数说明
注意问题
手机或相机拍摄的照片,通常都存在投影变形。本例程通过投影变换实现图像校正。
先用鼠标在图像中依次选取矩形的4个顶点,获取4个顶点的坐标,再根据长宽比计算4个顶点在投影变换后的坐标,进行投影变换,就可以实现图像校正。
# 【0606】基于投影变换实现图像校正
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
def onMouseAction(event, x, y, flags, param): # 鼠标交互 (单击选点,右击完成)
setpoint = (x, y)
if event == cv.EVENT_LBUTTONDOWN: # 单击
pts.append(setpoint) # 选中一个多边形顶点
print("选择顶点 {}:{}".format(len(pts), setpoint))
if __name__ == '__main__':
img = cv.imread("../images/Fig0602.png") # 读取彩色图像(BGR)
imgCopy = img.copy()
height, width = img.shape[:2]
# 鼠标交互从输入图像选择 4 个顶点
print("单击左键选择 4 个顶点 (左上-左下-右下-右上):")
pts = [] # 初始化 ROI 顶点坐标集合
status = True # 进入绘图状态
cv.namedWindow('origin') # 创建图像显示窗口
cv.setMouseCallback('origin', onMouseAction, status) # 绑定回调函数
while True:
if len(pts) > 0:
cv.circle(imgCopy, pts[-1], 5, (0,0,255), -1) # 绘制最近的一个顶点
if len(pts) > 1:
cv.line(imgCopy, pts[-1], pts[-2], (255, 0, 0), 2) # 绘制最近的一段线段
if len(pts) == 4: # 已有 4个顶点,结束绘制
cv.line(imgCopy, pts[0], pts[-1], (255,0,0), 2) # 绘制最后的一段线段
cv.imshow('origin', imgCopy)
cv.waitKey(1000)
break
cv.imshow('origin', imgCopy)
cv.waitKey(100)
cv.destroyAllWindows() # 释放图像窗口
ptsSrc = np.array(pts) # 列表转换为 (4,2),Numpy 数组
print(ptsSrc)
# 计算投影变换矩阵 MP
ptsSrc = np.float32(pts) # 列表转换为Numpy数组,图像4个顶点坐标为 (x,y)
x1, y1, x2, y2 = int(0.1*width), int(0.1*height), int(0.9*width), int(0.9*height)
ptsDst = np.float32([[x1,y1], [x1,y2], [x2,y2], [x2,y1]]) # 投影变换后的 4 个顶点坐标
MP = cv.getPerspectiveTransform(ptsSrc, ptsDst)
# 投影变换
dsize = (450, 400) # 输出图像尺寸为 (w, h)
perspect = cv.warpPerspective(img, MP, dsize, borderValue=(255,255,255)) # 投影变换
print(img.shape, ptsSrc.shape, ptsDst.shape)
plt.figure(figsize=(9, 3.4))
plt.subplot(131), plt.axis('off'), plt.title("1.Original")
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(132), plt.axis('off'), plt.title("2.Selected vertex")
plt.imshow(cv.cvtColor(imgCopy, cv.COLOR_BGR2RGB))
plt.subplot(133), plt.axis('off'), plt.title("3.Perspective correction")
plt.imshow(cv.cvtColor(perspect, cv.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()
程序说明:
(1) 本例程设置了回调函数,通过鼠标交互从输入图像选择了4个顶点。鼠标交互操作的使用方法详见4.9节。
(2) 投影变换后4个顶点的坐标是用户设定的,可以根据需要修改。
(3) 基于投影变换实现图像校正的运行结果如图6-6所示,图6-6(1)所示为原始图像,图6-6(2)所示为用鼠标在原始图像上选定棋盘的4个顶点,图6-6(3)所示为投影变换后的图像。可以看出,原始图像中透视拍照的倾斜棋盘被校正为矩形。
*图6-6 图像的投影变换
版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/134487182)
Copyright 2023 youcans, XUPT
Crated:2023-11-20
欢迎关注本书CSDN独家连载专栏
《数字图像处理-OpenCV/Python》连载: https://blog.csdn.net/youcans/category_12418787.html