opencv_c++学习(二十七)
一、单目相机模型

上图为针孔相机成像原理,蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。

单目相机映射关系如下:

将上式进行变换,就可以从三位空间映射到2维平面的公式。

相机的畸变公式如下:

二、模型投影函数
void cv:projectPoints ( InputArray objectPoints, InputArray rvec, InputArray tvec, InputArray cameraMatrix,InputArray distCoeffs,outputArray imagePolints, jacobian =, OutputArray naArray(), double aspectRatio = 0)
objectPoints:世界坐标系中3D点的三维坐标。
rvec:世界坐标系变换到相机坐标系的旋转向量。
tvec:世界坐标系变换到相机坐标系的平移向量。
cameraMatrix:相机的内参矩阵。
distCoeffs:相机的畸变系数矩阵。
imagcPoints:三维坐标点在像素坐标系中估计的坐标。
jacobian:可选输出的雅可比矩阵。
aspectRatio:是否固定“宽高比”参数标志。
本节应用案例如下:
int main() {//输入计算的内参矩阵和畸变矩阵(在相机厂家说明或者标定获得)Mat cameraMatrix = (Mat_<float>(3, 3) << 532.016297, 0, 332.172519,0, 531.565159, 233.388075,0, 0, 1);Mat distCoeffs = (Mat_<float>(1, 5) << -0.285188, 0.080097, 0.001274,0.002415, 0.106579);//图像相机坐标系与世界坐标系之间的关系Mat rvec = (Mat_<float>(1, 3) << -1.977853, -2.002220, 0.130029);Mat tvec = (Mat_<float>(1, 3) << -26.88155, -42.79936, 159.19703);//生成第一张图像中内角点的三位世界坐标Size boardSize = Size(9,6);//棋盘格每个方格的真实尺寸Size squareSize = Size(10, 10);vector<Point3f> PointSets;for (int j = 0; j < boardSize.height; j++){for (int k = 0; k < boardSize.width; k++){Point3f realPoint;//假设标定板为世界坐标系的Z平面,及z=0realPoint.x = j * squareSize.width;realPoint.y = k * squareSize.height;realPoint.z = 0;PointSets.push_back(realPoint);}}//根据三维坐标和相机与世界坐标系时间的关系估计内角点像素坐标vector<Point2f> imagePoints;projectPoints(PointSets, rvec, tvec, cameraMatrix, distCoeffs, imagePoints);for (int i = 0; i < imagePoints.size(); i++){cout << imagePoints[i] << endl;}waitKey(0);return 0;}
三、单目相机标定
标定原理:

从上图中可以看出,相机坐标系可以通过世界坐标系进行平移变换来得到。具体的变换矩阵如相机坐标系右侧的公式。
标定板的图例如下:

上图中为两种类型的标定板,左侧为常用标定板,在提取的时候是内角点。而右侧标定板中不存在内角点,所以我们提取的是每个圆的中心点。
内角点提取函数如下:
bool cv:.findChessboardCorners ( InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORNALIZE_IPAGE)
image:含有棋盘标定板的图像,图像必须是CV_8U的灰度图像或者彩色图像。
patternSize:图像中棋盘内角点行数和列数
corners:检测到的角点坐标
flags:检测角点方式的标志
圆形标定板中心提取:
bool cv::findCirclesGrid ( InputArray image, Size patternSize, OutputArray centers, int flags, const Ptr< FeatureDetector > & blolbDetector, const CirclesGridFinderParameters & parameters)
image:输入含有圆形网格的图像,图像必须是CV_8U的灰度图像或者彩色图像。
patternSize:图像中每行和每列圆形的数目。
corners:输出的圆形中心坐标。
flags:检测圆心的操作标志。
blobDetector:在浅色背景中寻找黑色圆形斑点的特征探测器。
角点位置优化函数:
bool cv.find4QuadCornerSubpix ( InputArray img, InputOutputArray corners, size region_size)
img:计算出内角点的图像。
patternSize:内角点坐标。
corners:优化坐标时考虑的邻域范围。
绘制内角点提取的结果:
void cv::drawChessboardCorners ( InputOutputArray image, size patternSize, InputArray corners, bool patternWasFound)
image:需要绘制角点的目标图像,必须是CU_8U的彩色图像。patternSize:标定板每行和每列角点的数目。
corners:检测到的角点坐标数组。
pattern WasFound:是否显示找到完成的标定板标志。
相机标定函数:
double cv::calibrateCamera ( InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,Size imageSize, InputOutputArray cameraMatrix, InputoutputArray distCoeffs, OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,int flags = 0, TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30,DBL_EPSILON)
objectPoints:棋盘格内角点的三维坐标。
imagePoints:棋盘格内角点在图像中的二维坐标。
imageSize:图像的像素尺寸大小。
cameraMatrix:相机的内参矩阵。
distCoeffs:相机的畸变系数矩阵。
rvecs:相机坐标系与世界坐标系之间的旋转向量。
tvecs:相机坐标系与世界坐标系之间的平移向量。
flags:选择标定算法的标志。
本节应用案例如下:
本案例中采用了两张标定板的提取图像:


并将两个图片的路径存放到ca.txt文件中

int main() {//读取图像vector<Mat>imgs;string imgName;//读取存放图片路径的txt文件ifstream fin("ca.txt");//挨个读取图片while(getline(fin, imgName)){Mat img = imread(imgName);imgs.push_back(img);}//方格标定板内角点的数目(行,列)Size board_size = Size(9, 6);//存放内角点坐标vector<vector<Point2f>> imgsPoints;//开始内角点提取for (int i = 0; i < imgs.size(); i++){Mat img1 = imgs[i];Mat gray1;cvtColor(img1, gray1, COLOR_BGR2GRAY);vector<Point2f> img1_points;//计算标定板的角点findChessboardCorners(gray1, board_size, img1_points);//细化方格标定板角点坐标find4QuadCornerSubpix(gray1, img1_points, Size(5, 5));bool pattern = true;drawChessboardCorners(img1, board_size, img1_points, pattern);namedWindow("img1", WINDOW_NORMAL);imshow("img1", img1);waitKey(0);imgsPoints.push_back(img1_points);}//生成每个内角点的空间坐标Size squareSize = Size(10, 10);vector<vector<Point3f>> objectPoints;for (int i = 0; i < imgsPoints.size(); i++){vector<Point3f> tempPointSet;for (int j = 0; j < board_size.height; j++){for (int k = 0; k < board_size.width; k++){Point3f realPoint;//设标定板为世界坐标系的z平面,即z=0realPoint.x = j * squareSize.width;realPoint.y = k * squareSize.height;realPoint.z = 0;tempPointSet.push_back(realPoint);}}objectPoints.push_back(tempPointSet);}//图像尺寸Size imageSize;imageSize.width = imgs[0].cols;imageSize.height = imgs[0].rows;//摄像机内参数矩阵Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0));//摄像机的5个畸变系数:k1,k2,p1,p2,k3Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0));//每幅图像的旋转向量、平移量vector<Mat> rvecs, tvecs;calibrateCamera(objectPoints, imgsPoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs, 0);cout << "相机的内参矩阵:" << cameraMatrix << endl;cout << "相机畸变系数:" << distCoeffs << endl;waitKey(0);return 0;
}
最终的运行结果如下图:

这里只放一张图像。最终的输出结果为:
相机的内参矩阵:[120.8643306554273, 0, 94.55565247064737;0, 119.979406894919, 55.48571212317609;0, 0, 1]
相机畸变系数:[-0.5559208449775317, 3.15840209023594, -0.001816753642197531, -0.01817901488786, -7.629569308066959]
四、图像矫正

如上图(左)可以看出,相机采集的数据造成了一定的畸变,尤其是在边缘部分。
去畸变函数:
void cv::undistort ( InputArray src, OutputArray dst, InputArray cameraMatrix, InputArray distCoeffs, InputArray newCameraMatrix = noArray())
src:含有畸变的输入图像。
dst:去畸变后的输出图像,与输入图像具有相同的尺寸和数据类型。
cameraMatrix:相机内参矩阵(上节中相机标定获得)。
distCoeffis:相机的畸变矩阵,根据近似模型不同,参数数量可以为4、5、8、12或者14,如果是空矩阵表示没有畸变。
newCameraMatrix:畸变图像的相机内参矩阵,一般情况下与第三个参数相同或者使用默认值。
本节应用案例如下:
//用undiststort()函数直接计算校正图像
void undist(vector<Mat> imgs, //原有图像向量Mat cameraMatrix, //计算得到的相机内存Mat distCoeffs, //计算得到的相机畸变系数vector<Mat> &undistImgs //校正后的输出图像
)
{for (int i = 0; i < imgs.size(); i++){Mat undisImg;undistort(imgs[i], undistImgs, cameraMatrix, distCoeffs);undistImgs.push_back(undisImg);}
}int main() {//读取图像vector<Mat>imgs;string imgName;//读取存放图片路径的txt文件ifstream fin("ca.txt");//挨个读取图片while (getline(fin, imgName)){Mat img = imread(imgName);imgs.push_back(img);}//输入计算的内参矩阵和畸变矩阵(在相机厂家说明或者标定获得)Mat cameraMatrix = (Mat_<float>(3, 3) << 120.8643306554273, 0, 94.55565247064737,0, 119.979406894919, 55.48571212317609,0, 0, 1);Mat distCoeffs = (Mat_<float>(1, 5) << -0.5559208449775317, 3.15840209023594, -0.001816753642197531, -0.01817901488786, -7.629569308066959);//去畸变图像存放变量vector<Mat> undistImags;Size imageSize;imageSize.width = imgs[0].cols;imageSize.height = imgs[0].rows;undist(imgs, cameraMatrix, distCoeffs, undistImags);//显示校正后的图像for (int i = 0; i < imgs.size(); i++){string windowNumber = to_string(i);imshow("矫正后的图像" + windowNumber, undistImags[i]);waitKey(0);destroyWindow("矫正后的图像" + windowNumber);}waitKey(0);return 0;
}
相关文章:
opencv_c++学习(二十七)
一、单目相机模型 上图为针孔相机成像原理,蓝色坐标中的O即为镜头光心。成像原理与小孔成像相同。 单目相机映射关系如下: 将上式进行变换,就可以从三位空间映射到2维平面的公式。 相机的畸变公式如下: 二、模型投影函数 vo…...
探查chatGPT插件:Outschool,resume,webhooks
引言 在我们的日常工作和学习中,插件扮演着重要的角色。它们可以帮助我们提高效率,简化复杂的任务。在这篇文章中,我将介绍三个非常有用的插件:Outschool,resume,和webhooks,并通过具体的例子来…...
【学习笔记】Unity基础(七)【uGUI基础、利用render Texture实现小地图功能】
目录 一 Canvas1.1 三种Render Space渲染空间 screen1.2 canvas scaler画布缩放器1.3sprite1.4 sprite packer1.5 unity目录1.6 RuleTile Tilemap1.7 sprite packer1.8 sorting layer 二 rect transform2.1 pivot 中轴 中心点2.2 anchor 锚点2.3 uGUI源代码 三 EventSystem3.1 …...
yolov5配置错误记录
这里是直接没有找到数据集,说明是路径错误。经过设置yaml后, # Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..] path: ../autodl-tmp/datasets/neu # dataset root dir tr…...
全平台数据 (数据库) 管理工具 DataCap 1.10.0 发布
当前版本涉及几个主要更新。 DataCap 已发布 发布版本发布时间1.10.02023-05-30 General 修复服务启动默认连接 mongo修复了 sql 模板的 h2 db update_time 和 create_time改进 H2 元数据管理获取类型改进 mysql 元数据管理获取类型固定元数据管理数据页默认为 1重构数据渲染…...
使用Mybatis接口开发
文章目录 目录 前言 公司项目用到了mybatis开发接口,虽然很简单,但是mybatis不是特别熟悉,这里学习一下 一、Mybatis接口绑定的两种方式 1.接口绑定实现方式 就是在接口的方法上加上Select,updateInsertDelete等注解 select注解介绍: 简便,能快速去操作sql,它只需要在mapper…...
数据采集技术的实现原理有哪些?
数据采集技术是指通过各种手段和技术手段,从互联网、移动设备、传感器等各种数据源中获取数据,并将其存储、处理和分析,以便为业务决策和应用提供支持。本文将介绍数据采集技术的实现原理,包括数据采集的基本流程、数据采集技术的…...
2023年数学建模随机森林:基于多个决策树的集成学习方法
2023年9月数学建模国赛期间提供ABCDE题思路加Matlab代码,专栏链接(赛前一个月恢复源码199,欢迎大家订阅):http://t.csdn.cn/Um9Zd 目录 目录 1. 什么是随机森林? 2. 随机森林的优缺点 3. 随机森林的构建过程...
OpenAI发布最新研究让大模型数学推理直接达到SOTA
🦉 AI新闻 🚀 OpenAI发布最新研究:基于过程奖励的监督方法,让大模型数学推理直接达到SOTA 摘要:OpenAI最新研究基于GPT-4微调,采用过程监督和结果监督两种监督方法,奖励每个正确推理步骤的过程…...
快速检测 GlassFish 任意文件读取漏洞的 Python 脚本
部分数据来源:ChatGPT 引言 当下,互联网安全问题正愈发严重,黑客利用各种漏洞进行攻击的频率也在持续增加。在2015年10月,一位名为“路人甲”的安全研究员在乌云上公开了一个名为“应用服务器glassfish存在通用任意文件读取漏洞”的漏洞(编号:wooyun-2010-0144595),该…...
Docker镜像更新通知器DIUN
什么是 DIUN ? Docker Image Update Notifier 是一个用 Go 编写的 CLI 应用程序,可作为单个可执行文件和 Docker 映像交付,用于当 Docker 映像在 Docker registry中更新时接收通知。 和老苏之前介绍过的 watchtower 不同,DIUN 只是通知&…...
插件框架PF4J-从理论到实践
PF4J:Plugin Framework for Java 目录 是什么? 不是什么? 特点 组件 主要类 流程概述 spring-pf4j 思考 功能模块化 我对pf4j的封装和使用demo GitHub - chlInGithub/pf4jDemo: pf4j demo 是什么? 开源轻量级的插件框架。通过插件…...
怎么将pdf文件免费转为扫描件
推荐两个工具,也算是给自己记一下 1、手机:扫描全能王APP 太好使了,可以直接拍照并转换为扫描件 不开会员的话会出现水印,因为我都是自己用或者交作业就没开 支持读取相册,一次一张、多张都可以 如果不想要水印也…...
vue+nodejs校园二手物品交易市场网站_xa1i4
。为满足如今日益复杂的管理需求,各类管理系统程序也在不断改进。本课题所设计的校园二手交易市场,使用vue框架,Mysql数据库、nodejs语言进行开发,它的优点代码不能从浏览器查看,保密性非常好,比其他的管理…...
Barra模型因子的构建及应用系列六之Book-to-Price因子
一、摘要 在前期的Barra模型系列文章中,我们构建了Size因子、Beta因子、Momentum因子、Residual Volatility因子和NonLinear Size因子,并分别创建了对应的单因子策略,其中Size因子和NonLinear Siz因子具有很强的收益能力。本节文章将在该系列…...
【c语言习题】使用链表解决约瑟夫问题
创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡>𖥦<)!! 主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步! 🔥c语言系列专栏:c语言之路重点知识整合 &#x…...
JVM之类的初始化与类加载机制
类的初始化 clinit 初始化阶段就是执行类构造器方法clinit的过程。此方法不需定义,是javac编译器自动收集类中的所有类变量的赋值动作和静态代码块中的语句合并而来。构造器方法中指令按语句在源文件中出现的顺序执行。clinit不同于类的构造器。(关联:…...
面试专题:java 多线程(1)----synchronized关键字相关问答
在java 多线程 面试中最多问题1.悲观锁和乐观锁;2.synchronized和lock的区别;3.可重入锁和非可重入锁的区别;4.多线程是解决什么问题的;5.线程池解决什么问题的;6.线程池原理;7.线程池使用注意事项…...
VMware SD-WAN 5.2 发布 - 软件定义的 WAN
VMware SD-WAN 5.2 发布 - 软件定义的 WAN SD-WAN 解决方案的领导者 请访问原文链接:https://sysin.org/blog/vmware-sd-wan-5/,查看最新版。原创作品,转载请保留出处。 作者主页:sysin.org 产品概述 软件定义的 WAN (SD-WAN)…...
Oracle+11g+RAC+PSU_EAM(2)
2.15 解压安装介质 在获取开篇1.2节中提到的安装介质如下: [rootebsrac1 ~]# ls -l -rw-r–r– 1 root root 1358454646 Apr 20 16:22 p13390677_112040_Linux-x86-64_1of7.zip -rw-r–r– 1 root root 1142195302 Apr 20 16:29 p13390677_112040_Linux-x86-64_…...
超短脉冲激光自聚焦效应
前言与目录 强激光引起自聚焦效应机理 超短脉冲激光在脆性材料内部加工时引起的自聚焦效应,这是一种非线性光学现象,主要涉及光学克尔效应和材料的非线性光学特性。 自聚焦效应可以产生局部的强光场,对材料产生非线性响应,可能…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
day36-多路IO复用
一、基本概念 (服务器多客户端模型) 定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力 作用:应用程序通常需要处理来自多条事件流中的事件,比如我现在用的电脑,需要同时处理键盘鼠标…...
作为测试我们应该关注redis哪些方面
1、功能测试 数据结构操作:验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化:测试aof和aof持久化机制,确保数据在开启后正确恢复。 事务:检查事务的原子性和回滚机制。 发布订阅:确保消息正确传递。 2、性…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
