4. 镜头畸变校正与图像去畸变

镜头畸变校正与图像去畸变 学习卡片

畸变模型与校正流程

工业镜头在近距离、大视场或低成本场景下,图像边缘常出现“直线变弯”的桶形或枕形畸变。相机标定的核心任务之一,就是求解径向畸变系数 k1、k2、k3 与切向畸变系数 p1、p2,并用它们把畸变图像映射回理想针孔成像模型。

去畸变分两步:先由畸变系数计算每个像素在理想图像中的对应位置,再通过双线性插值把灰度搬过去。OpenCV 的 calibrateCamera 会同时输出内参矩阵和畸变向量,undistort 或 initUndistortRectifyMap + remap 完成映射。

镜头畸变校正:从棋盘格标定到去畸变映射 ① 棋盘格采集 9×6 角点,多姿态 ≥15 张 ② 角点检测与标定 findChessboardCorners cornerSubPix 亚像素 calibrateCamera 输出:K, distCoeffs 重投影误差 RMS ③ 畸变系数 径向:k1, k2, k3 切向:p1, p2 x_d = x(1+k1r²+k2r⁴+k3r⁶) + 2p1xy + p2(r²+2x²) y_d 同理 ④ 去畸变映射 initUndistort RectifyMap remap 双线性 mapx / mapy 输出校正图 畸变类型与校正效果对比 桶形畸变 (k1 < 0) 边缘向外膨胀,直线外凸 枕形畸变 (k1 > 0) 边缘向内收缩,直线内凹 校正后 (理想针孔) 直线恢复笔直,网格均匀 评估指标: 重投影误差 RMS (px) 校正后直线度偏差 边缘像素位移量 标定板角点残差

标定与去畸变实现

下面代码完成从棋盘格图像到去畸变输出的完整链路。棋盘格规格为 9×6 内角点,方格边长 25 mm,采集 15 张不同姿态图像。

import cv2
import numpy as np
import glob

# 棋盘格参数
PATTERN = (9, 6)          # 内角点数 (列, 行)
SQUARE_MM = 25.0          # 方格边长 mm
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)

# 生成棋盘格世界坐标 (Z=0)
objp = np.zeros((PATTERN[0]*PATTERN[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:PATTERN[0], 0:PATTERN[1]].T.reshape(-1, 2) * SQUARE_MM

objpoints, imgpoints = [], []
images = sorted(glob.glob("calib_*.png"))
gray_shape = None

for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray_shape = gray.shape[::-1]
    ret, corners = cv2.findChessboardCorners(gray, PATTERN, None)
    if ret:
        corners = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)
        objpoints.append(objp)
        imgpoints.append(corners)

# 标定:求解 K 与畸变系数
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(
    objpoints, imgpoints, gray_shape, None, None)

print("RMS 重投影误差:", ret)
print("内参矩阵 K:\n", K)
print("畸变系数 [k1,k2,p1,p2,k3]:\n", dist.ravel())

# 去畸变:预计算映射表 + remap
newK, roi = cv2.getOptimalNewCameraMatrix(K, dist, gray_shape, alpha=1)
mapx, mapy = cv2.initUndistortRectifyMap(
    K, dist, None, newK, gray_shape, cv2.CV_32FC1)

test = cv2.imread("test_part.png")
undist = cv2.remap(test, mapx, mapy, cv2.INTER_LINEAR)
cv2.imwrite("undistorted.png", undist)

校正效果评估

标定完成后不能只看 RMS 数值,还要用实际检测图像验证。推荐三项检查:

  • 直线度检查:在去畸变图上取一条原本应为直线的边缘(如工件轮廓),用最小二乘拟合直线,计算最大偏差像素数。工业场景一般要求 < 0.5 px。
  • 角点残差:把标定板图像去畸变后重新检测角点,与理想网格位置比较,残差应接近标定 RMS。
  • 边缘位移量:对比去畸变前后图像四角像素的位移,位移过大说明畸变严重或 alpha 参数选择不当。
若 RMS 偏大(> 0.5 px),优先检查:棋盘格是否平整、角点检测是否准确、图像数量与姿态是否足够覆盖视场边缘。切向畸变 p1、p2 通常很小,若数值异常大,往往是标定板姿态过于单一导致。
去畸变会改变像素当量。若后续要做尺寸测量,必须使用去畸变后的内参矩阵 newK 重新计算像素当量,不能沿用原始 K 对应的比例关系。