3.鱼眼摄像机纠正,相机纠偏,详细源码及讲解
保持奋斗的连续性,你将无坚不摧!!!!
1.棋盘格制作c++,相机纠正
2.图片获取,相机纠正
做好棋盘格,进行相机纠偏。纠偏原理,网上一堆直接查。直接上代码。
//运行环境 VS2019+opencv3.4.10 已测试 VS2015+opencv3.2已测试
// time:2021.6.28
#include <opencv2\opencv.hpp>
#include <fstream>
using namespace std;
using namespace cv;int main()
{ofstream fout("caliberation_result.txt"); /** 保存定标结果的文件 **//************************************************************************读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化*************************************************************************/cout << "开始提取角点………………" << endl;int image_count = 14; /**** 图像数量 ****/Size board_size = Size(5, 7); /**** 定标板上每行、列的角点数 ****/vector<Point2f> corners; /**** 缓存每幅图像上检测到的角点 ****/vector<vector<Point2f>> corners_Seq; /**** 保存检测到的所有角点 ****/vector<Mat> image_Seq;int successImageNum = 0; /**** 成功提取角点的棋盘图数量 ****/int count = 0;for (int i = 0; i != image_count; i++){cout << "Frame #" << i + 1 << "..." << endl;string imageFileName;std::stringstream StrStm;StrStm << i + 1;StrStm >> imageFileName;imageFileName += ".jpg";cv::Mat image = imread(imageFileName);if (image.empty()){std::cout << "no photo....\n";return -1;}/* 提取角点 */Mat imageGray;cvtColor(image, imageGray, CV_BGR2GRAY);bool patternfound = findChessboardCorners(image, board_size, corners, CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE +CALIB_CB_FAST_CHECK);if (!patternfound){cout << "找不到角点,需删除图片文件" << imageFileName << "重新排列文件名,再次标定" << endl;getchar();exit(1);}else{/* 亚像素精确化 */cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));/* 绘制检测到的角点并保存 */Mat imageTemp = image.clone();for (int j = 0; j < corners.size(); j++){circle(imageTemp, corners[j], 10, Scalar(0, 0, 255), 2, 8, 0);}string imageFileName;std::stringstream StrStm;StrStm << i + 1;StrStm >> imageFileName;imageFileName += "_corner.jpg";imwrite(imageFileName, imageTemp);cout << "Frame corner#" << i + 1 << "...end" << endl;count = count + corners.size();successImageNum = successImageNum + 1;corners_Seq.push_back(corners);}image_Seq.push_back(image);}cout << "角点提取完成!\n";/************************************************************************摄像机定标*************************************************************************/cout << "开始定标………………" << endl;Size square_size = Size(20, 20);vector<vector<Point3f>> object_Points; /**** 保存定标板上角点的三维坐标 ****/Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0)); /***** 保存提取的所有角点 *****/vector<int> point_counts;/* 初始化定标板上角点的三维坐标 */for (int t = 0; t < successImageNum; t++){vector<Point3f> tempPointSet;for (int i = 0; i < board_size.height; i++){for (int j = 0; j < board_size.width; j++){/* 假设定标板放在世界坐标系中z=0的平面上 */Point3f tempPoint;tempPoint.x = j * square_size.width;tempPoint.y = i * square_size.height;tempPoint.z = 0;tempPointSet.push_back(tempPoint);}}object_Points.push_back(tempPointSet);}for (int i = 0; i < successImageNum; i++){point_counts.push_back(board_size.width * board_size.height);}/* 开始定标 */Size image_size = image_Seq[0].size();cv::Matx33d intrinsic_matrix; /***** 摄像机内参数矩阵 ****/cv::Vec4d distortion_coeffs; /* 摄像机的4个畸变系数:k1,k2,k3,k4*/std::vector<cv::Vec3d> rotation_vectors; /* 每幅图像的旋转向量 */std::vector<cv::Vec3d> translation_vectors; /* 每幅图像的平移向量 */int flags = 0;flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;flags |= cv::fisheye::CALIB_CHECK_COND;flags |= cv::fisheye::CALIB_FIX_SKEW;fisheye::calibrate(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, flags, cv::TermCriteria(3, 20, 1e-6));cout << "定标完成!\n";/************************************************************************对定标结果进行评价*************************************************************************/cout << "开始评价定标结果………………" << endl;double total_err = 0.0; /* 所有图像的平均误差的总和 */double err = 0.0; /* 每幅图像的平均误差 */vector<Point2f> image_points2; /**** 保存重新计算得到的投影点 ****/cout << "每幅图像的定标误差:" << endl;cout << "每幅图像的定标误差:" << endl << endl;for (int i = 0; i < image_count; i++){vector<Point3f> tempPointSet = object_Points[i];/**** 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 ****/fisheye::projectPoints(tempPointSet, image_points2, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs);/* 计算新的投影点和旧的投影点之间的误差*/vector<Point2f> tempImagePoint = corners_Seq[i];Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);for (size_t i = 0; i != tempImagePoint.size(); i++){image_points2Mat.at<Vec2f>(0, i) = Vec2f(image_points2[i].x, image_points2[i].y);tempImagePointMat.at<Vec2f>(0, i) = Vec2f(tempImagePoint[i].x, tempImagePoint[i].y);}err = norm(image_points2Mat, tempImagePointMat, NORM_L2);total_err += err /= point_counts[i];cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;}cout << "总体平均误差:" << total_err / image_count << "像素" << endl;fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;cout << "评价完成!" << endl;/************************************************************************保存定标结果*************************************************************************/cout << "开始保存定标结果………………" << endl;Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */fout << "相机内参数矩阵:" << endl;fout << intrinsic_matrix << endl;fout << "畸变系数:\n";fout << distortion_coeffs << endl;for (int i = 0; i < image_count; i++){fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;fout << rotation_vectors[i] << endl;/* 将旋转向量转换为相对应的旋转矩阵 */Rodrigues(rotation_vectors[i], rotation_matrix);fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;fout << rotation_matrix << endl;fout << "第" << i + 1 << "幅图像的平移向量:" << endl;fout << translation_vectors[i] << endl;}cout << "完成保存" << endl;fout << endl;/************************************************************************显示定标结果*************************************************************************/Mat mapx = Mat(image_size, CV_32FC1);Mat mapy = Mat(image_size, CV_32FC1);Mat R = Mat::eye(3, 3, CV_32F);cout << "保存矫正图像" << endl;for (int i = 0; i != image_count; i++){cout << "Frame #" << i + 1 << "..." << endl;//fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,intrinsic_matrix,image_size,CV_32FC1,mapx,mapy);fisheye::initUndistortRectifyMap(intrinsic_matrix, distortion_coeffs, R,getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0), image_size, CV_32FC1, mapx, mapy);Mat t = image_Seq[i].clone();cv::remap(image_Seq[i], t, mapx, mapy, INTER_LINEAR);string imageFileName;std::stringstream StrStm;StrStm << i + 1;StrStm >> imageFileName;imageFileName += "_d.jpg";imwrite(imageFileName, t);}cout << "保存结束" << endl;/************************************************************************测试一张图片*************************************************************************/if (1){//cout<<"TestImage ..."<<endl;//Mat testImage = imread("a.jpg",1);//fisheye::initUndistortRectifyMap(intrinsic_matrix,distortion_coeffs,R,// getOptimalNewCameraMatrix(intrinsic_matrix, distortion_coeffs, image_size, 1, image_size, 0),image_size,CV_32FC1,mapx,mapy);//Mat t = testImage.clone();//cv::remap(testImage,t,mapx, mapy, INTER_LINEAR);//imwrite("TestOutput.jpg",t);//cout<<"保存结束"<<endl;cout << "TestImage ..." << endl;Mat distort_img = imread("a.jpg", 1);Mat undistort_img;Mat intrinsic_mat(intrinsic_matrix), new_intrinsic_mat;intrinsic_mat.copyTo(new_intrinsic_mat);//调节视场大小,乘的系数越小视场越大new_intrinsic_mat.at<double>(0, 0) *= 0.5;new_intrinsic_mat.at<double>(1, 1) *= 0.5;//调节校正图中心,建议置于校正图中心new_intrinsic_mat.at<double>(0, 2) = 0.5 * distort_img.cols;new_intrinsic_mat.at<double>(1, 2) = 0.5 * distort_img.rows;fisheye::undistortImage(distort_img, undistort_img, intrinsic_matrix, distortion_coeffs, new_intrinsic_mat);imwrite("output.jpg", undistort_img);cout << "保存结束" << endl;}return 0;
}
原图:
效果图。
根据自己的视场角实际调整。该纠偏后图片还是有点问题,可以进一步调整,得到更加效果。
3.鱼眼摄像机纠正,相机纠偏,详细源码及讲解相关推荐
- Cesium 键盘鼠标控制相机漫游(源码+原理讲解)
Cesium 键盘鼠标控制相机漫游(源码+原理讲解) 在各大博客平台上,Cesium使用键盘控制相机漫游的源码已经有不少人贴出源码,本人在浏览这些源码的过程中发现大家采用的方式基本一致,大部分代码都是 ...
- 双目相机标定OpenCV源码讲解
双目相机标定OpenCV源码讲解 背景介绍 所述内容 参考资料 摄像机标定部分代码 代码思路 代码中的其他函数 找角点&求内参 求外参 求矫正映射矩阵 后记 背景介绍 暑假接近两个月的时间做了 ...
- 基于stm32、0.96寸OLED实现的贪吃蛇小游戏(详细源码注释)
简介:本实验基于stm32最小系统.0.96寸OLED(68*128)和摇杆实现一个经典的贪吃蛇小游戏.项目源码地址:点击下载. 硬件设计: 普通摇杆,0.96寸OLED 单色屏幕(SPI协议通讯), ...
- 基于stm32、0.96寸OLED实现的俄罗斯方块小游戏(详细源码注释)
概述:本实验基于stm32最小系统.0.96寸OLED(68*128)和摇杆实现一个经典的俄罗斯方块小游戏.项目源码地址:点击下载. 硬件要求: 普通摇杆,两个电位器和一个开关组成,左右摇动控制一个电 ...
- 实战|Python轻松实现动态网页爬虫(附详细源码)
用浅显易懂的语言分享爬虫.数据分析及可视化等干货,希望人人都能学到新知识. 项目背景 事情是这样的,前几天我公众号写了篇爬虫入门的实战文章,叫做<实战|手把手教你用Python爬虫(附详细源码) ...
- JUC.Condition学习笔记[附详细源码解析]
JUC.Condition学习笔记[附详细源码解析] 目录 Condition的概念 大体实现流程 I.初始化状态 II.await()操作 III.signal()操作 3个主要方法 Conditi ...
- android 自定义相机源码,Android 自定义相机及分析源码
Android 自定义相机及分析源码 使用Android 系统相机的方法: 要想让应用有相机的action,咱们就必须在清单文件中做一些声明,好让系统知道,如下 action的作用就是声明action ...
- set在python中的用法_python中set的用法:详细源码示例
这篇文章主要为大家详细介绍了python中set的用法:详细源码示例,具有一定的参考价值,可以用来参考一下. set函数基本用法感兴趣的小伙伴,下面一起跟随512笔记的小编罗X来看看吧. python ...
- beautifulsoup解析动态页面div未展开_实战|Python轻松实现动态网页爬虫(附详细源码)...
用浅显易懂的语言分享爬虫.数据分析及可视化等干货,希望人人都能学到新知识.项目背景事情是这样的,前几天我公众号写了篇爬虫入门的实战文章,叫做<实战|手把手教你用Python爬虫(附详细源码)&g ...
最新文章
- 还是自己写的东西比较放心
- jexus php 重写,如何让我们的PHP在Jexus中跑起来
- 【c++】0.C++笔记
- 【小白学PyTorch】15.TF2实现一个简单的服装分类任务
- Java获取并输出两日期间的所有日期 .
- SQLSERVER和ORACLE批量处理表名和字段名大写
- java future用法_纯干货:Java学习过程中的21个知识点和技术点
- 奥鹏计算机基础18秋在线作业答案,18秋华师《计算机基础》在线作业1(标准答案).doc...
- Qt工作笔记-主界面往模式对话框emit信号,有注意的问题
- matlab中LMI工具箱函数feasp的用法
- NHibernate Profiler使用方法
- dell 重装linux系统_U盘装系统开机按哪个键
- 中文搜索引擎技术揭密-网络蜘蛛
- 画java类图_java UML类图的使用
- 从零开始学习SLAM
- Rap2 模拟接口 常见规则示例
- vray许可服务器信息无名,【1人回答】vray3.6无法获取许可-3D溜溜网
- python复杂网络点图可视化_数据分析:R与Python怎么选?
- 安装Tomcat步骤
- Docker理论与实践(三)
热门文章
- 关于Android百度地图API步骑行导航引擎初始化失败以及View空指针异常的问题
- flutter 发送验证码
- html如何实现立体效果,纯css实现立体摆放图片效果的示例代码
- 在此计算机中找不到cad,在此计算机上找不到AutoCAD201x,你需要安装AutoCAD201x才可以安装此语言包CAD安装失败解决方法...
- Surv单因素批量生存分析使用 cox批量生存回归分析有点像deseq2的design差异分析designG:\r\2021_1203_geo\GEO-master\GSE11121_survival
- uvaoj 11121 Base -2 整数转成负数进制
- uva 11121(-2进制)
- 列表排序并返回索引_Python成为专业人士笔记–List列表
- Tensorflow2.0 复现 NNLM
- 【Java】Java学习笔记(2)——Java面向对象基础作业函数题