OpenCV双目相机外参标定C++

基于OpenCV库实现双目测量系统外参标定过程。通过分析双目测量系统左右相机拍摄的棋盘格标定板图像,包括角点检测、立体标定、立体校正和畸变校正的步骤,获取左右相机的相对位置关系和姿态。

a.检测每张图像中的棋盘格角点,并进行亚像素级精确化;根据左右相机的角点坐标、三维坐标、内参矩阵和畸变系数,计算旋转矩阵R和平移向量T,利用最小二乘法最小化重投影误差;根据标定结果对图像进行畸变校正。

b.输出为双目测量系统的标定结果,包括旋转矩阵、平移向量、投影矩阵和重投影矩阵,并通过imshow展示校正后的图像和视差图,以评估标定质量。

// 单目内参标定后进行双目标定
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/opencv.hpp>
#include<iostream>
#include <opencv2/core/utils/logger.hpp> //隐藏日志using namespace std;
using namespace cv;int n = 1;
int m = 1;int i = 1;
int j = 1;const int imagewidth = 2048;
const int imagehight = 2048;//图像的长宽
const int boardwidth = 11;
const int boardhight = 8;//图片上棋盘格标定板的内角点个数(行、列的角点数)
const int framenumber = 13;//标定图片数
const int squaresize = 50;//棋盘格标定板单个方格的大小
const cv::Size imagesize = cv::Size(imagewidth, imagehight);
const cv::Size boardsize = cv::Size(boardwidth, boardhight);vector<cv::Point3f> objectpoint;
vector<vector<cv::Point3f>> objpoint;vector<cv::Point2f> cornerL;
vector<cv::Point2f> cornerR;vector<vector<cv::Point2f>> imagepointL;
vector<vector<cv::Point2f>> imagepointR;Mat cameraMatrixL = (Mat_<double>(3, 3) << 2946.368631790921, 0, 992.3628859436697,0, 2947.324578115115, 1041.333927112967,0, 0, 1);
Mat distcoeffL = (Mat_<double>(5, 1) << -0.09314094645325596, 0.212990743663531, 0.001099206303953861, 0.0003299289802971191, 2.911155272910228);
Mat cameraMatrixR = (Mat_<double>(3, 3) << 2935.765597816497, 0, 997.8971330325958,0, 2938.133144049969, 1001.295460381107,0, 0, 1);
//获得的畸变参数
Mat distcoeffR = (Mat_<double>(5, 1) << -0.07849722399107049, -0.05592478850461548, -0.0009348860866305323, 8.96474606278152e-06, 4.375424240166232);cv::Mat R, T, E, F;
cv::Mat R1, R2, P1, P2, Q;cv::Mat maplx, maply, maprx, mapry;cv::Mat imageL, grayimageL;
cv::Mat imageR, grayimageR;cv::Rect validROIL, validROIR;void worldpoint()
{for (int i = 0; i < boardhight; i++){for (int j = 0; j < boardwidth; j++){objectpoint.push_back(cv::Point3f(i * squaresize, j * squaresize, 0.0f));}}for (int w = 1; w <= framenumber; w++){objpoint.push_back(objectpoint);}
}void outputparam()
{cv::FileStorage fs("intrinsics.yml", cv::FileStorage::WRITE);fs << "cameraMatrixL" << cameraMatrixL << "cameraDistcoeffL" << distcoeffL << "cameraMatrixR" << cameraMatrixR << "cameraDistcoeffR" << distcoeffR;fs.release();std::cout << "cameraMatrixL=:" << cameraMatrixL << endl << "cameraDistcoeffL=:" << distcoeffL << endl << "cameraMatrixR=:" << cameraMatrixR << endl << "cameraDistcoeffR=:" << distcoeffR << endl;fs.open("extrinsics.yml", cv::FileStorage::WRITE);fs << "R" << R << "T" << T << "Rl" << R1 << "Rr" << R2 << "Pl" << P1 << "Pr" << P2 << "Q" << Q << "F" << F << "E" << E;std::cout << "R=" << R << endl << "T=" << T << endl << "Rl=" << R1 << endl << "Rr=" << R2 << endl << "Pl=" << P1 << endl << "Pr=" << P2 << endl << "Q=" << Q << endl << "F=" << F << endl << "E=" << E << endl;fs.release();}int main()
{cv::utils::logging::setLogLevel(utils::logging::LOG_LEVEL_SILENT);//不再输出日志//或//utils::logging::setLogLevel(utils::logging::LOG_LEVEL_ERROR);//只输出错误日志//读取图片int current = 1;while (current <= framenumber){char frameL[50];sprintf_s(frameL, 50, "external/l%d.bmp", n++);imageL = cv::imread(frameL);cv::cvtColor(imageL, grayimageL, cv::ColorConversionCodes::COLOR_BGR2GRAY);char frameR[50];sprintf_s(frameR, 50, "external/r%d.bmp", m++);imageR = cv::imread(frameR);cv::cvtColor(imageR, grayimageR, cv::ColorConversionCodes::COLOR_BGR2GRAY);bool foundL, foundR;foundL = cv::findChessboardCorners(imageL, boardsize, cornerL);foundR = cv::findChessboardCorners(imageR, boardsize, cornerR);if (foundL == true && foundR == true){cv::cornerSubPix(grayimageL, cornerL, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS, 30, 1e-6));cv::cornerSubPix(grayimageR, cornerR, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::MAX_ITER | cv::TermCriteria::EPS, 30, 1e-6));cv::drawChessboardCorners(imageL, boardsize, cornerL, foundL);//cv::imshow("L", imageL);namedWindow("L", WINDOW_NORMAL);imshow("L", imageL);cv::waitKey(10);cv::drawChessboardCorners(imageR, boardsize, cornerR, foundR);//cv::imshow("R", imageR);namedWindow("R", WINDOW_NORMAL);imshow("R", imageR);cv::waitKey(10);imagepointL.push_back(cornerL);imagepointR.push_back(cornerR);cout << "The image  " << current << "  is good" << endl;}else{std::cout << "The image is bad please try again" << endl;}current++;}worldpoint();cout << "开始标定" << endl;double err = cv::stereoCalibrate(objpoint, imagepointL, imagepointR, cameraMatrixL, distcoeffL, cameraMatrixR, distcoeffR, imagesize, R, T, E, F,CALIB_USE_INTRINSIC_GUESS,cv::TermCriteria(cv::TermCriteria::COUNT + cv::TermCriteria::EPS, 30, 1e-6));cout << "The err = " << err << endl;cv::stereoRectify(cameraMatrixL, distcoeffL, cameraMatrixR, distcoeffR, imagesize, R, T, R1, R2, P1, P2, Q, cv::CALIB_ZERO_DISPARITY, -1, imagesize, &validROIL, &validROIR);cv::initUndistortRectifyMap(cameraMatrixL, distcoeffL, R1, P1, imagesize, CV_32FC1, maplx, maply);cv::initUndistortRectifyMap(cameraMatrixR, distcoeffR, R2, P2, imagesize, CV_32FC1, maprx, mapry);outputparam();cv::Mat canvas;double sf;int w, h;sf = 600. / MAX(imagesize.width, imagesize.height);w = cvRound(imagesize.width * sf);h = cvRound(imagesize.height * sf);canvas.create(h, w * 2, CV_8UC3);int currents = 1;while (currents <= framenumber){char frameL[50];sprintf_s(frameL, 50, "external/l%d.bmp", i++);imageL = cv::imread(frameL);char frameR[50];sprintf_s(frameR, 50, "external/r%d.bmp", j++);imageR = cv::imread(frameR);cv::Mat rectifyImageL2, rectifyImageR2;cv::remap(imageL, rectifyImageL2, maplx, maply, cv::InterpolationFlags::INTER_LINEAR);cv::remap(imageR, rectifyImageR2, maprx, mapry, cv::InterpolationFlags::INTER_LINEAR);cv::Mat canvasPart = canvas(cv::Rect(w * 0, 0, w, h));resize(rectifyImageL2, canvasPart, canvasPart.size(), 0, 0, cv::INTER_AREA);cv::Rect vroiL(cvRound(validROIL.x * sf), cvRound(validROIL.y * sf),cvRound(validROIL.width * sf), cvRound(validROIL.height * sf));cv::rectangle(canvasPart, vroiL, cv::Scalar(0, 0, 255), 3, 8);canvasPart = canvas(cv::Rect(w, 0, w, h));resize(rectifyImageR2, canvasPart, canvasPart.size(), 0, 0, cv::INTER_LINEAR);cv::Rect vroiR(cvRound(validROIR.x * sf), cvRound(validROIR.y * sf),cvRound(validROIR.width * sf), cvRound(validROIR.height * sf));cv::rectangle(canvasPart, vroiR, cv::Scalar(0, 255, 0), 3, 8);for (int i = 0; i < canvas.rows; i += 16)line(canvas, cv::Point(0, i), cv::Point(canvas.cols, i), cv::Scalar(0, 255, 0), 1, 8);cv::imshow("rectified", canvas);if (cv::waitKey() > 0){currents++;}}return 0;
}

