单目标定:OpenCV4实现单目标定及矫正
1 程序环境
系统环境:Windows 10;
编译器:Visual Studio 2015;
Opencv版本:Opencv4.1.2版本;
2 原理
主要为张正友标定法,利用棋盘格进行标定,原理参考:https://www.cnblogs.com/zyly/p/9366080.html.
3 程序源码
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;/*计算标定板上模块的实际物理坐标*/
void calobjectPoints(vector<Point3f>& obj, Size &boardSize, int squareSize)
{for (int i = 0; i < boardSize.height; ++i)for (int j = 0; j < boardSize.width; ++j)obj.push_back(Point3f((float)(j*squareSize), (float)(i*squareSize), 0.f));
}void main()
{Size boardSize = Size(8, 6); // 标定棋盘格的内角点尺寸(如7x7)float squareSize = 30.0; // 标定板上黑白格子的实际边长(mm)int nrFrames = 18; // 用于标定的图像数目string outputFileName; // 输出文件的名称vector<string> imageList;Size imageSize;/****************将存放标定图像的路径读入到imageList(1/2)向量中****************/char name[100];for (int i = 1; i <= nrFrames; i++){sprintf_s(name, "../Picture/%d%s", i, ".bmp");imageList.push_back(name);}cout << "imageList.size:" << imageList.size() << endl;/****************标定前的准备工作:获取objectPoints和imagePoints*********************///1 首先根据squareSize(棋盘格的实际边长,比如20mm)和boardSize(棋盘格的角点数,比如5x5),利用for循环得到角点的世界坐标objectPoints(Z坐标假设为0)//2 利用for循环和findChessboardCorners()函数得到与角点世界坐标向量objectPoints对应的图像像素坐标向量imagePointsvector<vector<Point2f> > imagePoints;//各个图像找到的角点的集合vector<vector<Point3f> > objectPoints(1);//暂时先定义一维的objectPoints1,等确定了imagePoints的维数之后再进行扩容calobjectPoints(objectPoints[0], boardSize, squareSize);//数据初始化,否则标定函数会报错bool displayCorners1 = true;//可通过改变变量displayCorners1的值来确定是否展示获取角点后的图像for (int i = 0; i<imageList.size(); i++){Mat src1 = imread(imageList[i], 1);imageSize = src1.size();vector<Point2f> pointBuf1;//2读取角点并进行亚像素,并提取角点bool found1 = findChessboardCorners(src1, boardSize, pointBuf1);//使用不同方法进行棋盘格查找,不同方法标定结果差别很小//若是圆盘标定板,使用如下函数//bool found1 = findCirclesGrid(src1, boardSize, pointBuf1);if (found1){Mat grayimage1;cvtColor(src1, grayimage1, COLOR_BGR2GRAY);//亚像素角点检测,输出 pointBuf1cornerSubPix(grayimage1, pointBuf1, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1));imagePoints.push_back(pointBuf1);if (displayCorners1){Mat MidImage1 = src1.clone();//画角点drawChessboardCorners(MidImage1, boardSize, Mat(pointBuf1), found1);imshow("相机角点获取情况", MidImage1);waitKey(300);}}}destroyWindow("相机角点获取情况");//利用resize()函数对objectPoints向量进行扩容objectPoints.resize(imagePoints.size(), objectPoints[0]);/********************************进行相机标定******************************************///通过calibrateCamera()函数进行相机标定//主要为了得到相机的内参矩阵cameraMatrix、畸变系数矩阵distCoeffs//另外可以通过函数返回的重投影误差大小评价相机标定的精度如何//这里得到的相机外参矩阵不重要Mat cameraMatrix = Mat::eye(3, 3, CV_64F);Mat distCoeffs = Mat::zeros(5, 1, CV_64F);//畸变系数的顺序是[k1,k2,p1,p2,k3]vector<Mat> rvecs, tvecs;/*calibrateCamera()输入参数 objectPoints 角点的实际物理坐标imagePoints 角点的图像坐标imageSize 图像的大小输出参数cameraMatrix 相机的内参矩阵distCoeffs 相机的畸变参数,畸变系数的顺序是[k1,k2,p1,p2,k3]rvecs 旋转矢量(外参数)tvecs 平移矢量(外参数)*///如果我们不需要K3,在初始化K3为O之后,可以使用标志CV_CALIB_FIX_K3,这样,标定函数不会改变K3的值//一般地,K3应设置为0,除非使用鱼眼镜头(参考《learning opencv》第十一章)//返回的distCoeffs1向量的长度由标志位flag决定,当flag设置为CV_CALIB_RATIONAL_MODEL时返回所有畸变参数(8个)//当设置成其他flag时都返回5维的畸变系数,即[k1,k2,p1,p2,k3]std::cout << "正在进行相机标定..." << endl;double re_project_err1 = calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs,CALIB_FIX_K3);//checkRange()函数---用于检查矩阵中的每一个元素的有效性bool ok1 = checkRange(cameraMatrix) && checkRange(distCoeffs);if (ok1){cout << "相机标定成功!" << endl;cout << "相机标定的重投影误差:" << re_project_err1 << endl;cout<<"相机内参矩阵:"<<endl<<cameraMatrix<<endl;cout<<"相机畸变系数矩阵:"<<endl<<distCoeffs<<endl;}bool showUndistorsed = true;if(showUndistorsed==true){for(int i=0;i<imageList.size();i++){Mat temp=imread(imageList[i],1);;//利用undistort()函数得到经过畸变矫正的图像Mat undistort_view;undistort(temp, undistort_view, cameraMatrix, distCoeffs);imshow("原畸变图像",temp);imshow("畸变矫正图像",undistort_view);waitKey(300);}waitKey(0);destroyAllWindows();}return;
}
4程序运行结果
4.1 标定过程
4.2 矫正结果
4.3 程序输出
imageList.size:18
正在进行相机标定...
相机标定成功!
相机标定的重投影误差:0.23798
相机内参矩阵:
[644.5700972013594, 0, 642.8375612362015;0, 645.8354258462127, 364.0228582907439;0, 0, 1]
相机畸变系数矩阵:
[0.002553038122538741;-0.0001313912440763992;-0.0002960299077962415;-0.001097115527929319;0]
(若能帮到读者,请关注+点赞,谢谢!)
单目标定:OpenCV4实现单目标定及矫正相关推荐
- 项目实战——基于计算机视觉的物体位姿定位及机械臂抓取(单目标定)
项目实战--基于计算机视觉的物体位姿定位及机械臂抓取(单目标定) 请各位读者朋友注意,这里面很多东西涉及到我的毕设,写作辛苦,请勿滥用,转载请务必注明出处! 单目标定主要分为两个部分, ...
- 【研究报告】从单目深度估计到单目三维场景重建-沈春华老师-VALSE Webinar 22-13(总第279期)
从单目深度估计到单目三维场景重建-沈春华老师-VALSE Webinar 22-13(总第279期) 报告总结 & 相关论文 论文代码 相关术语 前言 研究问题 单目深度估计 单目三维场景重建 ...
- 双目标定(一)单目标定与矫正的基本介绍
1.单目相机标定 首先,任何标定都是用基于小孔模型的数学模型去近似相机模型,我们需要用fx = f/dx, fy = f/dy,图像坐标系中的光心原点坐标(和可能的缩放因子ks)这5个相机内参数,切向 ...
- 双目测距(一)--图像获取与单目标定
原文: http://blog.csdn.net/chenyusiyuan/article/details/5961769 双目测距的基本原理 如上图所示,双目测距主要是利用了目标点在左右两幅视图上成 ...
- 任务感知单目深度估计的3D目标检测
标题:Task-Aware Monocular Depth Estimation for 3D Object Detection 作者:Xinlong Wang1∗, Wei Yin1, Tao Ko ...
- MO-LTR:基于单目RGB视频的多目标定位、跟踪与重建
点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 标题:MO-LTR: Multiple Object Localization, Tracking a ...
- Opencv单目标定flag的设定
1. flag中的标签顺序: 在代码中的对应如下: enum{CALIB_USE_INTRINSIC_GUESS = 1 << 0,CALIB_RECOMPUTE_EXTRINSIC = ...
- Opencv 单目标定
参考博客:https://blog.csdn.net/xuelabizp/article/details/50314633(该作者很慷慨的分享了代码) 多图与公式直接摘录自以上博客 参考:学习Open ...
- Halcon 单目标定,畸变矫正,图像坐标系转世界坐标系
代码为Halcon代码,只有代码以及解释,默认已经理解世界坐标系(WCS)到相机坐标系(CCS)到图像坐标系(ICS)到像素坐标系(PCS)转换 *********************1. 标定内 ...
- cv::omni::StereoCalibrate 源码解析 (一) —— 单目标定
cv::omni::StereoCalibrate 的代码逻辑和cv::StereoCalibrate相似. 在opencv库基础上稍微改动. //omni单目标定 输入calibrate(世界坐标系 ...
最新文章
- 拿haojava官方过程
- GT Transceiver的复位与初始化(2)CPLL复位以及QPLL复位
- VMprotect简介
- Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照
- linux | 网卡驱动
- 96. 不同的二叉搜索树
- 无聊的一天_一人互联网公司背后的无聊技术
- 漫话:如何给女朋友解释什么是2PC(二阶段提交)?
- 半小时让你快速入门linux掌握基础命令
- notepad 配置python_Notepad++配置Python开发环境的图文详解
- jQuery EasyUI教程之datagrid应用-1
- Android自定义View研究(六)--View中的原点坐标相关问题
- Module build failed: Error: Couldn't find preset react relative to directory
- orangepizero编译ch934x驱动
- 关于R语言多水平线性回归分析
- buuctf—荷兰宽带数据泄露
- 记一次cocos逆向
- “2019-04-25T16:00:00.000+000”时间格式转换 (IE兼容问题)
- Java基础篇--多线程之第一个线程用来计算2~100000之间的素数的个数,第二个线程用来计算100000~200000之间的素数的个数
- 微信小程序 pages的使用