OpenCV相机标定与3D重建(8)相机标定函数calibrateCamera()的使用
- 操作系统:ubuntu22.04
- OpenCV版本:OpenCV4.9
- IDE:Visual Studio Code
- 编程语言:C++11
算法描述
从校准图案的多个视图中找到相机的内参和外参参数.
cv::calibrateCamera 是 OpenCV 中用于相机标定的一个非常重要的函数。它通过一系列已知的世界坐标点(通常是棋盘格角点)和它们在图像中的对应点来计算相机的内参矩阵 cameraMatrix 和畸变系数 distCoeffs。
函数原型
double cv::calibrateCamera
(InputArrayOfArrays objectPoints,InputArrayOfArrays imagePoints,Size imageSize,InputOutputArray cameraMatrix,InputOutputArray distCoeffs,OutputArrayOfArrays rvecs,OutputArrayOfArrays tvecs,OutputArray stdDeviationsIntrinsics,OutputArray stdDeviationsExtrinsics,OutputArray perViewErrors,int flags = 0,TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON)
)
参数
- 参数objectPoints:
在新接口中,这是一个包含校准图案点在标定图案坐标空间中的向量的向量(例如 std::vector<std::vectorcv::Vec3f>)。外层向量包含的元素数量与图案视图的数量相同。如果每个视图中显示相同的标定图案且完全可见,则所有向量将相同。尽管可以使用部分遮挡的图案,甚至在不同的视图中使用不同的图案,在这种情况下,向量将不同。虽然这些点是3D的,但如果使用的标定图案是平面刚体,它们都位于标定图案的XY坐标平面上(因此Z坐标为0)。在旧接口中,来自不同视图的所有对象点向量被连接在一起。 - 参数imagePoints:
在新接口中,这是一个包含标定图案点投影的向量的向量(例如 std::vector<std::vectorcv::Vec2f>)。imagePoints.size() 和 objectPoints.size(),以及对于每个 i 的 imagePoints[i].size() 和 objectPoints[i].size() 必须分别相等。在旧接口中,来自不同视图的所有对象点向量被连接在一起。 - 参数imageSize:
图像尺寸,仅用于初始化相机内参矩阵。 - 参数cameraMatrix:
输入/输出 3x3 浮点相机内参矩阵 A = [ f x 0 c x 0 f y c y 0 0 1 ] A = \begin{bmatrix} f_x & 0 & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \end{bmatrix} A= fx000fy0cxcy1 。如果指定了 CALIB_USE_INTRINSIC_GUESS 和/或 CALIB_FIX_ASPECT_RATIO、CALIB_FIX_PRINCIPAL_POINT 或 CALIB_FIX_FOCAL_LENGTH,则必须在调用函数之前初始化 f_x、f_y、c_x 和 c_y 中的一个或全部。 - 参数distCoeffs:
输入/输出畸变系数向量 (k1, k2, p1, p2[, k3[, k4, k5, k6[, s1, s2, s3, s4[, τx, τy]]]]),包含 4、5、8、12 或 14 个元素。 - 参数rvecs:
输出旋转向量 (Rodrigues) 估计值,每个图案视图一个 (例如 std::vectorcv::Mat )。也就是说,每个第 i 个旋转向量和相应的第 i 个平移向量(见下一个输出参数描述)将标定图案从对象坐标空间(其中指定对象点)带到相机坐标空间。更技术地说,第 i 个旋转和平移向量的组合执行了从对象坐标空间到相机坐标空间的基变换。由于其对偶性,这个组合等同于标定图案相对于相机坐标空间的位置。 - 参数tvecs:
输出平移向量估计值,每个图案视图一个,参见上述参数描述。 - 参数stdDeviationsIntrinsics:
输出内参标准偏差估计值。偏差值的顺序:(fx, fy, cx, cy, k1, k2, p1, p2, k3, k4, k5, k6, s1, s2, s3, s4, τx, τy)。如果某个参数未估计,则其偏差为零。 - 参数stdDeviationsExtrinsics:
输出外参标准偏差估计值。偏差值的顺序:(R0, T0, …, RM−1, TM−1),其中 M 是图案视图的数量。Ri, Ti 是连接的 1x3 向量。 - 参数perViewErrors:
输出每个图案视图的 RMS 重投影误差估计值。 - 参数flags:
不同的标志,可以为零或以下值的组合:- CALIB_USE_INTRINSIC_GUESS: cameraMatrix 包含有效的初始值 fx, fy, cx, cy,这些值将进一步优化。否则,(cx, cy) 初始设置为图像中心(使用 imageSize),焦距通过最小二乘法计算。注意,如果已知内参参数,不需要使用此函数仅估计外参参数。应使用 solvePnP。
- CALIB_FIX_PRINCIPAL_POINT: 主点在全局优化过程中不改变。它保持在中心或在设置了 CALIB_USE_INTRINSIC_GUESS 时指定的不同位置。
- CALIB_FIX_ASPECT_RATIO: 函数仅考虑 fy 作为自由参数。fx/fy 的比例保持与输入 cameraMatrix 中的比例相同。当未设置 - CALIB_USE_INTRINSIC_GUESS 时,实际输入的 fx 和 fy 值被忽略,仅计算并使用它们的比例。
- CALIB_ZERO_TANGENT_DIST: 切向畸变系数 (p1, p2) 设置为零并保持为零。
- CALIB_FIX_FOCAL_LENGTH: 如果设置了 CALIB_USE_INTRINSIC_GUESS,则焦距在全局优化过程中不改变。
- CALIB_FIX_K1, …, CALIB_FIX_K6: 相应的径向畸变系数在优化过程中不改变。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数。否则,将其设置为 0。
- CALIB_RATIONAL_MODEL: 启用系数 k4, k5 和 k6。为了提供向后兼容性,需要显式指定此额外标志以使标定函数使用有理模型并返回 8 个或更多系数。
- CALIB_THIN_PRISM_MODEL: 启用系数 s1, s2, s3 和 s4。为了提供向后兼容性,需要显式指定此额外标志以使标定函数使用薄棱镜模型并返回 12 个或更多系数。
- CALIB_FIX_S1_S2_S3_S4: 薄棱镜畸变系数在优化过程中不改变。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 - distCoeffs 矩阵中的系数。否则,将其设置为 0。
- CALIB_TILTED_MODEL: 启用系数 τX 和 τY。为了提供向后兼容性,需要显式指定此额外标志以使标定函数使用倾斜传感器模型并返回 14 个系数。
- CALIB_FIX_TAUX_TAUY: 倾斜传感器模型的系数在优化过程中不改变。如果设置了 CALIB_USE_INTRINSIC_GUESS,则使用提供的 distCoeffs 矩阵中的系数。否则,将其设置为 0。
- 参数criteria:
迭代优化算法的终止条件。
返回值
总体 RMS 重投影误差
该函数估计每个视图的相机内参和外参。算法基于 [314] 和 [37]。必须指定3D对象点及其在每个视图中的对应2D投影坐标。这可以通过使用具有已知几何形状且易于检测特征点的对象来实现。这种对象被称为校准装置或校准图案,OpenCV 内置支持棋盘格作为校准装置(见 findChessboardCorners)。目前,内参初始化(当未设置 CALIB_USE_INTRINSIC_GUESS 时)仅适用于平面校准图案(其中对象点的 Z 坐标必须全为零)。只要提供了初始的 cameraMatrix,也可以使用3D校准装置。
算法执行以下步骤:
- 计算初始内参(仅适用于平面校准图案)或从输入参数中读取。畸变系数最初全部设为零,除非指定了某些 CALIB_FIX_K?。
- 估计初始相机姿态,假设内参已经已知。这是通过 solvePnP 完成的。
- 运行全局 Levenberg-Marquardt 优化算法 以最小化重投影误差,即观测特征点 imagePoints 和投影(使用当前估计的相机参数和姿态)对象点 objectPoints 之间的总平方距离之和。有关详细信息,请参见 projectPoints。
- 注意事项
如果你使用非正方形(即非 N x N)网格并使用 findChessboardCorners 进行校准,并且 calibrateCamera 返回了不合理的值(例如,畸变系数为零,cx 和 cy 远离图像中心,或者 fx 和 fy 之间有较大的差异(比率超过 10:1 或更多)),那么你可能在 findChessboardCorners 中使用了 patternSize=cvSize(rows, cols) 而不是 patternSize=cvSize(cols, rows)。
如果提供了不支持的参数组合或系统欠定,该函数可能会抛出异常。
代码示例
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>int main() {// 棋盘格参数int boardSize = 10; // 棋盘格的行数和列数double squareSize_mm = 10.0; // 每个方块的大小,以毫米为单位// 图像尺寸cv::Size imageSize;// 存储所有图像中的棋盘格角点std::vector<std::vector<cv::Point2f>> imagePoints;std::vector<std::vector<cv::Point3f>> objectPoints;// 生成对象点std::vector<cv::Point3f> obj;for (int y = 0; y < boardSize; ++y) {for (int x = 0; x < boardSize; ++x) {obj.push_back(cv::Point3f(x * squareSize_mm, y * squareSize_mm, 0));}}// 读取图像文件列表std::vector<std::string> imageFilenames = {"image1.jpg", "image2.jpg", "image3.jpg", "image4.jpg"}; // 添加更多图像for (const auto &filename : imageFilenames) {cv::Mat image = cv::imread(filename);if (image.empty()) {std::cerr << "无法读取图像: " << filename << std::endl;continue;}if (imageSize.width == 0 || imageSize.height == 0) {imageSize = image.size();}std::vector<cv::Point2f> corners;bool found = cv::findChessboardCorners(image, cv::Size(boardSize, boardSize), corners);if (found) {// 亚像素精度调整cv::cornerSubPix(image, corners, cv::Size(11, 11), cv::Size(-1, -1),cv::TermCriteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 30, 0.01));// 保存角点imagePoints.push_back(corners);objectPoints.push_back(obj);// 可视化角点cv::drawChessboardCorners(image, cv::Size(boardSize, boardSize), corners, found);cv::imshow("Chessboard Corners", image);cv::waitKey(500); // 显示图像,等待半秒} else {std::cerr << "无法找到棋盘格角点: " << filename << std::endl;}}// 标定相机cv::Mat cameraMatrix, distCoeffs;std::vector<cv::Mat> rvecs, tvecs;std::vector<float> perViewErrors;double rms = cv::calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs,cv::noArray(), cv::noArray(), perViewErrors,cv::CALIB_FIX_ASPECT_RATIO | cv::CALIB_ZERO_TANGENT_DIST);std::cout << "Reprojection error: " << rms << std::endl;std::cout << "Camera matrix: " << cameraMatrix << std::endl;std::cout << "Distortion coefficients: " << distCoeffs << std::endl;// 使用标定结果进行图像校正for (const auto &filename : imageFilenames) {cv::Mat image = cv::imread(filename);if (image.empty()) {std::cerr << "无法读取图像: " << filename << std::endl;continue;}cv::Mat undistortedImage;cv::undistort(image, undistortedImage, cameraMatrix, distCoeffs);cv::imshow("Undistorted Image", undistortedImage);cv::waitKey(0);}return 0;
}
相关文章:
OpenCV相机标定与3D重建(8)相机标定函数calibrateCamera()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 从校准图案的多个视图中找到相机的内参和外参参数. cv::calibrateCamera 是 OpenCV 中用于相机标定的一个非常重要的函数。它通过一系列已知的世…...
Linux信号量的编程
一,用信号量来实现是父进程先进行,还是子进程先进性 信号量的没有P,V操作之前,我们不知道如何控制: #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/sem.h>…...

