OpenCV单应性变换点坐标不匹配,如何还原350mm正方形真实尺寸?
单应性变换还原真实尺寸的校正方法
问题原因
单应性矩阵(H)是齐次变换矩阵,它存在一个任意的缩放因子——OpenCV的findHomography会对H做归一化处理,导致变换后的坐标尺度和真实世界尺寸不匹配,这就是你能拉直正方形但尺寸出现偏差的核心原因。
解决步骤
要还原真实尺寸,需要用已知的真实边长对H矩阵做尺度校正:
- 计算带尺度偏差的变换坐标:将图像角点转为齐次坐标,用原始H矩阵计算变换结果后,再转换为非齐次坐标。
- 推导缩放因子:用真实世界的标准边长(350mm)除以变换后对应边的长度,得到尺度校正系数。
- 校正H矩阵:将原始H矩阵整体乘以缩放因子,得到能还原真实尺寸的新H矩阵。
具体代码实现
import numpy as np import cv2 n_corners_px = np.array([[88, 102], [1808, 214], [1834, 1872], [109, 1986]], dtype=np.float32) n_corners_mm = np.array([[0, 350], [350, 350], [350, 0], [0, 0]], dtype=np.float32) # 计算原始单应性矩阵 H, _ = cv2.findHomography(n_corners_px, n_corners_mm) # 定义齐次坐标转真实坐标的工具函数 def transform_point(H, pt): hom_pt = np.append(pt, 1) transformed = np.dot(H, hom_pt) return transformed[:2] / transformed[2] # 计算所有角点变换后的带偏差坐标 transformed_corners = np.array([transform_point(H, pt) for pt in n_corners_px]) # 计算缩放因子:真实边长 / 变换后边长 real_edge_length = np.linalg.norm(n_corners_mm[1] - n_corners_mm[0]) transformed_edge_length = np.linalg.norm(transformed_corners[1] - transformed_corners[0]) scale_factor = real_edge_length / transformed_edge_length # 校正H矩阵 H_scaled = H * scale_factor # 验证校正效果 print("校正后[350,350]角点的变换结果:") print(transform_point(H_scaled, n_corners_px[1])) print("是否匹配真实坐标:", np.isclose(transform_point(H_scaled, n_corners_px[1]), n_corners_mm[1]).all()) # 用校正后的H做透视变换,得到真实尺寸的图像(1像素对应1mm) target_size = (350, 350) # 注意:original_img需替换为你的输入图像变量 warped_img = cv2.warpPerspective(original_img, H_scaled, target_size)
额外说明
- 计算边长时优先选正方形的完整边,避免用对角线(减少误差);
- 校正后的H矩阵可直接用于图像任意点的真实坐标转换,点击图像点后调用
transform_point(H_scaled, click_pt)即可得到对应mm坐标。
内容的提问来源于stack exchange,提问作者keuj6
相关产品推荐
相关产品推荐

