在 OpenCV 中,坐标还原通常指将经过变换(如旋转、缩放、仿射/透视变换)后的图像中的坐标点,反向映射回原始图像中的对应位置。这在目标检测、图像配准、几何校正等场景中非常关键。
一、坐标还原的核心原理
坐标还原本质是 逆变换。若对图像应用了某种变换矩阵 ( M ),则还原坐标需使用其逆矩阵 ( M^{-1} )。
数学表示:
- 变换公式:( \text{dst}(x’, y’) = M \cdot \text{src}(x, y) )
- 逆变换公式:( \text{src}(x, y) = M^{-1} \cdot \text{dst}(x’, y’) )
二、常见场景与实现方法
1. 仿射变换的坐标还原
仿射变换(如旋转、平移、缩放)使用 2x3 矩阵,可通过计算逆矩阵还原坐标。
步骤:
- 生成逆变换矩阵:
OpenCV 提供cv2.invertAffineTransform(M)直接计算仿射矩阵的逆矩阵。 - 应用逆变换:
使用cv2.transform()或手动矩阵乘法还原坐标。
代码示例:
import cv2
import numpy as np
# 原图尺寸
h, w = 400, 600
# 定义仿射变换矩阵(旋转45度)
center = (w//2, h//2)
M = cv2.getRotationMatrix2D(center, angle=45, scale=1.0)
# 变换后的图像
rotated = cv2.warpAffine(img, M, (w, h))
# 计算逆矩阵
M_inv = cv2.invertAffineTransform(M)
# 假设变换后图像中的点 (x_dst, y_dst)
x_dst, y_dst = 100, 200
# 还原到原图坐标
src_point = np.array([[x_dst, y_dst]], dtype=np.float32)
restored_point = cv2.transform(src_point.reshape(1, -1, 2), M_inv).squeeze()
print(f"变换后坐标: ({x_dst}, {y_dst}) -> 原图坐标: {restored_point}")
2. 透视变换的坐标还原
透视变换(如投影校正)使用 3x3 矩阵,需计算逆矩阵或使用 cv2.perspectiveTransform()。
步骤:
- 生成逆矩阵:
使用np.linalg.inv(M)计算透视变换矩阵的逆矩阵 ( M^{-1} )。 - 应用逆变换:
使用cv2.perspectiveTransform()处理齐次坐标。
代码示例:
# 定义透视变换矩阵(假设已通过cv2.getPerspectiveTransform获取)
M_perspective = cv2.getPerspectiveTransform(src_pts, dst_pts)
# 变换后的图像
warped = cv2.warpPerspective(img, M_perspective, (w, h))
# 计算逆矩阵
M_perspective_inv = np.linalg.inv(M_perspective)
# 变换后图像中的点 (x_dst, y_dst)
x_dst, y_dst = 150, 300
# 齐次坐标转换
dst_point = np.array([[[x_dst, y_dst]]], dtype=np.float32)
restored_point = cv2.perspectiveTransform(dst_point, M_perspective_inv).squeeze()
print(f"变换后坐标: ({x_dst}, {y_dst}) -> 原图坐标: {restored_point}")
3. ROI(感兴趣区域)的坐标还原
若操作仅涉及图像裁剪(ROI),坐标还原只需 平移操作。
代码示例:
# 定义ROI区域 (x, y, width, height)
roi_x, roi_y, roi_w, roi_h = 100, 50, 200, 150
roi = img[roi_y:roi_y+roi_h, roi_x:roi_x+roi_w]
# 在ROI中检测到点的局部坐标 (x_local, y_local)
x_local, y_local = 30, 40
# 还原到原图全局坐标
x_global = roi_x + x_local
y_global = roi_y + y_local
print(f"ROI坐标: ({x_local}, {y_local}) -> 原图坐标: ({x_global}, {y_global})")
三、注意事项
-
矩阵可逆性:
- 仿射矩阵必须满足可逆条件(行列式不为零)。
- 透视矩阵需为满秩矩阵。
-
浮点精度误差:
还原后的坐标可能为浮点数,需根据需求决定是否取整。 -
边界处理:
若变换后坐标超出原图范围,需进行有效性检查:if (0 <= x_restored < w) and (0 <= y_restored < h): # 坐标有效 else: # 坐标越界 -
齐次坐标:
透视变换需使用齐次坐标(三维向量),还原后需归一化:restored_point_homogeneous = np.dot(M_inv, [x_dst, y_dst, 1]) x_restored = restored_point_homogeneous[0] / restored_point_homogeneous[2] y_restored = restored_point_homogeneous[1] / restored_point_homogeneous[2]
四、完整应用案例
场景:在旋转后的图像中检测目标框,还原坐标到原图。
# 旋转图像
M = cv2.getRotationMatrix2D((w//2, h//2), 30, 1.0)
rotated = cv2.warpAffine(img, M, (w, h))
# 在旋转后的图像中检测目标框 (x1, y1, x2, y2)
box_rotated = [50, 80, 200, 300]
# 还原四个顶点坐标
points_dst = np.array([
[box_rotated[0], box_rotated[1]],
[box_rotated[2], box_rotated[1]],
[box_rotated[2], box_rotated[3]],
[box_rotated[0], box_rotated[3]]
], dtype=np.float32)
M_inv = cv2.invertAffineTransform(M)
points_src = cv2.transform(points_dst.reshape(1, -1, 2), M_inv).squeeze()
# 在原图中绘制还原后的框
cv2.polylines(img, [points_src.astype(np.int32)], True, (0, 255, 0), 2)
cv2.imshow('Restored Box', img)
cv2.waitKey(0)
五、总结
| 变换类型 | 核心方法 | 关键函数 | 适用场景 |
|---|---|---|---|
| 仿射变换 | 计算逆仿射矩阵 | cv2.invertAffineTransform() | 旋转、平移、缩放 |
| 透视变换 | 计算逆透视矩阵 + 齐次坐标归一化 | cv2.perspectiveTransform() | 投影校正、视角变换 |
| ROI | 直接平移坐标 | 无 | 图像裁剪后的坐标映射 |
掌握坐标还原技术能有效提升图像处理流程的灵活性,尤其在需要跨变换空间传递信息的任务中(如目标跟踪、增强现实)。
3168

被折叠的 条评论
为什么被折叠?



