在机器视觉开发中,经常会遇到目标存在倾斜、旋转或拍摄角度不一致的问题。例如标签识别、二维码识别、文档扫描、车牌识别等,如果直接进行后续处理,往往会影响算法的准确率。
透视变换(Perspective Transform) 可以将任意四边形区域映射为规则矩形,实现图像校正(Rectification),是工业视觉中非常重要的一项图像处理技术。
本文将介绍透视变换的基本原理,并结合 OpenCV 提供完整的 Python 示例代码。
一、什么是透视变换?
透视变换(Perspective Transform)又称单应性变换(Homography),它能够描述同一平面在不同视角下的映射关系。
倾斜图像 校正后
┌────────┐ ┌──────────┐
/ /| │ │
/ / | ---> │ │
└──────────┘ | │ │
\ \ | │ │
\ \| └──────────┘
经过透视变换后:
- 倾斜标签恢复水平
- 文档恢复矩形
- 方便 OCR 识别
- 提高测量精度
二、透视变换原理
二维平面的透视变换可表示为:
x′y′w=Hxy1 \begin{bmatrix} x' \\ y' \\ w \end{bmatrix} = H \begin{bmatrix} x \\ y \\ 1 \end{bmatrix} x′y′w =H xy1
其中:
- (x,y)(x,y)(x,y):原图坐标
- (x′,y′)(x',y')(x′,y′):变换后的坐标
- HHH:3×3 单应性矩阵(Homography Matrix)
最终坐标需要进行归一化:
X=x′w,Y=y′w X = \frac{x'}{w}, \quad Y = \frac{y'}{w} X=wx′,Y=wy′
OpenCV 会自动完成这些计算,我们只需要提供四个对应点即可。
三、OpenCV 实现流程
透视变换通常分为两步:
- 四个对应点
cv2.getPerspectiveTransform()→ 得到变换矩阵 Mcv2.warpPerspective()→ 得到校正后的图像
四、getPerspectiveTransform()
OpenCV 提供:
python
M = cv2.getPerspectiveTransform(src, dst)
其中:
src:原图四个角点dst:目标图四个角点
例如:
python
src = np.float32([
[120,80],
[450,60],
[480,320],
[90,350]
])
dst = np.float32([
[0,0],
[400,0],
[400,300],
[0,300]
])
M = cv2.getPerspectiveTransform(src, dst)
此时得到变换矩阵 M(3×3 Matrix)。
五、warpPerspective()
获得矩阵之后即可进行透视校正:
python
result = cv2.warpPerspective(img, M, (400, 300))
参数说明:
| 参数 | 说明 |
|---|---|
img |
输入图像 |
M |
透视变换矩阵 |
(400, 300) |
输出图像尺寸 |
返回值就是校正后的图像。
六、完整示例
python
import cv2
import numpy as np
# 读取图片
img = cv2.imread("label.jpg")
# 原图四个顶点
src = np.float32([
[120,80],
[450,60],
[480,320],
[90,350]
])
# 目标矩形
dst = np.float32([
[0,0],
[400,0],
[400,300],
[0,300]
])
# 计算透视矩阵
M = cv2.getPerspectiveTransform(src, dst)
# 执行透视变换
result = cv2.warpPerspective(
img,
M,
(400,300)
)
cv2.imshow("Original", img)
cv2.imshow("Perspective", result)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行后即可得到校正后的矩形图像。
七、自动获取四个顶点
实际项目中,四个角点通常不是手动输入,而是通过轮廓检测获得。
例如:
python
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
mask = cv2.inRange(gray, 120, 255)
contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnt = max(contours, key=cv2.contourArea)
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.float32(box)
此时 box 就是四个角点坐标,可以直接作为透视变换输入。这也是工业视觉最常见的方法。
八、角点排序
由于 cv2.boxPoints() 返回的四个点顺序可能不同,因此通常需要重新排序。
常见顺序为:
左上 ---- 右上
| |
| |
左下 ---- 右下
排序后才能保证透视结果不会发生镜像或旋转。
示例代码:
python
def order_points(pts):
pts = np.array(pts)
s = pts.sum(axis=1)
diff = np.diff(pts, axis=1)
rect = np.zeros((4, 2), dtype=np.float32)
rect = pts[np.argmin(s)] # 左上
rect = pts[np.argmax(s)] # 右下
rect = pts[np.argmin(diff)] # 右上
rect = pts[np.argmax(diff)] # 左下
return rect
这是 OpenCV 项目中常用的排序方式。
九、工业视觉中的应用
透视变换广泛应用于:
- 标签识别
- OCR 文字识别
- 条码识别
- 二维码识别
- 文档扫描
- PCB 定位
- 产品尺寸测量
- AOI 自动光学检测
- 工件姿态校正
例如在标签检测中,通常先通过轮廓找到标签区域,再利用透视变换将倾斜标签拉正,最后送入 OCR 引擎识别,可显著提升识别准确率。
十、透视变换与仿射变换的区别
| 对比项 | 仿射变换 | 透视变换 |
|---|---|---|
| 需要点数 | 3 个点 | 4 个点 |
| 保持平行线 | 保持 | 不保持 |
| 是否可处理透视畸变 | 不可以 | 可以 |
| 变换矩阵 | 2×3 | 3×3 |
| 常见函数 | cv2.warpAffine() |
cv2.warpPerspective() |
简单来说,仿射变换适用于旋转、平移、缩放等线性变换,而透视变换能够处理拍摄角度带来的透视畸变,因此适用范围更广。
十一、总结
透视变换是 OpenCV 中处理图像几何畸变的重要工具,通过四个对应点建立映射关系,可以将倾斜或变形的目标恢复为规则矩形。在工业视觉中,它常与阈值分割、轮廓检测、最小外接矩形等算法配合使用,实现标签校正、OCR 识别、二维码识别以及高精度尺寸测量等功能。
熟练掌握 cv2.getPerspectiveTransform() 与 cv2.warpPerspective() 的使用方法,是进行图像校正和机器视觉开发的重要基础。