详解相机的内参和外参,以及内外参的标定方法

1 四个坐标系

要想深入搞清楚相机的内参和外参含义, 首先得清楚以下4个坐标系的定义:

  • 世界坐标系: 名字看着很唬人, 其实没什么大不了的, 这个就是你自己定义的某一个坐标系。 比如, 你把房间的某一个点定为原点, 并且定义好方向, 这就是世界坐标系。 一般是个三维坐标系, 单位是m
  • 相机坐标系: 以相机光心为原点, 一般我们把z轴指向相机前方,x向右,y向下,是个三维坐标系, 单位是m
  • 成像平面坐标系: 这个是定义在物理成像平面的坐标系,方向定义与相机坐标系一致(没有z方向), 原点是光心在物理成像平面上的投影,是个二维坐标系, 单位是m。 注意, 我们一般都会忽略这个坐标系, 因为它是个中间过渡状态, 很少直接使用它。
  • 像素坐标系: 这个应该是最为常用, 也最为大家熟悉的坐标系, 计算机视觉任务的输出的坐标表达都是在这个坐标系。 它是个二维坐标系, 原点通常在图像的左上角, x向右,y向下, 单位是像素, 没有具体的尺度。
    在这里插入图片描述

2 内参和外参

除了世界坐标系, 后面三个坐标系只跟相机本身有关。 相机内参表达的就是这三个坐标之间的转换关系, 而相机外参表达的是相机与世界坐标系之间的转换关系。

成像的过程实质上是几个坐标系的转换。首先空间中的一点由世界坐标系转换到相机坐标系 ,然后再将其投影到物理成像平面 ( 成像平面坐标系 ) ,最后再将成像平面上的数据转换像素坐标系 。

在这里插入图片描述
从世界坐标到像素坐标总共有3步转换, 前面2个合在一起就是相机内参, 最后一个是相机外参。

上面矩阵中的参数很好理解, 也都有明确的物理含义: a 和b 表示从成像平面坐标转到像素坐标时, 分别在x和y轴上的缩放系数, u 0 u_0 u0 v 0 v_0 v0是原点的平移量。 r r r是扭曲因子, 一般为0。 f f f是相机的焦距。 R和T是旋转和平移矩阵。

把前面2个合一起, 就得到了如下更为常见的内参矩阵:

K = [ f x 0 c x 0 f y c y 0 0 1 ] \mathbf{K} = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} K= fx000fy0cxcy1
下面的讲解中, 我们直接用这种形式,跳过成像平面坐标系。

注意, 实际上内参包含2部分: 内参矩阵K和畸变系数D, 上面只讲到了内参矩阵的原理, 没有讲畸变系数。 这里简单列一下畸变系数, 不做详细介绍。
D = [k1 k2 p1 p2 k3]
其中 k1、k2、k3 是径向畸变系数(radial distortion coefficients) p1、p2 是切向畸变系数(tangential distortion coefficients)。

3 常用的坐标转换

假设有某一个点, 在世界坐标下的坐标为 P w = ( X w , Y w , Z w ) P_w = (X_w, Y_w, Z_w) Pw=(Xw,Yw,Zw), 在相机坐标系下的坐标为 P = ( X c , Y c , Z c ) P = (X_c, Y_c, Z_c) P=(Xc,Yc,Zc), 在像素坐标系下的坐标为 P u v = ( u , v ) P_{uv} = (u, v) Puv=(u,v)

  • 世界坐标转到相机坐标:
    P = R P w + t P = RP_w + t P=RPw+t

  • 相机坐标转到像素坐标:
    P u v = 1 Z c K P P_{uv} =\frac 1{Z_c} KP Puv=Zc1KP
    展开就是:
    [ u v 1 ] = 1 Z c K [ X c Y c Z c ] = 1 Z c [ f x 0 c x 0 f y c y 0 0 1 ] [ X c Y c Z c ] \begin{bmatrix} u \\ v \\ 1 \end{bmatrix} = \frac 1{Z_c} \mathbf{K} \begin{bmatrix} X_c \\ Y_c \\ Z_c \\ \end{bmatrix} = \frac 1{Z_c} \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} X_c \\ Y_c \\ Z_c \\ \end{bmatrix} uv1 =Zc1K XcYcZc =Zc1 fx000fy0cxcy1 XcYcZc

  • 像素坐标转到像素坐标
    这个转换是最为常用的, 因为我们通常得到的都是像素坐标系下的信息, 如目标检测、分割的结果就是像素坐标, 得到像素坐标后 ,可以转为相机坐标, 进一步再转为世界坐标。另外, 在点云目标检测中, 通常要把原始的彩色图像和深度信息转换为点云, 就需要用到这个转换。
    P = Z c K − 1 P u v P = Z_cK^{-1}P_{uv} P=ZcK1Puv
    展开就是:
    X c = u − c x f x ∗ Z c X_c = \frac {u-c_x}{f_x}*Z_c Xc=fxucxZc
    Y c = v − c y f y ∗ Z c Y_c = \frac {v-c_y}{f_y}*Z_c Yc=fyvcyZc
    注意上面有个尺度因子 Z c Z_c Zc, 从相机坐标系的三维坐标投影到像素平面的二维坐标, 实际上丢失了z方向也就是深度信息。 所以如果不知道深度, 从像素坐标就无法恢复出准确的相机坐标。深度通常可以通过深度相机直接测量得到, 或通过深度估计算法预测。

