当前位置: 首页 > 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.dtcms.com/a/290060.html

相关文章:

  • 在Windows Server 2012 R2中安装与配置IIS服务并部署mssql靶机教程
  • 在Web API 开发中践行Security by Default原则
  • 【操作篇】群晖NAS用root权限直接访问系统分区文件
  • 4x4矩阵教程
  • channel_up和lane_up
  • OpenLayers 入门指南【三】:API概要
  • MetaGPT源码剖析(三):多智能体系统的 “智能角色“ 核心实现——Role类
  • GoLang教程005:switch分支
  • wordle game(猜词游戏)小demo【react + ts】
  • 子网划分核心原理 (网络原理1)
  • 配置 Nginx 反向代理
  • 微信小程序服务端快速对接指南(java版)
  • 本地生活服务 app 同城信息发布系统搭建
  • 文件的写出操作|文件的追加写入操作|文件操作的综合案例
  • BERT 的“池化策略”
  • 基于SpringBoot和leaflet-timeline-slider的历史叙事GIS展示-以哪吒2的海外国家上映安排为例
  • 技能学习PostgreSQL中级专家
  • 云原生安全工具:数字基础设施的免疫长城
  • 解码视觉体验:视频分辨率、屏幕尺寸、屏幕分辨率与观看距离的科学关系
  • 【Linux庖丁解牛】— 线程控制!
  • iOS 加固工具有哪些?快速发布团队的实战方案
  • 个人中心产品设计指南:从信息展示到用户体验的细节把控
  • SQLite以及Room框架的学习:用SQLite给新闻app加上更完善的登录注册功能
  • Lua:小巧而强大的脚本语言,游戏与嵌入式的秘密武器
  • 遇到偶现Bug(难以复现)怎么处理?
  • uni-app 开发小程序项目中实现前端图片压缩,实现方式
  • taro+pinia+小程序存储配置持久化
  • 健身管理小程序|基于微信开发健身管理小程序的系统设计与实现(源码+数据库+文档)
  • 【Unity基础】Unity中2D和3D项目开发流程对比
  • uni-app开发小程序,根据图片提取主题色值