当前位置: 首页 > ds >正文

【图像处理基石】什么是相机的内外参数?

在这里插入图片描述

相机内参与外参的概念

1. 相机内参(Intrinsic Parameters)

相机内参是描述相机自身光学和几何特性的参数,与拍摄场景无关,主要包括:

  • 焦距(fx,fyf_x, f_yfx,fy:镜头焦距在图像平面上的投影(单位:像素),分别对应x轴和y轴方向(通常因像素非正方形可能不同)。
  • 主点(cx,cyc_x, c_ycx,cy:光轴与图像平面的交点(单位:像素),理想情况下是图像中心。
  • 畸变系数:镜头光学畸变的参数,包括:
    • 径向畸变(k1,k2,k3k_1, k_2, k_3k1,k2,k3):因镜头形状导致的畸变(边缘像素偏移更明显)。
    • 切向畸变(p1,p2p_1, p_2p1,p2):因镜头与图像平面不平行导致的畸变。

内参矩阵通常表示为:
K=[fx0cx0fycy001] K = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} K=fx000fy0cxcy1

2. 相机外参(Extrinsic Parameters)

外参描述相机在世界坐标系中的位置和姿态,用于将世界坐标系中的3D点转换到相机坐标系,包括:

  • 旋转矩阵(RRR:3×3矩阵,描述相机坐标系相对世界坐标系的旋转。
  • 平移向量(ttt:3×1向量,描述相机坐标系原点相对世界坐标系原点的平移。

外参通过变换矩阵将世界坐标系点PwP_wPw转换为相机坐标系点PcP_cPc
Pc=R⋅Pw+t P_c = R \cdot P_w + t Pc=RPw+t

相机标定方法

相机标定的核心是通过已知的3D世界点及其对应的2D图像点,求解内参和外参。最常用的是张正友标定法,步骤如下:

  1. 准备平面标定板(如棋盘格),已知格子的物理尺寸(如20mm×20mm)。
  2. 从不同角度、姿态拍摄标定板的多张图片(通常需要10-20张)。
  3. 检测每张图片中棋盘格的内角点(2D图像坐标)。
  4. 定义内角点在世界坐标系中的3D坐标(例如,令标定板平面为Z=0Z=0Z=0,左上角为原点)。
  5. 利用透视变换约束,通过非线性优化求解内参、外参和畸变系数。

Python实现相机标定

使用OpenCV库实现标定,主要步骤:读取图片→检测角点→亚像素优化→标定计算→评估误差。

代码实现
import cv2
import numpy as np
import glob# ---------------------- 配置参数 ----------------------
# 棋盘格内角点数量(行×列,不含边框)
chessboard_size = (9, 6)  # 例如:9列,6行内角点
# 棋盘格单个格子的物理尺寸(单位:mm)
square_size = 20.0# 世界坐标系中的3D点(Z=0,仅X、Y有值)
objp = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2)
objp *= square_size  # 缩放为实际物理尺寸# 存储所有图片的3D世界点和2D图像点
obj_points = []  # 世界坐标系3D点
img_points = []  # 图像坐标系2D点# ---------------------- 读取图片并检测角点 ----------------------
# 读取标定板图片(需提前准备,放在"calibration_images"文件夹)
images = glob.glob('calibration_images/*.jpg')  # 支持jpg/png等格式for fname in images:img = cv2.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图# 检测棋盘格内角点(返回角点是否找到,以及角点坐标)ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)# 如果找到角点,进行亚像素精确化if ret:obj_points.append(objp)  # 添加3D世界点# 亚像素角点优化(提高精度)criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)corners_subpix = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)img_points.append(corners_subpix)  # 添加优化后的2D图像点# 可视化角点检测结果img = cv2.drawChessboardCorners(img, chessboard_size, corners_subpix, ret)cv2.imshow('Chessboard Corners', img)cv2.waitKey(500)  # 每张图显示0.5秒cv2.destroyAllWindows()# ---------------------- 相机标定 ----------------------
# 调用OpenCV标定函数
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None
)# ---------------------- 输出标定结果 ----------------------
print("标定是否成功:", "成功" if ret else "失败")
print("\n内参矩阵 K:\n", mtx)
print("\n畸变系数(k1, k2, p1, p2, k3):\n", dist)
print("\n外参(旋转向量和平移向量):")
for i in range(len(rvecs)):print(f"第{i+1}张图:")print(f"旋转向量 rvec:\n{rvecs[i]}")print(f"平移向量 tvec:\n{tvecs[i]}\n")# ---------------------- 评估标定精度(重投影误差) ----------------------
# 重投影误差:标定后的3D点投影到图像上的位置与实际检测的2D点的偏差
mean_error = 0
for i in range(len(obj_points)):img_points2, _ = cv2.projectPoints(obj_points[i], rvecs[i], tvecs[i], mtx, dist)error = cv2.norm(img_points[i], img_points2, cv2.NORM_L2) / len(img_points2)mean_error += errorprint(f"平均重投影误差:{mean_error / len(obj_points):.6f} 像素")
print("(误差越小,标定精度越高,通常应小于0.5像素)")# ---------------------- 保存标定结果 ----------------------
np.savez('camera_calibration.npz', mtx=mtx, dist=dist, rvecs=rvecs, tvecs=tvecs)
print("\n标定结果已保存至 camera_calibration.npz")
测试用例说明
  1. 准备数据

    • 打印一张棋盘格标定板(如9×6内角点),测量单个格子的物理尺寸(如20mm)。
    • 用相机从不同角度、距离拍摄10-20张标定板图片(确保所有内角点都可见),保存到calibration_images文件夹。
  2. 运行代码

    • 安装依赖:pip install opencv-python numpy
    • 运行脚本,程序会自动检测角点并显示,最终输出内参、外参和重投影误差。
  3. 结果评估

    • 若平均重投影误差小于0.5像素,说明标定效果较好;若误差过大,需检查图片质量(如模糊、角点不全)或增加图片数量。

代码关键步骤解释

  1. 角点检测cv2.findChessboardCorners检测棋盘格内角点,返回粗略坐标。
  2. 亚像素优化cv2.cornerSubPix通过迭代提高角点坐标精度(至亚像素级别)。
  3. 标定核心cv2.calibrateCamera利用3D-2D点对应关系,求解内参(mtx)、畸变系数(dist)、外参(旋转向量rvecs、平移向量tvecs)。
  4. 精度评估:重投影误差反映标定参数的准确性,误差越小说明模型越可靠。

通过上述方法,可快速实现相机内外参的标定,为后续的立体视觉(如深度估计)、图像校正等任务奠定基础。

http://www.xdnf.cn/news/16079.html

相关文章:

  • springcloud -- 微服务02
  • 关于 URL 中 “+“ 号变成空格的问题
  • 数据结构:找出字符串中重复的字符(Finding Duplicates in a String)——使用哈希表
  • HTTP性能优化实战技术详解(2025)
  • Linux进程核心机制:状态、优先级与上下文切换详解
  • Redis进阶--缓存
  • AQS 抽象队列同步器 资源竞争-排队等待
  • C++实战案例:从static成员到线程安全的单例模式
  • Django视图与路由系统
  • Elasticsearch、Solr 与 OpenSearch 搜索引擎方案对比分析及选型建议
  • 漏洞扫描 + 渗透测试:双轮驱动筑牢网络安全防线
  • 计算机发展史:个人计算机时代的多元融合与变革
  • cartographer内置评估工具使用流程:评估前端优化的误差
  • XSS学习总结
  • 【LeetCode数据结构】栈的应用——有效的括号问题详解
  • iOS 加固工具有哪些?快速发布团队的实战方案
  • Django Ninja
  • 【web 自动化】-6- 数据驱动DDT
  • AWS Certified Cloud Practitioner 认证考试 测试题与解析
  • CSS实现背景色下移10px
  • 自动化与安全 - 将 Terraform 集成到 CI/CD
  • rancher上使用rke在华为云多网卡的服务器上安装k8s集群问题处理了
  • 使用Trae简单编写一个登陆页面
  • 智能合约安全 - 重入攻击 - 常见漏洞(第一篇)
  • AUTOSAR进阶图解==>AUTOSAR_SWS_COMManager
  • 【JS逆向基础】数据库之MongoDB
  • c#转python第四天:生态系统与常用库
  • 近期工作感想:职业规划篇
  • Web开发 04
  • 【企业架构】TOGAF概念之一