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;
}
代码运行结果如下:
相关文章:

OpenCV双目相机外参标定C++
基于OpenCV库实现双目测量系统外参标定过程。通过分析双目测量系统左右相机拍摄的棋盘格标定板图像,包括角点检测、立体标定、立体校正和畸变校正的步骤,获取左右相机的相对位置关系和姿态。 a.检测每张图像中的棋盘格角点,并进行亚像素级精…...

【GESP】C++一级练习BCQM3055,4位数间隔输出
一级知识点取余、整除运算和格式化输出知识点应用。其实也可以用string去处理,那就属于GESP三级的知识点范畴了,孩子暂未涉及。 题目题解详见:https://www.coderli.com/gesp-1-bcqm3055/ https://www.coderli.com/gesp-1-bcqm3055/https://w…...

纯血鸿蒙的最难时刻才开始
关注卢松松,会经常给你分享一些我的经验和观点。 纯血鸿蒙(HarmonyOS NEXT)也正式发布了,绝对是一个历史性时刻,但最难的鸿蒙第二个阶段,也就是生态圈的建设,才刚刚开始。 目前,我劝你现在不要升级到鸿蒙…...
记一个mysql的坑
数据库表user, 存在一个name字段,字段为varchar类型 现在user表有这么两条记录: idnameageclass1NULL18一班2lisi20二班 假如我根据下面这一条件去更新,更新成功数据行显示为0 update user set age 19 where age 18 and class “一班”…...
Java中的设计模式:单例模式详解
摘要 单例模式(Singleton Pattern)是Java中最常用的设计模式之一,属于创建型模式。它的主要目的是确保一个类在系统中只有一个实例,并提供一个全局访问点来访问该实例。 1. 单例模式的定义 单例模式确保一个类只有一个实例&…...

NanoTrack原理与转tensorrt推理
文章目录 前言一、NanoTrack 工作原理二、运行demo与转换tensorrt模型2.1 运行pt模型demo2.2 转onnx模型2.3 转tensorrt模型2.4 运行trt模型推理 三、推理速度对比总结 前言 NanoTrack 是一种轻量级且高效的目标跟踪算法,基于Siamese网络架构,旨在在资源…...

YOLO11改进 | 卷积模块 | 卷积模块替换为选择性内核SKConv【附完整代码一键运行】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 本文给大家带来的教程是将YOLO11的卷积替…...

CentOS进入单用户模式进行密码重置
一、单用户模式介绍 单用户模式是一种特殊的启动模式,主要用于系统维护和故障排除。在单用户模式下,系统以最小化的状态启动,只有最基本的系统服务会被加载,通常只有root用户可以登录。这种模式提供了对系统的完全控制࿰…...
bitpoke- mysql-operator cluster
sidecar版本只支持到8.0.35,35可以支持到mysql8.0.35 . 默认镜像是5.7的。需要自己打sidecar的镜像: # Docker image for sidecar containers # https://github.com/bitpoke/mysql-operator/tree/master/images/mysql-operator-sidecar-8.0 # 参考5…...
第5课 基本数据类型
一、数据类型的诞生 在Python的世界里,万物皆对象,每个对象都有自己的若干属性,每一个属性都能描述对象的某一个方面。就像我们每个人,都有自己的身高、年龄、姓名、性别等很多方面的信息,这里的身高、年龄、姓名、性…...

OceanBase 首席科学家阳振坤:大模型时代的数据库思考
2024年 OceanBase 年度大会 即将于10月23日,在北京举行。 欢迎到现场了解更多“SQL AI ” 的探讨与分享! 近期,2024年金融业数据库技术大会在北京圆满举行,聚焦“大模型时代下数据库的创新发展”议题,汇聚了国内外众多…...
国内知名的几个镜像源
在国内,有许多常用的Python库镜像源可以帮助加速库的下载。以下是几个知名的镜像源: 1. 清华大学TUNA协会 网址: https://pypi.tuna.tsinghua.edu.cn/simple命令示例:pip install numpy --index-url https://pypi.tuna.tsinghua.edu.cn/simple2. 阿里云…...

海外著名新闻门户媒体软文发稿之华盛顿独立报-大舍传媒
在当今全球化的时代,信息传播的速度和范围达到了前所未有的程度。对于企业和个人而言,如何在国际舞台上有效地展示自己、传递信息,成为了一项至关重要的任务。而海外媒体发稿,特别是通过像华盛顿独立报这样的知名新闻门户…...
青少年编程与数学 02-002 Sql Server 数据库应用 13课题、函数的编写
青少年编程与数学 02-002 Sql Server 数据库应用 13课题、函数的编写 课题摘要:一、函数内置函数用户定义的函数 (User-Defined Functions, UDFs)使用示例主要特点 二、内置函数数学函数(Mathematical Functions)字符串函数(String Functions…...

关于LaTeX的floatrow包导入后标题无法直接放到浮动体上方
排版一个文章,标题怎么弄都弄不到表格上方,经过阅读帮助文档才发现问题。又是一个坑。 标题位置控制 使用floatrow包之后,类似 \begin{table}[htbp]\caption{xxx。}\label{table1}\centering\begin{tabular}{lcccc}\toprule& \multicol…...

Flutter Image和Text图文组件实战案例
In this section, we’ll go through the process of building a user interface that showcases a product using the Text and Image widgets. We’ll follow Flutter’s best practices to ensure a clean and effective UI structure. 在本节中,我们将使用“Te…...
使用 xlrd 和 xlwt 库进行 Excel 文件操作
使用 xlrd 和 xlwt 库进行 Excel 文件操作 在数据分析和处理的过程中,Excel 文件是最常用的数据存储格式之一。Python 提供了多种库来处理 Excel 文件,其中 xlrd 和 xlwt 是两个经典的库,分别用于读取和写入 Excel 文件。本文将详细介绍如何使用这两个库进行 Excel 文件的操…...
03.04、化栈为队
03.04、化栈为队 1、题目描述 实现一个 MyQueue 类,该类用两个栈来实现一个队列。 2、解题思路 本题要求使用两个栈来实现一个队列。队列遵循先进先出(FIFO)的原则,而栈遵循后进先出(LIFO)的原则。因此…...

Coppelia Sim (v-REP)仿真 机器人3D相机手眼标定与实时视觉追踪 (二)
coppelia sim[V-REP]仿真实现 机器人于3D相机手眼标定与实时视觉追踪 二 zmq API接口python调用python获取3D相机的数据获取彩色相机的数据获取深度相机的数据用matpolit显示 python控制机器人运动直接控制轴的位置用IK运动学直接移动到末端姿态 相机内参的标定记录拍照点的位置…...

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

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

Qt/C++开发监控GB28181系统/取流协议/同时支持udp/tcp被动/tcp主动
一、前言说明 在2011版本的gb28181协议中,拉取视频流只要求udp方式,从2016开始要求新增支持tcp被动和tcp主动两种方式,udp理论上会丢包的,所以实际使用过程可能会出现画面花屏的情况,而tcp肯定不丢包,起码…...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...

【VLNs篇】07:NavRL—在动态环境中学习安全飞行
项目内容论文标题NavRL: 在动态环境中学习安全飞行 (NavRL: Learning Safe Flight in Dynamic Environments)核心问题解决无人机在包含静态和动态障碍物的复杂环境中进行安全、高效自主导航的挑战,克服传统方法和现有强化学习方法的局限性。核心算法基于近端策略优化…...

R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...