代码运行结果如下: 

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

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

相关文章

Python游戏开发超详细(基础理论知识篇)

一、引导&#xff1a; Python游戏开发是一个非常有趣且富有挑战性的领域。通过Python&#xff0c;你可以利用其强大的库和框架来创建各种类型的游戏&#xff0c;从简单的2D游戏到复杂的3D游戏。以下是第一课的基础理论知识&#xff0c;帮助你入门Python游戏开发。 二、理论知识…

使用Prometheus对微服务性能自定义指标监控

背景 随着云计算和容器化技术的不断发展&#xff0c;微服务架构逐渐成为现代软件开发的主流趋势。微服务架构将大型应用程序拆分成多个小型、独立的服务&#xff0c;每个服务都可以独立开发、部署和扩展。这种架构模式提高了系统的可伸缩性、灵活性和可靠性&#xff0c;但同时…

【数据结构和算法】三、动态规划原理讲解与实战演练

目录 1、什么是动态规划&#xff1f; 2、动态规划实战演练 2.1 力扣题之爬楼梯问题 &#xff08;1&#xff09;解题思路1: &#xff08;2&#xff09;解题思路2: &#xff08;3&#xff09;动态规划&#xff08;DP&#xff09;&#xff1a;解题思路 &#xff08;4&#x…

