理解OpenCV单应性变换最小点集应用及转换结果异常排查
你的代码存在3个核心问题:
- 齐次坐标构造错误:2D点扩展为齐次坐标时,第三个分量应为1,你设置为0会导致计算结果完全偏离预期
- 未做齐次坐标归一化:单应性矩阵是尺度无关的3x3矩阵,与齐次坐标相乘后得到的结果需要除以最后一个维度的数值,才能得到正确的2D笛卡尔坐标,直接取前两位的结果是错的
- 手动矩阵运算容易出维度匹配问题,更推荐直接调用OpenCV封装好的
cv2.perspectiveTransform方法做坐标变换
修复后可运行代码:
import cv2 import numpy as np import matplotlib.pyplot as plt points = np.array([ [675, 585], [675, 1722], [3155, 580], [3162, 1722], ], dtype=np.float32) t_points = np.array([ [0,0], [0, 8.23], [23.77, 0], [23.77, 8.23] ], dtype=np.float32) # 测试点构造 pt = np.array([675, 580+(1722-580)/2], dtype=np.float32) pt_test = np.array([0,8.23/2], dtype=np.float32) def get_h_matrix(src_list, dst_list): src_pts = src_list.reshape(-1,1,2) dst_pts = dst_list.reshape(-1,1,2) H, mask = cv2.findHomography(src_pts, dst_pts) return H H = get_h_matrix(points, t_points) # 手动矩阵运算的正确写法 pt_homogeneous = np.append(pt, 1) # 齐次坐标第三个分量设为1 transformed_h = H @ pt_homogeneous transformed = transformed_h[:2] / transformed_h[2] # 归一化得到笛卡尔坐标 # 也可以直接调用OpenCV内置方法,更简便不易出错 # transformed = cv2.perspectiveTransform(pt.reshape(-1,1,2), H)[0][0] print(f"实际变换坐标:{transformed}") print(f"理论目标坐标:{pt_test}") plt.scatter(t_points[:,0], t_points[:,1], color = 'blue') plt.scatter(transformed[0], transformed[1], color = 'orange') plt.scatter(pt_test[0], pt_test[1], color = 'green') plt.show() plt.scatter(points[:,0], points[:,1], color = 'blue') plt.scatter(pt[0],pt[1], color = 'orange') plt.show()
运行后可以看到橙色点和绿色点几乎完全重合,仅有的微小误差来自你原始标注点的少量偏移(原始points中第一点y值为585、第三点y值为580,本身不是完全水平的)。
内容的提问来源于stack exchange,提问作者not_converging
相关产品推荐
相关产品推荐

