相机标定之--张正友标定法

文章目录

前言

张正友标定标定法是相机标定的经典之作,他是由张正友(微软研究院),于1998年提出的。如果想通过相机计算机坐标,以及通过相机测距,必须要对相机进行标定。

背景信息

张正友标定法,使用平面棋盘格标定,不需要精密 3D 标定物,成本极低、精度高、鲁棒好;通过张正友标定法可以求解 相机内参 K、外参 (R, t)、镜头畸变系数。

相机成像模型

张正友标定法涉及的几个坐标系如下:

世界坐标系 → 相机坐标系 → 图像坐标系 → 像素坐标系

通过相机标定后,利用标定后求出的参数我们最终求解出机器人从世界坐标系到像素坐标系的转换关系;

  • 摄像头在没有畸变的情况时(理想情况)

    世界坐标系和像素坐标系之间的关系,如下:

    以上公式中各个符号代表的意思如下:

  • u和v 表示的是像素坐标系;右侧的Xw、Yw、Zw是世界坐标系;

  • K是内参矩阵

    其中fx和fy是焦距;cx和cy是中心点(光轴与图像的焦点);在相机镜头无倾斜的情况下fx约等于fy

  • R t\] 是外参矩阵 其中R是3×3旋转矩阵;t 是3×1平移向量;

令单应性矩阵H=K [r1 r2 t]

所以以上公式变形为:

其中H为齐次矩阵。

1、标定流程

准备与拍摄

  • 标定板:棋盘格(黑白方块),已知方格物理尺寸(如 20mm×20mm)
  • 拍摄:
    • 不同角度、不同距离、不同倾斜(俯仰 / 偏航 / 滚动)
    • 覆盖全画面,边缘也要有角点
    • 数量:≥15 张(工程常用 15~25 张)
    • 要求:棋盘清晰、无模糊、角点明显

角点检测

  • 提取每张图的 棋盘角点(亚像素级)
  • 建立:世界坐标 (Xw, Yw, 0) ↔ 像素坐标 (u, v) 对应关系

线性求解内参和外参

  • 单应性矩阵 H 求解
    对每幅图,用 DLT(直接线性变换) 解 H:

2、畸变模型

实际镜头有畸变,主要分:1. 径向畸变(主导)和切向畸变

1. 径向畸变(主导)

2. 切向畸变(镜头安装误差)

3、非线性优化

目标:最小化重投影误差

4、工程要点

1、重投影误差

  • <0.5px:高精度可用
  • 0.5~1.0px:常规可用
  • 2px:重拍 / 剔除坏图

2、拍摄要点

  • 倾斜、远近、左右、上下都要有
  • 棋盘占画面 1/2~2/3
  • 不要模糊、不要过曝
  • 边缘必须拍到

3、畸变系数选择

  • 普通镜头:k1,k2,p1,p2 足够
  • 广角:加 k3

4、内参意义

  • fx, fy 一般接近相等
  • cx, cy 靠近图像中心

程序的实现

接下来通过程序实现以下以上流程:

棋盘格生成程序

python 复制代码
import cv2
import numpy as np

def generate_chessboard(pattern_size=(9,6), square_size=25, margin=20):
    w = pattern_size[0]
    h = pattern_size[1]
    img_w = w * square_size + 2 * margin
    img_h = h * square_size + 2 * margin
    img = np.ones((img_h, img_w), dtype=np.uint8) * 255

    for i in range(h):
        for j in range(w):
            if (i + j) % 2 == 0:
                x1 = margin + j * square_size
                y1 = margin + i * square_size
                x2 = x1 + square_size
                y2 = y1 + square_size
                cv2.rectangle(img, (x1, y1), (x2, y2), 0, -1)
    return img

if __name__ == "__main__":
    chess = generate_chessboard((9,6), 100)
    cv2.imwrite("chessboard.png", chess)
    cv2.imshow("chess", chess)
    cv2.waitKey(0)

以上程序生成的是6行9列的棋盘格,棋盘格生成后就可以对摄像头进行标定了;

标定程序

python 复制代码
import cv2
import numpy as np
import glob
import os

# ====================== 配置 ======================
PATTERN_SIZE = (9, 6)          # 内角点行列
SQUARE_SIZE_MM = 25.0          # 棋盘格物理尺寸 mm
IMG_DIR = "calib_imgs/*"       # 标定图路径
SHOW_CORNERS = True
SAVE_RESULT = True
# ====================================================