ArcGIS必会的选择要素方法(AND、OR、R、IN等)位置选择等

今天来看看ArcGIS中的几个选择的重要使用方法 1、常规选择、 2、模糊查询、 3、组合复合条件查询&#xff08;AND、OR、IN&#xff09;&#xff0c; 4、空值NULL查询 5、位置选择 推荐学习&#xff1a; 以梦为马&#xff0c;超过万名学员学习ArcGIS入门到实战的应用课程…

Pandas模块之垂直或水平交错条形图

目录 df.plot() 函数Pandas模块之垂直条形图Pandas模块之水平交错条形图 df.plot() 函数 df.plot() 是 Pandas 中的一个函数&#xff0c;用于绘制数据框中的数据。它是基于 Matplotlib 库构建的&#xff0c;可以轻松地创建各种类型的图表&#xff0c;包括折线图、柱状图、散点…

【纯血鸿蒙】专项测试工具 DevEco Testing

DevEco Testing 为生态合作伙伴接入 HarmonyOS 生态提供专业的测试服务,共筑高品质的智能硬件产品。 云端服务平台面向开发者提供724 小时的远程多终端真机实验室,提供华为专业的应用安全隐私检测,提供基于华为真机的应用自动化测试。 访问地址:https://devecostudio.huawe…

线程的互斥与同步

目录 一、互斥 1、数据不一致问题 2、锁 3、饥饿问题 4、锁的原理 5、封装锁 6、抢票逻辑中加入封装的锁 7、可重入VS线程安全 8、死锁 二、同步 1、什么是同步 2、如何实现同步 3、条件变量 4、生产消费者问题 &#xff08;1&#xff09;CP问题 &#xff08;2&am…

SLAM|2. 差异与统一:坐标系变换与外参标定

本章主要内容 1.坐标系变换 2.相机外参标定 上一章我们了解了相机内参的概念&#xff0c;内参主要解决三维世界与二维图像之间的映射关系。有了内参我们可以一定程度上还原相机看到了什么&#xff08;但缺乏尺度&#xff09;。但相机看到的数据只是处于相机坐标系&#xff0c;为…

C# Unity 同步/异步编程和多线程什么关系?async/await和coroutine又是什么?