4 内外参标定方法

4.1 内参标定方法

内参标定通常使用张正友标定法, 也就是常见的棋盘格标定。

代码可参考https://github.com/leo038/hand_eye_calibrate/blob/main/hand_eye_calibrate.py 中的camera_calibrate函数。

4.2 外参标定方法

外参标定的核心是:已知多个点分别在相机坐标系下的坐标和在世界坐标系下的坐标, 求它们之间的映射关系。
常用求解PnP 的方法,即已知多个点, 在像素坐标系的二维坐标, 和在世界坐标系的三维坐标,并且已知内参, 求解旋转平移矩阵。

cv2 中提供了外参标定方法, cv2.solvePnP 只需提供对应的点对即可。
完整代码实现如下:

import cv2
import numpy as np# 定义已知的3D空间点和对应的2D图像点
objectPoints = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]], dtype=np.float32)
imagePoints = np.array([[10, 20], [30, 50], [20, 70], [50, 40]], dtype=np.float32)# 定义相机的内参矩阵和畸变系数
cameraMatrix = np.array([[1000, 0, 320], [0, 1000, 240], [0, 0, 1]], dtype=np.float32)
distCoeffs = np.zeros((4, 1), dtype=np.float32)# 使用solvePnP函数求解相机的位姿
ret, rvec, tvec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs, flags=cv2.SOLVEPNP_EPNP)if ret:print("Rotation vector:\n", rvec)print("Translation vector:\n", tvec)
else:print("Failed to solve PnP.")res, _ = cv2.Rodrigues(rvec)
print(f"旋转矩阵: {res}")

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75812.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学透Spring Boot — 011. 一篇文章学会Spring Test

