解析一下 OpenCV 中的 warp
(变换)操作,特别是与透视相关的 warpPerspective
。
在 OpenCV 的上下文中,warp
通常指的是一种图像几何变换,它根据某种数学规则将输入图像中的像素映射到输出图像中的新位置。这个过程通常涉及两个核心步骤:
- 坐标变换:为输出图像中的每个像素点,计算其在输入图像中的对应位置。
- 像素插值:由于计算出的对应位置往往是浮点数,需要通过插值算法(如最近邻、双线性等)来确定该位置的像素值。
核心函数:cv2.warpPerspective
这是实现逆透视映射 (IPM) 最直接相关的函数。
功能
对图像进行透视变换 。它可以将图像投影到一个新的视平面,非常适合实现仿射变换 无法实现的"透视效果",例如将一张图片"贴"到一个变形的四边形表面上,或者像我们讨论的,生成鸟瞰图。
工作原理
-
输入:
src
: 源图像。M
: 一个 3x3 的透视变换矩阵。这个矩阵定义了变换的规则。dsize
: 输出图像的大小(width, height)
。flags
: 插值方法(如cv2.INTER_LINEAR
最常用)。borderMode
: 处理边界像素的模式(如cv2.BORDER_CONSTANT
)。borderValue
: 如果边界模式为BORDER_CONSTANT
,用于填充边界的值(通常为黑色0
)。
-
内部过程(逆映射) :
warpPerspective
使用的是逆映射(Inverse Mapping),这是理解其行为的关键。它的工作流程是:- 对于输出图像(鸟瞰图) 上的每一个目标像素点
(x_dst, y_dst)
... - 使用变换矩阵
M
的逆矩阵M⁻¹
,计算该点在输入图像 上对应的源位置(x_src, y_src)
。
(x_src, y_src) = apply_homography(M⁻¹, (x_dst, y_dst))
- 由于
(x_src, y_src)
通常是浮点数,使用指定的插值算法(如双线性插值)从输入图像中该位置周围像素计算出一个新的像素值。 - 将这个新像素值赋给输出图像的
(x_dst, y_dst)
位置。
为什么用逆映射? 因为正向映射(从原图映射到目标图)会导致目标图上出现空洞(没有像素映射到)和重叠(多个像素映射到同一点)的问题。逆映射可以保证输出图像中的每个像素都被精确地填充。
- 对于输出图像(鸟瞰图) 上的每一个目标像素点
-
输出 :
经过透视变换后的新图像。
如何获取变换矩阵 M
?
M
矩阵是 warpPerspective
的灵魂。获取方式主要有两种:
-
cv2.getPerspectiveTransform(src_pts, dst_pts)
-
作用 :根据源图像和目标图像上的 4 组对应点 ,计算变换矩阵
M
。 -
原理:通过解线性方程组来求解单应性矩阵。它需要至少 4 个点,并且假设这些点都在同一个平面上(完美符合IPM的假设)。
-
示例 :
python# 假设在原始透视图像上选取了一个梯形的四边形区域 src_pts = np.float32([[580, 460], [700, 460], [1100, 720], [200, 720]]) # 希望它在鸟瞰图中变成一个矩形 dst_pts = np.float32([[400, 0], [900, 0], [900, 720], [400, 720]]) M = cv2.getPerspectiveTransform(src_pts, dst_pts) # 计算从 src 到 dst 的变换矩阵 bird_eye_view = cv2.warpPerspective(image, M, (image.shape[1], image.shape[0]))
-
-
cv2.findHomography(src_pts, dst_pts, method)
-
作用:功能更强大的函数,也用于计算单应性矩阵。
-
优势 :
- 可以输入多于4个的点对,求一个最优解。
- 内置了鲁棒性算法(如
cv2.RANSAC
),可以排除错误匹配点( outliers ) 的干扰。这在通过特征点匹配计算Homography时非常有用。 - 是
getPerspectiveTransform
的一个更通用、更鲁棒的版本。
-
示例 :
pythonM, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
-
其他相关的 warp
函数
-
cv2.warpAffine
- 功能 :进行仿射变换。仿射变换是透视变换的一个子集,它保持了图像的"平直性"(直线变换后还是直线)和"平行性"(平行线变换后依然平行)。
- 常见应用 :平移、旋转、缩放、剪切。它不能产生透视效果(近大远小)。
- 变换矩阵 :使用 2x3 的矩阵。
-
cv2.remap
- 功能:一种更底、更灵活的几何变换函数。
- 原理 :它直接要求你提供两个映射图
map_x
和map_y
,来指明输出图像中每个像素(x,y)
应该从输入图像的哪个位置(map_x(x,y), map_y(x,y))
取像素值。 - 应用 :常用于复杂的自定义变换,例如镜头畸变校正 。校正鱼眼相机图像时,
cv2.fisheye.undistortImage
的内部通常就是先计算好map_x
和map_y
,然后调用remap
来实现的。
总结
函数 | 核心作用 | 变换类型 | 关键输入 |
---|---|---|---|
warpPerspective |
执行透视变换,实现IPM、视角转换 | 投影变换 | 3x3 单应性矩阵 M |
getPerspectiveTransform |
计算 用于 warpPerspective 的变换矩阵 M |
- | 4组对应点 |
findHomography |
鲁棒地计算 变换矩阵 M (更强大) |
- | 多组对应点 + 方法(如RANSAC) |
warpAffine |
执行仿射变换(旋转、缩放、剪切等) | 仿射变换 | 2x3 矩阵 |
remap |
执行任意自定义的几何变换 | 任意变换 | 映射图 map_x , map_y |
简单来说,在逆透视映射的流程中:
getPerspectiveTransform
/findHomography
负责制定规则 (计算变换矩阵 M
),而 warpPerspective
负责执行规则 (根据 M
对图像进行实际的像素变换)。