2. 亚像素角点精确定位
任务说明
在相机标定中,棋盘格角点的定位精度直接影响标定结果的准确性。本案例使用OpenCV的cornerSubPix()函数,对findChessboardCorners()检测到的整数像素角点进行亚像素级精确定位,并可视化定位结果。
实现方案
核心流程为:读取棋盘格图像 → 转换为灰度图 → 使用findChessboardCorners()获取初始角点 → 使用cornerSubPix()迭代优化至亚像素精度 → 绘制并显示结果。亚像素定位基于角点邻域内灰度梯度的正交性约束,通过迭代最小化误差实现。
完整代码
import cv2
import numpy as np
# 棋盘格内角点数量(列数-1, 行数-1)
pattern_size = (9, 6)
# 读取图像并转为灰度
img = cv2.imread('chessboard.jpg')
if img is None:
raise FileNotFoundError("未找到图像文件 chessboard.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 1. 整数像素级角点检测
found, corners = cv2.findChessboardCorners(gray, pattern_size, None)
if not found:
raise RuntimeError("未能检测到棋盘格角点,请检查图像或pattern_size")
# 2. 亚像素角点精确定位
# 终止条件:最大迭代30次或误差小于0.001
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners_subpix = cv2.cornerSubPix(
gray, corners, (11, 11), (-1, -1), criteria
)
# 3. 计算偏移量并可视化
offset = corners_subpix - corners
print(f"检测到 {len(corners)} 个角点")
print(f"最大亚像素偏移: {np.max(np.abs(offset)):.4f} 像素")
# 绘制亚像素角点(红色圆点)
img_result = img.copy()
for c in corners_subpix:
x, y = c.ravel()
cv2.circle(img_result, (int(x), int(y)), 3, (0, 0, 255), -1)
# 拼接原图与结果图便于对比
vis = np.hstack([img, img_result])
cv2.imshow('Original | Subpixel Corners', vis)
cv2.waitKey(0)
cv2.destroyAllWindows()
运行与验证
依赖:OpenCV(含contrib模块)、NumPy。使用pip install opencv-contrib-python numpy安装。
运行方式:将代码保存为subpixel_corners.py,与棋盘格图像chessboard.jpg置于同一目录,执行python subpixel_corners.py。
验证方法:观察弹出的对比窗口,亚像素角点应精确落在棋盘格黑白交界的角点上,且红色圆点中心与角点几何中心重合。控制台输出的最大亚像素偏移通常为0.1~0.5像素量级(具体值取决于图像质量与初始检测精度)。若偏移量接近0,说明初始整数检测已足够精确;若偏移量过大(>1像素),需检查图像是否模糊或棋盘格是否倾斜严重。
判定标准
程序正常执行且无报错;对比窗口中红色角点与棋盘格角点精确对齐;控制台输出的最大偏移量在合理范围(0~1像素)内,即视为通过验证。若需定量评估,可保存亚像素坐标至文件,与手工标注的参考坐标对比,均方根误差小于0.1像素为优秀。