系列文章目录 这是学透Spring Boot的第11篇文章。更多系列文章请关注 CSDN postnull 用户的专栏 文章目录 系列文章目录Spring Test的依赖Spring Test的核心功能SpringBootTest 加载Spring上下文依赖注入有问题时Spring配置有问题时 WebMvcTest 测试Web层(Controll…

Mysql 数据库编程技术01

一、数据库基础 1.1 认识数据库 为什么学习数据库 瞬时数据:比如内存中的数据,是不能永久保存的。持久化数据:比如持久化至数据库中或者文档中,能够长久保存。 数据库是“按照数据结构来组织、存储和管理数据的仓库”。是一个长…

新一代AI架构实践:数字大脑AI+智能调度MCP+领域执行APP的黄金金字塔体系

新一代AI架构实践:数字大脑智能调度领域执行的黄金金字塔体系 一、架构本质的三层穿透性认知 1.1 核心范式转变(CPS理论升级) 传统算法架构:数据驱动 → 特征工程 → 模型训练 → 业务应用 新一代AI架构:物理规律建…

macOS可视化桌面配置docker加速器

macOS可视化桌面配置docker加速器 在镜像settings->docker Engine改为国内镜像修改为国内镜像重启docker(可视化界面启动或者使用命令行)使用命令重启可视化界面重启 在镜像settings->docker Engine改为国内镜像 修改为国内镜像 {"registry-mirrors": ["…

Nginx 基础使用(2025)

一、Nginx目录结构 [rootlocalhost ~]# tree /usr/local/nginx /usr/local/nginx ├── client_body_temp # POST 大文件暂存目录 ├── conf # Nginx所有配置文件的目录 │ ├── fastcgi.conf # fastcgi相…

用spring-webmvc包实现AI(Deepseek)事件流(SSE)推送

前后端: Spring Boot Angular spring-webmvc-5.2.2包 代码片段如下: 控制层: GetMapping(value "/realtime/page/ai/sse", produces MediaType.TEXT_EVENT_STREAM_VALUE)ApiOperation(value "获取告警记录进行AI分析…

基于Python的招聘推荐数据可视化分析系统

【Python】基于Python的招聘推荐数据可视化分析系统(完整系统源码开发笔记详细部署教程)✅ 目录 一、项目简介二、项目界面展示三、项目视频展示 一、项目简介 🚀🌟 基于Python的招聘推荐数据可视化分析系统!&#x1…

使用注解开发springMVC

引言 在学习过第一个springMVC项目建造过后&#xff0c;让我们直接进入真实开发中所必需的注解开发&#xff0c; 是何等的简洁高效&#xff01;&#xff01; 注&#xff1a;由于Maven可能存在资源过滤的问题&#xff0c;在maven依赖中加入 <build><resources>&l…

linux专题3-----禁止SSH的密码登录

要在linux系统中禁止密码登录&#xff0c;您可以通过修改 SSH 配置来实现。请按照以下步骤操作(此处以 Ubuntu为例)&#xff1a; 1、SSH 登录到您的服务器&#xff08;或直接在命令行模式下&#xff09;。 2、备份 SSH 配置文件&#xff1a; 在终端中运行以下命令以备份现有的…

基于LangChain和通义(Tongyi)实现NL2SQL的智能检索(无需训练)

在数据驱动的时代,如何高效地从数据库中获取信息成为了一个重要的挑战。自然语言到SQL(NL2SQL)技术提供了一种便捷的解决方案,使用户能够用自然语言查询数据库,而无需深入了解SQL语法。本文将探讨如何利用LangChain和通义(Tongyi)实现NL2SQL的智能检索,具体步骤如下: …

深度学习处理文本(10)

保存自定义层 在编写自定义层时&#xff0c;一定要实现get_config()方法&#xff1a;这样我们可以利用config字典将该层重新实例化&#xff0c;这对保存和加载模型很有用。该方法返回一个Python字典&#xff0c;其中包含用于创建该层的构造函数的参数值。所有Keras层都可以被序…

机器视觉3D中激光偏镜的优点

机器视觉的3D应用中,激光偏镜(如偏振片、波片、偏振分束器等)通过其独特的偏振控制能力,显著提升了系统的测量精度、抗干扰能力和适应性。以下是其核心优点: 1. 提升3D成像精度 抑制环境光干扰:偏振片可滤除非偏振的环境杂光(如日光、室内照明),仅保留激光偏振信号,大…

线程同步的学习与应用

1.多线程并发 1).多线程并发引例 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> #include <pthread.h>int wg0; void *fun(void *arg) {for(int i0;i<1000;i){wg;printf("wg%d\n",wg);} } i…

写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码?

VB.NET 写.NET可以指定运行SUB MAIN吗?调用任意一个里面的类时,如何先执行某段初始化代码? 分享 1. 在 VB.NET 中指定运行 Sub Main 在 VB.NET 里&#xff0c;你能够指定 Sub Main 作为程序的入口点。下面为你介绍两种实现方式&#xff1a; 方式一&#xff1a;在项目属性…

【AI插件开发】Notepad++ AI插件开发实践(代码篇):从Dock窗口集成到功能菜单实现

一、引言 上篇文章已经在Notepad的插件开发中集成了选中即问AI的功能&#xff0c;这一篇文章将在此基础上进一步集成&#xff0c;支持AI对话窗口以及常见的代码功能菜单&#xff1a; 显示AI的Dock窗口&#xff0c;可以用自然语言向 AI 提问或要求执行任务选中代码后使用&…

关联容器-模板类pair数对

关联容器 关联容器和顺序容器有着根本的不同:关联容器中的元素是按关键字来保存和访问的,而顺序容器中的元素是按它们在容器中的位置来顺序保存和访问的。 关联容器支持高效的关键字查找和访问。 两个主要的关联容器(associative-container),set和map。 set 中每个元素只包…

京东运维面试题及参考答案

目录 OSPF 实现原理是什么? 请描述 TCP 三次握手的过程。 LVS 的原理是什么? 阐述 Nginx 七层负载均衡的原理。 Nginx 与 Apache 有什么区别? 如何查看监听在 8080 端口的是哪个进程(可举例:netstat -tnlp | grep 8080)? OSI 七层模型是什么,请写出各层的协议。 …

输入框输入数字且保持精度

在项目中如果涉及到金额等需要数字输入且保持精度的情况下&#xff0c;由于输入框是可以随意输入文本的&#xff0c;所以一般情况下可能需要监听输入框的change事件&#xff0c;然后通过正则表达式去替换掉不匹配的文本部分。 由于每次文本改变都会被监听&#xff0c;包括替换…

使用 requests 和 BeautifulSoup 解析淘宝商品

以下将详细解释如何通过这两个库来实现按关键字搜索并解析淘宝商品信息。 一、准备工作 1. 安装必要的库 在开始之前&#xff0c;确保已经安装了 requests 和 BeautifulSoup 库。如果尚未安装&#xff0c;可以通过以下命令进行安装&#xff1a; bash pip install requests…

C#调用ACCESS数据库,解决“Microsoft.ACE.OLEDB.12.0”未注册问题

C#调用ACCESS数据库&#xff0c;解决“Microsoft.ACE.OLEDB.12.0”未注册问题 解决方法&#xff1a; 1.将C#采用的平台从AnyCpu改成X64 2.将官网下载的“Microsoft Access 2010 数据库引擎可再发行程序包AccessDatabaseEngine_X64”文件解压 3.安装解压后的文件 点击下载安…