OpenCV-python小玩意11 透视变换
0.什么是透视变换?
透视变换(Perspective Transformation)是计算机视觉中的一项基础技术,它能够将图像从一个视角投影到另一个视角。
用我的大白话来说:透视变换就是让图像"正"起来的技术。比如你斜着拍了一张身份证照片,通过透视变换可以让它变成正面的样子,就像身份证平放在扫描仪上拍的一样。
透视变换的数学本质是一个3x3的变换矩阵,通过这个矩阵可以实现:将倾斜拍摄的平面物体"扶正"、模拟不同视角下的拍摄效果以及消除透视畸变,获得物体的正视图等效果。
今天我们的任务就是 扶正图片:把倾斜拍摄的文档变成正面视图。
1. 用到的函数
1.1 cv2.getPerspectiveTransform
该函数用于计算透视变换矩阵。
函数原型:
cv2.getPerspectiveTransform(src, # 源图像中的四边形顶点坐标dst, # 目标图像中的对应顶点坐标solveMethod=None # 求解方法
) -> M # 返回3x3透视变换矩阵
参数说明:
- src:源图像中四边形顶点的坐标,4x2的numpy数组
- dst:目标图像中对应顶点的坐标,4x2的numpy数组
返回值:
- 3x3的透视变换矩阵
举个栗子:
import cv2
import numpy as np# 定义源点和目标点
src_points = np.float32([[56,65], [368,52], [389,390], [72,387]])
dst_points = np.float32([[0,0], [300,0], [300,300], [0,300]])# 计算变换矩阵
M = cv2.getPerspectiveTransform(src_points, dst_points)print("变换矩阵:\n", M)
1.2 cv2.warpPerspective
它是OpenCV中用于执行透视变换的核心函数,它能够将图像从一个视角投影到另一个视角。
函数原型:
dst = cv2.warpPerspective(src, # 输入图像M, # 3x3变换矩阵dsize, # 输出图像尺寸dst=None, # 输出图像(可选)flags=cv2.INTER_LINEAR, # 插值方法borderMode=cv2.BORDER_CONSTANT, # 边界处理模式borderValue=0 # 边界填充值
)
参数说明:
- src:输入图像
- M:3x3变换矩阵,通过cv2.getPerspectiveTransform计算或cv2.findHomography计算单应性矩阵
- dsize:输出图像大小 (width, height)
- flags:插值方法,默认为INTER_LINEAR
| 标志 | 说明 | 适用场景 |
|---|---|---|
| INTER_NEAREST | 最近邻插值 | 实时性要求高,质量要求低 |
| INTER_LINEAR | 双线性插值(默认) | 大多数通用场景 |
| INTER_CUBIC | 双三次插值 | 高质量放大 |
| INTER_LANCZOS4 | Lanczos插值 | 最高质量要求 |
| INTER_AREA | 区域插值 | 图像缩小 |
- borderMode:边界像素处理模式,默认为BORDER_CONSTANT
| 模式 | 说明 | 典型值 |
|---|---|---|
| BORDER_CONSTANT | 固定值填充 | 0或(0,0,0) |
| BORDER_REPLICATE | 边缘复制 | - |
| BORDER_REFLECT | 镜像反射 | - |
| BORDER_WRAP | 平铺重复 | - |
- borderValue:边界填充值,默认为0
返回值:
- 变换后的图像
举个栗子:
import cv2
import numpy as np# 读取图像
img = cv2.imread('document.jpg')
h, w = img.shape[:2]# 定义源点和目标点
src_pts = np.float32([[56,65], [368,52], [389,390], [72,387]])
dst_pts = np.float32([[0,0], [w,0], [w,h], [0,h]])# 计算变换矩阵
M = cv2.getPerspectiveTransform(src_pts, dst_pts)# 执行透视变换
result = cv2.warpPerspective(img, M, (w, h))cv2.imshow('Result', result)
cv2.waitKey(0)
2.图像矫正手动示例
2.1 准备图像
首先准备一张倾斜拍摄的图像:
import cv2
import numpy as np# 读取图像
image = cv2.imread('document.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 显示原始图像
cv2.imshow('Original', image)
cv2.waitKey(0)
2.2 手动选择角点
我们需要先找到文档的四个角点,自动检测的角点难度比较大,放到后面研究,这次我们手动选择:
# 创建一个回调函数
points = []
def click_event(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
points.append((x,y))
cv2.circle(image, (x,y), 5, (0,255,0), -1)
cv2.imshow('Image', image)# 显示图像并等待点击
cv2.imshow('Image', image)
cv2.setMouseCallback('Image', click_event)
cv2.waitKey(0)
cv2.destroyAllWindows()# 转换为numpy数组
src_points = np.float32(points[:4])

2.3 计算透视变换矩阵
现在我们有了源图像的四个角点,还需要定义目标图像的四个角点位置:
# 源图像角点
src_points = np.float32(points[:4])# 计算目标图像大小
width = max(np.linalg.norm(src_points[0]-src_points[1]),
np.linalg.norm(src_points[2]-src_points[3]))
height = max(np.linalg.norm(src_points[0]-src_points[3]),
np.linalg.norm(src_points[1]-src_points[2]))# 目标图像角点
dst_points = np.float32([[0,0], [width,0], [width,height], [0,height]])# 计算透视变换矩阵
M = cv2.getPerspectiveTransform(src_points, dst_points)
2.4 执行透视变换
有了变换矩阵,就可以进行实际变换了:
# 执行变换
warped = cv2.warpPerspective(image, M, (int(width), int(height)))# 显示结果
cv2.imshow('Warped', warped)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果图如下:

4.写在最后
今天算是对透视变换有了初步的了解,由浅入深,慢慢进步。
有了透视变换,就可以轻松地把各种倾斜拍摄的文档、标牌、图片"扶正",为后续的处理和分析打下良好基础。
后面等着我们的还有仿射变换。
