4. 图像畸变校正
任务说明
本案例针对机械手视觉定位中相机镜头引入的图像畸变问题,使用已知的相机内参矩阵和畸变系数,对一张棋盘格标定板图像执行去畸变处理,并通过角点重投影位置对比验证校正效果。输入图像为标定阶段采集的原始畸变图像,输出为校正后的无畸变图像及定量验证结果。
实现方案
采用OpenCV标准去畸变流程:先读取原始图像,利用cv2.undistort()函数结合内参与畸变系数生成校正图像;随后在原始图像和校正图像上分别检测棋盘格角点,计算校正前后角点坐标的偏移量,以平均像素误差作为校正效果的量化指标。代码中使用的内参和畸变系数来自典型工业相机标定结果,棋盘格尺寸为9×6内角点,方格边长25mm。
代码实现
import cv2
import numpy as np
# 相机内参(来自标定结果)
K = np.array([[822.79, 0.0, 326.45],
[0.0, 823.18, 239.82],
[0.0, 0.0, 1.0]], dtype=np.float64)
# 畸变系数 (k1, k2, p1, p2, k3)
dist_coeffs = np.array([-0.2834, 0.0735, 0.0012, -0.0008, -0.0156], dtype=np.float64)
# 棋盘格参数:9列×6行内角点
pattern_size = (9, 6)
def load_image(path):
"""读取图像并转为灰度"""
img = cv2.imread(path)
if img is None:
raise FileNotFoundError(f"无法读取图像: {path}")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
return img, gray
def undistort_image(img):
"""使用内参和畸变系数校正图像"""
h, w = img.shape[:2]
new_K, roi = cv2.getOptimalNewCameraMatrix(K, dist_coeffs, (w, h), 1.0, (w, h))
undistorted = cv2.undistort(img, K, dist_coeffs, None, new_K)
# 裁剪ROI区域(去除边缘黑边)
x, y, w_roi, h_roi = roi
undistorted = undistorted[y:y+h_roi, x:x+w_roi]
return undistorted
def detect_corners(gray_img):
"""检测棋盘格角点,返回亚像素坐标"""
ret, corners = cv2.findChessboardCorners(gray_img, pattern_size, None)
if not ret:
raise RuntimeError("未能检测到棋盘格角点")
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners_sub = cv2.cornerSubPix(gray_img, corners, (11, 11), (-1, -1), criteria)
return corners_sub.reshape(-1, 2)
def compute_corner_offset(corners_orig, corners_undist):
"""计算校正前后角点坐标的欧氏距离"""
diff = corners_orig - corners_undist
distances = np.sqrt(np.sum(diff**2, axis=1))
return distances
def main():
# 1. 加载原始畸变图像
img_orig, gray_orig = load_image("calib_image.jpg")
# 2. 执行去畸变
img_undist = undistort_image(img_orig)
gray_undist = cv2.cvtColor(img_undist, cv2.COLOR_BGR2GRAY)
# 3. 检测校正前后角点
corners_orig = detect_corners(gray_orig)
corners_undist = detect_corners(gray_undist)
# 4. 计算偏移量
offsets = compute_corner_offset(corners_orig, corners_undist)
# 5. 输出统计结果
print(f"检测到角点数: {len(corners_orig)}")
print(f"平均偏移量: {np.mean(offsets):.2f} 像素")
print(f"最大偏移量: {np.max(offsets):.2f} 像素")
print(f"最小偏移量: {np.min(offsets):.2f} 像素")
# 6. 保存校正结果
cv2.imwrite("undistorted.jpg", img_undist)
print("校正图像已保存为 undistorted.jpg")
if __name__ == "__main__":
main()
运行与验证
依赖环境:Python 3.8+,OpenCV 4.x,NumPy。安装命令:pip install opencv-python numpy。
输入文件:将标定阶段采集的棋盘格图像命名为calib_image.jpg,放置于代码同目录。图像应包含完整棋盘格(9×6内角点),光照均匀、无明显遮挡。
执行方式:直接运行脚本:python undistort_demo.py。
验证方法:程序输出角点偏移量统计,并生成undistorted.jpg。判定标准:
- 校正后图像中棋盘格直线边缘无明显弯曲,格线横平竖直;
- 角点偏移量统计中,平均偏移量通常大于0.5像素(说明原始图像确实存在畸变且被校正);
- 若将校正后图像再次检测角点并与理论投影位置比较,重投影误差应小于0.5像素(本案例通过校正前后角点偏移量间接反映校正幅度)。
预期输出示例:检测到角点数: 54;平均偏移量: 3.42 像素;最大偏移量: 7.85 像素;最小偏移量: 0.23 像素。实际数值取决于输入图像的畸变程度。