“Yaker,你可以全局配置插件环境变量!“
周四周四,Vme50(bushi 大家好,这里是疯狂超级牛(功能上新版) 经常有用户问 “牛牛如何为不同插件配置相同的变量值呢?” “能有一个一波搞定插件变量的方式就好了” 超级牛听到了广大用户的声音,默默地拿起…...

SAAS美容美发系统架构解析
随着技术的不断发展,SAAS(Software as a Service,软件即服务)模式在各个行业的应用逐渐深化,美容美发行业也不例外。传统的美容美发店面通常依赖纸质记录、手动操作和复杂的管理流程,而随着SAAS平台的出现&…...

如何为 ext2/ext3/ext4 文件系统的 /dev/centos/root 增加 800G 空间
如何为 ext2/ext3/ext4 文件系统的 /dev/centos/root 增加 800G 空间 一、引言二、检查当前磁盘和分区状态1. 使用 `df` 命令检查磁盘使用情况2. 使用 `lsblk` 命令查看分区结构3. 使用 `fdisk` 或 `parted` 命令查看详细的分区信息三、扩展逻辑卷(如果使用 LVM)1. 检查 LVM …...
vscode远程连接ssh
一. 使用vscode里的ssh查件连不上远程的解决方法 删除Windows上的known_host文件,该文件会在连接之后自动生成,用于验证远程服务器的身份。 konwn_host和id_rsa,id_rsa.pub的关系 (1)konwn_host用于客户端验证远程服务…...

智慧防汛平台在城市生命线安全建设中的应用
随着城市化进程的加快,城市基础设施的复杂性和互联性不断增强,城市生命线的安全管理面临前所未有的挑战。智慧防汛平台作为城市生命线安全建设的重要组成部分,通过现代信息技术提升城市防汛应急管理的智能化水平,保障城市安全。 …...
python实现TCP Socket控制测试仪器
python实现TCP Socket控制测试仪器 说明前提条件代码 说明 本例是用python实现TCP Socket,最终目的是为了控制LCR电容测试仪器。 前提条件 测试仪器 配备了以太网接口,支持TCP/IP协议栈 用户可以通过IP地址和端口号连接到仪器,建立TCP通信…...

51c自动驾驶~合集38
我自己的原文哦~ https://blog.51cto.com/whaosoft/12358456 #GaussianPretrain 万能3D高斯预训练表示!爆拉3D检测、Occ、高精地图等四大任务! 受Tesla的技术的推动,越来越多的厂商开始走"纯视觉"的路线,多数方案还…...
电脑显示器拔插DVI线后副屏不显示
问题:台式机副屏显示器插拔DVI线后副屏无法检测到,不显示 其他现象:电脑设备管理器“显示适配器”中只有独显,未显示集显。 尝试方法: 1、 重新插拔并拧紧DVI线、更换DVI线、将DVI线替换为VGA线、调换DVI线及VGA线两…...

Bash脚本常用命令
1.Bash常用快捷键 2.通配符 3.Bash其他特殊符号 4.位置参数 5.预定义变量 6.常用变量比较 7.基础正则表达式 8.文件类型判断 9.文件权限判断 10.整数比较命令 11.字符串判断 其他常用参考: https://zhuanlan.zhihu.com/p/748857250...

《Unity Shader 入门精要》高级纹理
立方体纹理 图形学中,立方体纹理(Cubemap)是环境映射(Environment Mapping)的一种实现方法。环境映射可以模拟物体周围的环境,而使用了环境映射的物体可以看起来像镀了层金属一样反射出周围的环境。 对立…...

vue3实现自定义导航菜单
一、创建项目 1. 打开HBuilder X 图1 2. 新建一个空项目 文件->新建->项目->uni-app 填写项目名称:vue3demo 选择项目存放目录:D:/HBuilderProjects 一定要注意vue的版本,当前选择的版本为vue3 图2 点击“创建”之后进入项目界面 图…...

[2024年3月10日]第15届蓝桥杯青少组stema选拔赛C++中高级(第二子卷、编程题(2))
方法一(string): #include <iostream> #include <string> using namespace std;// 检查是否为回文数 bool isPalindrome(int n) {string str to_string(n);int left 0, right str.size() - 1;while (left < right) {if (s…...

EDA软件研发的DevOps平台
1:什么是DevOps DevOps是十几年前,在互联网比较火的词,实际上就是ci/cd平台的另外一种说法,核心是说打破研发,测试,运维的边界,能够将整个产品开发的流程快速循环起来,随时可发版&a…...
从单机缓存到分布式缓存那些事
作者:秦怀 1 缓存前世今生 1.1 故事从硬件开始 Cache 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词“cache”赋予“safekeeping storage”的涵义,用于电脑工程领域。当时没有 Cache,CPU 和内存都很慢,CPU 直接访…...
[Ubuntu20] Gym入门,Mujoco
OpenAI Gym是 OpenAI 出的研究强化学习算法的 toolkit,对于强化学习算法来说,大部分的论文环境都已经被 OpenAI 的 gym 环境集成,我们可以很便利的使用该工程来测试自己的强化学习算法,与他人的算法做一个对比。 Gym 官网 Github…...
Linux(ubuntu)系统的一些基本操作和命令(持续更新)
操作: Ctrl Alt T(打开命令终端) Ctrl Shift (放大命令终端窗口) Ctrl c(退出当前在终端运行的程序) 在命令终端窗口按Tab键可以补全要写的命令 命令: pwd(查…...

【NLP高频面题 - 分布式训练】ZeRO1、ZeRO2、ZeRO3分别做了哪些优化?
【NLP高频面题 - 分布式训练】ZeRO1、ZeRO2、ZeRO3分别做了哪些优化? 重要性:★★ NLP Github 项目: NLP 项目实践:fasterai/nlp-project-practice 介绍:该仓库围绕着 NLP 任务模型的设计、训练、优化、部署和应用&am…...
android 安全sdk相关
前述 在网上有看到许多android安全sdk相关的内容,有重复的也有比较新鲜的内容,这里做一个整体的合集,以及后续又看到一些比较新的东西会一起放在这里。 android内sdk目前可以分为以下几个部分(有一些部分可能会存在一些重合&#…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...