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

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

在这里插入图片描述

相机内参与外参的概念

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.lryc.cn/news/594849.html

相关文章:

  • 单表查询-分页提前获取数据
  • 自动化与安全 - 将 Terraform 集成到 CI/CD
  • 安装pytorch(cpu版)
  • 电科金仓2025发布会,国产数据库的AI融合进化与智领未来
  • 【Lucene】SimScorer
  • 【Spring AI】Advisors API—顾问(即拦截器)
  • 轨迹优化 | 基于边界中间值问题(BIVP)的路径平滑求解器(附C++/Python仿真)
  • 6.String、StringBuffer、StringBuilder区别及使用场景
  • C++学习笔记(六:数组)
  • AI Agent与MCP Service技术进展结构化分析报告(2025Q2)
  • 解决win10下Vmware虚拟机在笔记本睡眠唤醒后ssh连接不上的问题
  • 项目研发进度安排
  • 音视频学习(四十二):H264帧间压缩技术
  • 【时时三省】(C语言基础)使用字符指针变量和字符数组的比较
  • Electron使用WebAssembly实现CRC-16 原理校验
  • Java 二叉树
  • C++11之右值引用与移动语义(提高效率)重要
  • 【Linux指南】Linux系统 -权限全面解析
  • Jetpack ViewModel LiveData:现代Android架构组件的核心力量
  • 病历数智化3分钟:AI重构医院数据价值链
  • AI+Python | 长时序植被遥感:动态·物候·变异归因·RSEI生态评估全流程[特殊字符]
  • C语言(20250718)
  • 车载电子电器架构 --- MCU信息安全相关措施
  • 基于springboot+vue+mysql的在线教育系统(源码+论文)
  • 深入详解随机森林在医学图像质量评估中的应用与实现细节
  • 网络编程Socket linux
  • 【Prometheus+Grafana篇】监控通过Keepalived实现的MySQL HA高可用架构
  • DeepSeek vs ChatGPT:谁更胜一筹?
  • Python 模块未找到?这样解决“ModuleNotFoundError”
  • 02-UE5蓝图初始的三个节点作用