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

OpenCV三维解算常用方法C++

    如果标定过程是通过OpenCV张正友标定法实现的,得到的内参外参保存在.txt文件中是这样的形式:

① 内参intrinsics.txt:

 ② 外参extrinsics.txt:

    那么可以通过如下方法读取.txt文件获取左右相机内外参,主要包括三维解算需要用到的左右相机内参矩阵、畸变系数,以及左右相机构成双目系统的旋转矩阵和平移矩阵,具体代码如下:

std::string intrinsicsPath{ "D:\\Program Files\\edge下载文件\\030716.16\\030716.16\\intrinsics.txt" }; // 左右相机内参数文件路径
std::string extrinsicsPath{ "D:\\Program Files\\edge下载文件\\030716.16\\030716.16\\extrinsics.txt" }; // 左右相机外参数文件路径// 加载左右相机内参数
cv::Mat cameraMatrixL;  // 左相机内参矩阵
cv::Mat distCoeffsL;    // 左相机畸变参数
cv::Mat cameraMatrixR;  // 右相机内参矩阵
cv::Mat distCoeffsR;    // 右相机畸变参数cv::FileStorage fs(intrinsicsPath, cv::FileStorage::READ);
fs["cameraMatrixL"] >> cameraMatrixL;
fs["cameraDistcoeffL"] >> distCoeffsL;
fs["cameraMatrixR"] >> cameraMatrixR;
fs["cameraDistcoeffR"] >> distCoeffsR;
fs.release();//std::cout << "左相机内参矩阵......" << std::endl;
//std::cout << cameraMatrixL << std::endl;
//std::cout << "左相机畸变参数......" << std::endl;
//std::cout << distCoeffsL << std::endl;
//std::cout << std::endl;
//std::cout << "右相机内参矩阵......" << std::endl;
//std::cout << cameraMatrixR << std::endl;
//std::cout << "右相机畸变参数......" << std::endl;
//std::cout << distCoeffsR << std::endl;
//std::cout << std::endl;// 加载相机外参数
cv::Mat R; // 旋转矩阵
cv::Mat T; // 平移向量fs.open(extrinsicsPath, cv::FileStorage::READ);
fs["R"] >> R;
fs["T"] >> T;
fs.release();

    在得到二维像素坐标之后可以通过畸变校正,三角测量法(Triangulation) 来计算三维点坐标。通常是基于 OpenCV 提供的 cv::triangulatePoints 进行计算,这是一个标准的立体视觉技术,用于通过两个相机视角中的匹配点估算其三维坐标。

    步骤如下代码所示:

    二维坐标→畸变校正→转换到相机坐标系→三维解算。

        std::vector<cv::Point2f> leftPointsUndistort, rightPointsUndistort;cv::undistortPoints(targetsL, leftPointsUndistort, cameraMatrixL, distCoeffsL, cv::Mat(), cameraMatrixL);// targetsL是未做畸变矫正前处理得到的二维中心点坐标(左相机)cv::undistortPoints(targetsR, rightPointsUndistort, cameraMatrixR, distCoeffsR, cv::Mat(), cameraMatrixR);// targetsR是未做畸变矫正前处理得到的二维中心点坐标(右相机)// 转换到相机坐标系std::vector<cv::Point2f> leftPointsCam = pixel2cam(leftPointsUndistort, cameraMatrixL);std::vector<cv::Point2f> rightPointsCam = pixel2cam(rightPointsUndistort, cameraMatrixR);// 求解三维坐标std::vector<cv::Point3f> points3d = triangulation(leftPointsCam, rightPointsCam, R, T);

调用的函数代码:

std::vector<cv::Point3f> triangulation(const std::vector<cv::Point2f>& pts1, const std::vector<cv::Point2f>& pts2, cv::Mat& R, cv::Mat& T)
{cv::Mat T1 = (cv::Mat_<float>(3, 4) << 1, 0, 0, 0,0, 1, 0, 0,0, 0, 1, 0);R.convertTo(R, CV_64FC1);T.convertTo(T, CV_64FC1);cv::Mat T2 = (cv::Mat_<float>(3, 4) <<R.at<double>(0, 0), R.at<double>(0, 1), R.at<double>(0, 2), T.at<double>(0, 0),R.at<double>(1, 0), R.at<double>(1, 1), R.at<double>(1, 2), T.at<double>(1, 0),R.at<double>(2, 0), R.at<double>(2, 1), R.at<double>(2, 2), T.at<double>(2, 0));cv::Mat pts4d;cv::triangulatePoints(T1, T2, pts1, pts2, pts4d);std::vector<cv::Point3f> pts3d;for (int i = 0; i < pts4d.cols; ++i){float x = pts4d.at< float >(0, i) / pts4d.at< float >(3, i);float y = pts4d.at< float >(1, i) / pts4d.at< float >(3, i);float z = pts4d.at< float >(2, i) / pts4d.at< float >(3, i);pts3d.emplace_back(cv::Point3f(x, y, z));}return pts3d;
}std::vector<cv::Point2f> pixel2cam(const std::vector<cv::Point2f>& pts, const cv::Mat& cameraMatrix)
{std::vector<cv::Point2f> ptsCam;for (const auto& p : pts){cv::Point2f c((p.x - cameraMatrix.at<double>(0, 2)) / cameraMatrix.at<double>(0, 0),(p.y - cameraMatrix.at<double>(1, 2)) / cameraMatrix.at<double>(1, 1));ptsCam.emplace_back(c);}return ptsCam;
}

 注:pixel2cam 函数的作用是将像素坐标转换为归一化相机坐标(normalized camera coordinates)。这是必要的,因为 三角测量法 计算三维点的位置时,假设输入的点是在无畸变的相机坐标系下。

这里的 (xc,yc) 是归一化相机坐标,表示 光学中心 归一化后的坐标,它们不再依赖于摄像机的焦距和像素比例,因此可以用于三角测量。 

三角测量的数学原理

  • 三角测量基于 两个不同视角的相机投影矩阵(Projection Matrix)。

  • 如果使用 像素坐标,那么投影矩阵应该是 P=K[R∣T](包含相机内参)。

  • 但如果使用 归一化相机坐标,那么投影矩阵可以简化为 P=[R∣T](去除了相机内参)。

  • 这样可以直接利用 相机外参(R, T) 进行计算,提高准确性。

三角测量计算的流程

  1. 将像素坐标转换为归一化相机坐标pixel2cam

  2. 构造相机投影矩阵

    • 第一个相机位于世界坐标系的原点(通常以左相机为原点):

      P1=[I∣0]
    • 第二个相机的投影矩阵由外参 旋转矩阵 R平移向量 T 给出:

      P2=[R∣T]
  3. 使用 OpenCV 的 triangulatePoints 进行三角测量

    • 通过求解一组线性方程,得到齐次坐标 (X,Y,Z,W)

    • 通过 X′=X/W,Y′=Y/W,Z′=Z/W 得到真实的三维坐标

 

相关文章:

OpenCV三维解算常用方法C++

如果标定过程是通过OpenCV张正友标定法实现的&#xff0c;得到的内参外参保存在.txt文件中是这样的形式&#xff1a; ① 内参intrinsics.txt&#xff1a; ② 外参extrinsics.txt&#xff1a; 那么可以通过如下方法读取.txt文件获取左右相机内外参&#xff0c;主要包括三维解算…...

JavaScript 类型转换:全面解析与实践

引言 在 JavaScript 编程里&#xff0c;类型转换是一个频繁出现且极为重要的操作。由于 JavaScript 是一种动态类型语言&#xff0c;变量的类型在运行时可以改变&#xff0c;这就使得类型转换变得十分常见。类型转换主要分为隐式类型转换和显式类型转换&#xff0c;下面将详细…...

Qt Concurrent Filter and Filter-Reduce

并行滤波和滤波-还原 QtConcurrent::filter()、QtConcurrent::filtered() 和 QtConcurrent::filedReduced() 函数并行过滤序列中的项目&#xff0c;如QList 。QtConcurrent::filter() 就地修改序列&#xff0c;QtConcurrent::filtered() 返回包含过滤内容的新序列&#xff0c;…...

【蓝桥杯每日一题】3.25

&#x1f3dd;️专栏&#xff1a; 【蓝桥杯备篇】 &#x1f305;主页&#xff1a; f狐o狸x “OJ超时不是终点&#xff0c;是算法在提醒你该优化时间复杂度了&#xff01;” 目录 3.25 差分数组 一、一维差分 题目链接&#xff1a; 题目描述&#xff1a; 解题思路&#xff1a;…...

深挖增长内核:好产品驱动增长的全方位解析

年前在老板的带领下深入学习了《增长黑客》&#xff0c;并思考了在CPS站外引流的落地方案&#xff0c;最近刚好在做京东联盟的京粉推客增长体系建设&#xff0c;再次回顾一下增长黑客方法以及记录一下思考。 好产品才是增长的根本。增长黑客理念风靡&#xff0c;“啊哈时刻” 概…...

Python技术栈与数据可视化创意实践详解(三)