目录 不用模板生成的目录怎么这么丑啊 1.同步&#xff1f;异步&#xff1f;多线程&#xff1f; 2.async/await和coroutine&#xff1f; 证明 单线程中的同步/异步 同 异 多线程中的同步异步 同 异 1.同步&#xff1f;异步&#xff1f;多线程&#xff1f; 首先&#…

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…

第二代 GPT-SoVITS V2:解锁语音克隆与合成的无限可能

在 AI 技术蓬勃发展的今天&#xff0c;第二代 GPT-SoVITS V2 如一颗璀璨的明星闪耀登场&#xff0c;为语音处理领域带来了前所未有的变革。它是一款集先进技术与强大功能于一身的声音克隆与语音合成工具&#xff0c;由 RVC 变声器创始人 “花儿不哭” 与 AI 音色转换技术 Sovit…

sharpkeys-键盘部分按键不好用,用其它不常用按键代替

sharpkeys-键盘部分按键不好用&#xff0c;用其它不常用按键代替 文章目录

Rust的move关键字在线程中的使用

为什么使用 move&#xff1f; 在 Rust 中&#xff0c;move 关键字主要用于闭包。当我们在一个线程中创建一个闭包并将其传递给另一个线程时&#xff0c;如果闭包中使用了某些变量&#xff0c;就需要决定这些变量的所有权归属。 不使用 move&#xff1a; 默认情况下&#xff0…

前端开发:Vue中数据绑定原理

Vue 中最大的一个特征就是数据的双向绑定&#xff0c;而这种双向绑定的形式&#xff0c;一方面表现在元数据与衍生数据之间的响应&#xff0c;另一方面表现在元数据与视图之间的响应&#xff0c;而这些响应的实现方式&#xff0c;依赖的是数据链&#xff0c;因此&#xff0c;要…

Pytorch与深度学习 #10.PyTorch训练好的模型如何部署到Tensorflow环境中

1. Tensorflow vs Pytorch 在这个AI时代&#xff0c;各大厂商都在主推自家的AI框架&#xff0c;因此知名和不知名的大大小小可能十来种。但是我们选型的时候&#xff0c;一般首先考虑是Google家的Tensorflow呢还是Meta家的Pytorch。 在选择 PyTorch 或 TensorFlow 进行工业级…

苏州金龙技术创新赋能旅游新质生产力

2024年10月23日&#xff0c;备受瞩目的“2024第六届旅游出行大会”在云南省丽江市正式开幕。作为客车行业新质生产力标杆客车&#xff0c;苏州金龙在大会期间现场展示了新V系V12商旅版、V11和V8E纯电车型&#xff0c;为旅游出行提供全新升级方案。 其中&#xff0c;全新15座V1…

【vue 全家桶】1、vue 基础(更新中)

目录 Vue 核心Vue 简介模板语法插值语法 {{}}指令语法 v- 数据绑定单向数据绑定 v-bind双向数据绑定 v-model MVVM模型事件处理计算属性与监视class 与 style 绑定条件渲染列表渲染收集表单数据过滤器内置指令与自定义指令Vue 实例生命周期 Vue 组件化编程模块与组件、模块化与…

Python | Leetcode Python题解之第508题出现次数最多的子树元素和

题目&#xff1a; 题解&#xff1a; class Solution:def findFrequentTreeSum(self, root: TreeNode) -> List[int]:cnt Counter()def dfs(node: TreeNode) -> int:if node is None:return 0sum node.val dfs(node.left) dfs(node.right)cnt[sum] 1return sumdfs(r…

【linux】服务器Ubuntu20.04安装cuda11.8教程

【linux】服务器Ubuntu20.04安装cuda11.8教程 文章目录 【linux】服务器Ubuntu20.04安装cuda11.8教程到官网找到对应版本下载链接终端操作cudnn安装到官网下载下载后解压进入解压后的目录&#xff1a;将头文件复制到 /usr/local/cuda/include/ 目录&#xff1a;将库文件复制到 …

语音语言模型最新综述! 关于GPT-4o背后技术的尝试

近期,大型语言模型(LLMs)在生成文本和执行各种自然语言处理任务方面展现出了卓越的能力,成为了强大的AI驱动语言理解和生成的基础模型。然而&#xff0c;仅依赖于基于文本模态的模型存在显著局限性。这促使了基于语音的生成模型的发展,使其能够更自然、直观地与人类互动。 为了…