# 1. 准备世界坐标
objp = np.zeros((PATTERN_SIZE[0]*PATTERN_SIZE[1], 3), np.float32)
objp[:,:2] = np.mgrid[0:PATTERN_SIZE[0], 0:PATTERN_SIZE[1]].T.reshape(-1,2)
objp *= SQUARE_SIZE_MM

obj_points = []   # 3D点
img_points = []   # 2D点
img_shape = None

# 2. 读取图片并检测角点
img_paths = sorted(glob.glob(IMG_DIR))
print(f"找到 {len(img_paths)} 张标定图")

for path in img_paths:
    img = cv2.imread(path)
    if img is None: continue
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    if img_shape is None:
        img_shape = gray.shape[::-1]

    # 查找角点
    ret, corners = cv2.findChessboardCorners(gray, PATTERN_SIZE, None)
    if ret:
        # 亚像素优化
        criteria = (cv2.TERM_CRITERIA_EPS+cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
        corners_sub = cv2.cornerSubPix(gray, corners, (11,11), (-1,-1), criteria)

        obj_points.append(objp)
        img_points.append(corners_sub)

        if SHOW_CORNERS:
            cv2.drawChessboardCorners(img, PATTERN_SIZE, corners_sub, ret)
            cv2.imshow("corners", img)
            cv2.waitKey(100)

cv2.destroyAllWindows()
if len(obj_points) < 3:
    print("有效图片太少,至少3张")
    exit()

# 3. 张正友标定
print("开始标定...")
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(
    obj_points, img_points, img_shape, None, None
)

# 4. 计算平均重投影误差(核心评价指标)
total_err = 0
errors = []
for i in range(len(obj_points)):
    img_proj, _ = cv2.projectPoints(obj_points[i], rvecs[i], tvecs[i], K, dist)
    err = cv2.norm(img_points[i], img_proj, cv2.NORM_L2) / len(img_proj)
    errors.append(err)
    total_err += err
mean_err = total_err / len(obj_points)

# ====================== 输出结果 ======================
print("\n===== 相机内参 K =====")
print(K)
print("\n===== 畸变系数 dist =====")
print("k1, k2, p1, p2, k3 =")
print(dist.ravel())
print(f"\n平均重投影误差: {mean_err:.4f} 像素")
print("(<0.5 优秀,<1.0 良好,>2.0 需重拍)")

# 5. 保存结果
if SAVE_RESULT:
    np.savez("calib_result.npz", K=K, dist=dist, rvecs=rvecs, tvecs=tvecs)
    print("已保存到 calib_result.npz")

# 6. 去畸变示例
if img_paths:
    img = cv2.imread(img_paths[0])
    h, w = img.shape[:2]
    new_K, roi = cv2.getOptimalNewCameraMatrix(K, dist, (w,h), 1, (w,h))
    dst = cv2.undistort(img, K, dist, None, new_K)

    cv2.imshow("original", img)
    cv2.imshow("undistorted", dst)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

以上内容若有错误欢迎指正!

相关推荐
QYR-分析2 小时前
小型战术地面机器人(STGR)行业全景分析及市场机遇展望
人工智能·机器人
胡摩西2 小时前
室内定位技术方法汇总:从WiFi到超声波,机器人如何在室内“找准自己”?
人工智能·机器人·slam·室内定位·roomaps
PNP Robotics2 小时前
集智联机器人(PNP)亮相第三届中国具身智能大会,以“双臂+遥操作“多维方案定义具身交互新范式
大数据·人工智能·python·深度学习·机器人
song1502653729812 小时前
视觉检测设备:自动识别缺陷、尺寸、瑕疵、装配错误,一键全检
人工智能·计算机视觉·视觉检测
鲁邦通物联网13 小时前
架构实战:基于机器视觉的机器人自主乘梯状态机与人机分流设计
机器人·机器人梯控·agv梯控·非侵入式采集·机器人乘梯·机器人自主乘梯·agv机器人梯控
普密斯科技15 小时前
齿轮平面度与正反面智能检测方案:3D视觉技术破解精密制造品控难题
人工智能·计算机视觉·平面·3d·自动化·视觉检测
步步精BBJconn17 小时前
从消费电子到机器人,步步精科技如何切入连接器高端赛道
科技·机器人
MarkHD17 小时前
RPA进阶实战:集成邮件自动化与API,构建企业级智能流程机器人
机器人·自动化·rpa
天辛大师19 小时前
山东居士林:天辛大师用AI+预测城市田园农场运营调配
大数据·人工智能·随机森林·机器人·启发式算法