Python在数据可视化领域凭借丰富的库和灵活的生态系统&#xff0c;能够实现从基础图表到复杂交互式可视化的全场景覆盖。以下从技术选型、创意实现到实战优化进行系统化解析&#xff0c;并提供可直接落地的代码示例。 一、Python数据可视化技术栈 1. 基础与统计可视化 Matplotl…...

前端NVM安装

https://v0.dev/chat/settings 本地启动环境 1安装 nvm 2安装node nvm install v18.19.0 nvm install v20.9.0 nvm use 18 node -v 3安装 pnpm npm install -g pnpm 或者 npm i -g pnpm 4启动 代码 目录下 执行 pnpm i pnpm run dev 4.1到代码目录下 4.2直接cmd…...

Springboot应用配置github自动流部署 深入理解CI/CD:构建、测试和部署的自动化完整流程

什么是 CI 持续集成 通过自动化的流程和工具&#xff0c;提高软件开发的效率、质量和交付速度。 持续集成是开发团队通过将代码的不同部分集成到共享存储库中&#xff0c;并频繁地进行构建和测试&#xff0c;以确保代码的一致性和稳定性。 概念 在现在的开发模式中&#x…...

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《深度探秘&#xff1a;AI界的007》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、什么是Docker 2、什么是Ollama 二、准备工作 1、操…...

c++R 格式

问题描述 小蓝最近在研究一种浮点数的表示方法&#xff1a;RR 格式。对于一个大于 0 的浮点数 dd&#xff0c;可以用 RR 格式的整数来表示。给定一个转换参数 nn&#xff0c;将浮点数转换为 RR 格式整数的做法是: 将浮点数乘以 2n2n&#xff1b; 四舍五入到最接近的整数。 …...

qt QOffscreenSurface详解

1、概述 QOffscreenSurface 是 Qt 中用于离屏渲染的一个类。它允许在不直接与屏幕交互的情况下进行 OpenGL 渲染操作&#xff0c;常用于生成纹理、预渲染场景等。通过 QOffscreenSurface&#xff0c;可以在后台创建一个渲染表面&#xff0c;进行绘制操作&#xff0c;并将结果捕…...

基于Spring Boot的消防物资存储系统的设计与实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…...

深度学习算法清单

目录 1. 神经网络必备基础知识点 2. 神经网络前向传播与反向传播 3. 网络模型整体架构分析实例 4. 神经网络建模效果分析 5. 激活函数与过拟合问题解决 6. 卷积神经网络核心知识点 7. 卷积建模流程与各参数作用分析 8. 池化层的作用与效果 9. 经典卷积神经网络架构分析…...

docker ssh远程连接

目录 操作命令&#xff1a; 确保 SSH 配置允许 root 登录&#xff1a; docker提交&#xff1a; 操作命令&#xff1a; # 进入容器 docker exec -ti lbg04 /bin/bash# 更新包管理并安装 SSH 服务&#xff08;Ubuntu/Debian 示例&#xff09; apt-get update apt-get install…...

leetcode 20.有效括号

20. 有效的括号 - 力扣&#xff08;LeetCode&#xff09; class Solution:def isValid(self, s: str) -> bool:stack []for i in s :if i in ((,{,[ ):stack.append(i)elif i in () ):# 这种情况是 栈弹出元素为空时候 &#xff0c;右半部分的括号多出来一些 比如&#x…...

【杂记三】Cython加速模块cython_nms未编译

一、问题 from cython_nms import nms as cnms ModuleNotFoundError: No module named cython_nms Github download 需要生成如下的 二、安装编译编译安装 cython_nms 1. 确保已经安装了 Cython conda activate your-env pip install cython2. 编译编译 cython_nms 进入编译…...

LeetCode(977):有序数组的平方

有序数组的平方 题目链接 题目&#xff1a;给你一个按非递减顺序排序的整数数组 nums&#xff0c;返回每个数字的平方组成的新数组&#xff0c;要求也按非递减顺序排序。 //暴力 #include<stdio.h> void sort(int *nums,int n){for(int i0;i<n;i)for(int ji1;j<…...

订票系统|基于Java+vue的火车票订票系统(源码+数据库+文档)

订票系统目录 基于Springbootvue的火车票订票系统 一、前言 二、系统设计 三、系统功能设计 1会员信息管理 2 车次信息管理 3订票订单管理 4留言板管理 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍…...

「Unity3D」使用C#获取Android虚拟键盘的高度

原理是&#xff1a;利用getWindowVisibleDisplayFrame方法&#xff0c;获取Android窗口可见区域的Rect&#xff0c;这个Rect剔除了状态栏与导航栏&#xff0c;并且在有虚拟键盘遮挡的时候&#xff0c;会剔除这个遮挡区域。 接着&#xff0c;Unity的safeArea也剔除了状态栏与导…...

近场通信(NFC)在电动车启动系统中的技术实现路径

电动车NFC一键启动系统基于13.56MHz频段实现非接触控制&#xff0c;技术方案要点如下&#xff1a; ‌系统架构‌ ‌硬件核心‌ NFC芯片&#xff08;如N32G45x&#xff09;处理通信协议&#xff0c;支持手机/卡片识别STM32主控解析指令&#xff0c;AES-128加密模块保障双向认证…...

斜线、短横、空格,三种分隔日期的优雅解析(Python | DeepSeek)

标准日期解析操作&#xff0c;str.replace链式如灵蛇蜿蜒&#xff0c;三元表达式像空灵仙家妙法。 笔记模板由python脚本于2025-03-25 22:32:24创建&#xff0c;本篇笔记适合三元表达式、字符串操作修习的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值&#xff1a;在…...

自动化逆向框架使用(Objection+Radare2)

1. 工具链架构与核心优势 1.1 动静结合逆向体系 graph LR A[动态分析] -->|Objection实时Hook| B[关键点定位] B --> C[行为数据捕获] D[静态分析] -->|Radare2深度解析| E[控制流重建] E --> F[漏洞模式识别] B --> F C --> F 组合优势对比&…...

inline 配置全局参数变量

在 C 中&#xff0c;对于头文件中定义的全局变量&#xff0c;使用 inline 比 static 更优&#xff0c;主要原因如下&#xff1a; 1. 避免重复定义的多个副本 static 的问题 每个包含该头文件的 .cpp 都会生成一个独立的变量副本&#xff0c;导致&#xff1a; 内存浪费&#xf…...

(C语言)静态通讯录(正式版)(C语言小项目)

1.首先是头文件&#xff1a; //头文件 //contact.h//防止头文件被重复包含 #pragma once //定义符号常亮&#xff0c;方便维护和修改 //联系人基本信息容量 #define NAME_MAX 20 #define AGE_MAX 5 #define SEX_MAX 5 #define TELE_MAX 15 #define ADDR_MAX 30 //联系人最大容量…...

Windows 计划任务服务(Task Scheduler)

svchost.exe -k netsvcs -p -s Schedule 是 Windows 计划任务服务&#xff08;Task Scheduler&#xff09; 的标准启动命令&#xff0c;通常用于管理系统定时任务。以下是详细解析&#xff1a; 命令拆解 svchost.exe Windows 核心进程&#xff0c;用于托管系统服务&#xff08;…...

[特殊字符] 2025蓝桥杯备赛Day13——P10984 [蓝桥杯 2023 国 Python A] 残缺的数字

&#x1f50d; 2025蓝桥杯备赛Day13——P10984 [蓝桥杯 2023 国 Python A] 残缺的数字 &#x1f680; 题目速览 题目难度&#xff1a;⭐⭐⭐&#xff08;需掌握位运算与组合数学&#xff09; 考察重点&#xff1a;二进制状态处理、位运算、乘法原理、枚举 P10984 [蓝桥杯 2…...

线程控制与线程库

目录 解析tid 线程的地址空间布局 线程栈 我们来学习线程控制与线程库 解析tid #include<iostream> #include<string> #include<cstdio> #include<cstring> #include<unistd.h> #include<thread> using namespace std;int shared_val…...

P1182 数列分段 Section II

P1182 数列分段 Section II - 洛谷 题目描述 对于给定的一个长度为 N 的正整数数列 A1​∼AN​&#xff0c;现要将其分成 M&#xff08;M≤N&#xff09;段&#xff0c;并要求每段连续&#xff0c;且每段和的最大值最小。 关于最大值最小&#xff1a; 例如一数列 4 2 4 5 1…...

比手动备份快 Iperius全自动加密备份,NAS/云盘/磁带机全兼容

IperiusBackupFull是一款专为服务器和工作站设计的备份解决方案&#xff0c;它同时也是一款针对Windows 7/8/10/11/Server系统的简洁且可靠的备份软件。该软件支持增量备份、数据同步以及驱动器镜像&#xff0c;确保能够实现完全的系统恢复。在备份存储方面&#xff0c;Iperius…...

从概率到梯度:理解分类问题中交叉熵的优越性

分类问题一般使用交叉熵&#xff08;Cross-Entropy&#xff09;而不是平方损失&#xff08;Square Loss&#xff09;函数1. **概率解释**2. **梯度性质**3. **对错误的惩罚**4. **计算复杂度**5. **总结** 分类问题一般使用交叉熵&#xff08;Cross-Entropy&#xff09;而不是平…...