什么是相机标定的内外参:
一文带你搞懂相机内参外参(Intrinsics & Extrinsics) - 知乎Yanjie Ze, July 14 2021 摘要:本文介绍了相机的内参和外参以及推导过程,由三个部分组成:第一部分,相机内参; 第二部分,相机外参;第三部分,总结。 1 相机内参在左图中,我们把相机看作是针孔,现实世界中的…https://zhuanlan.zhihu.com/p/389653208相机标定的畸变以及张正友标定法:相机标定的基本原理与经验分享_哔哩哔哩_bilibili收到3D视觉工坊公众号的邀请做了一次分享,这是20200322直播的录播视频,讲解了相机标定的基本原理和我的一些实战经验分享,对于刚入门的同学会有很大的帮助。时间较长,但是干货满满。第一次讲公开课比较紧张,也是连续讲了有100分钟,可能有时候口胡,请多见谅啦。如果有任何意见和建议,可以在弹幕和评论区友善交流。, 视频播放量 32705、弹幕量 362、点赞数 707、投硬币枚数 516、收藏人数 2035、转发人数 181, 视频作者 fighterpilot0, 作者简介 机械工程博士 分享专业知识与兴趣爱好,相关视频:3.1 相机标定的基本概念,三维重建第七课:相机标定代码讲解,【计算机视觉】相机标定/双目测距/Camera Calibration,单目相机标定总结及实战,双相机标定及计算,【3D视觉工坊】第二期公开课:相机标定的基本原理与经验分享,【相机入门01】用珍珠奶茶理解光圈快门ISO,5分钟学会摄影曝光基础,【20分钟搞懂】数码相机全部参数!!!快门、光圈、iso、景深、虚化、躁点、高感、底大和底小的各自优势等等,基于深度学习的垃圾分类【保姆级教程】,相机标定之带你推张正友标定方法https://www.bilibili.com/video/BV1eE411c7kr/?spm_id_from=333.337.search-card.all.click&vd_source=a8464fe2c290cfb1b1ac3c3bd4733ad2
1. 拍摄棋盘格各个角度十几二十张图像;
2. openCV函数findChessboardCorners(image,patternSize,corners,flags = None)提取角点,其 中参数image表示输入图,pattenSize为棋盘格内角点每行每列个数,corners检测到的角点输 出保存数组。
3. 步骤2提取的整数坐标角点是不精确的,需要进行亚像素精确化,采用openCV函数 cornerSubPix(image,corners,winSize,zeroZone,criteria),image:输入;corners:角点数 组,既是输入也是输出;winSize:计算亚像素点时考虑的范围;zeroSize:类似于winSize, 但是总是具有较小的范围,通常忽略(即Size(-1, -1));criteria停止优化的标准。
4. 初始化标定板上的三维坐标,假设标定板放在世界坐标系的z=0的平面上。
5. 利用openCV函数calibrateCamera(object_points, image_points_seq, image_size, cameraMatrix, distCoeffs, rvecsMat, tvecsMat, 0)进行标定,其中1. object_points标定板上角 点三维坐标; 2. image_points_seq检测到的角点; 3.image_size图像尺寸; 4. cameraMatrix内参矩阵 5.distCoeffs五个畸变系数k1,k2,k3,p1,p2;6. rvecsMat平移向量; 7. tvecsMat旋转向量,可以得到旋转矩阵。
相机标定的目的是矫正畸变以及后续的场景重建(双目相机标定)。
// zhang's method.cpp: 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include
#include
#include
using namespace cv;
using namespace std;
void main()
{
ifstream fin("calibdata.txt"); /* 标定所用图像文件的路径 */
ofstream fout("caliberation_result.txt"); /* 保存标定结果的文件 */
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
cout << "开始提取角点………………";
int image_count = 0; /* 图像数量 */
Size image_size; /* 图像的尺寸 */
Size board_size = Size(9, 6); /* 标定板上每行、列的角点数 */
vector image_points_buf; /* 缓存每幅图像上检测到的角点 */
vector> image_points_seq; /* 保存检测到的所有角点 */
string filename;
int count = 0;//用于存储角点个数。
while (getline(fin, filename))
{
image_count++;
// 用于观察检验输出
cout << "image_count = " << image_count << endl;
//cout << "-->count = " << count< 第 " << j << "图片的数据 --> : " << endl;
}
if (0 == ii % 3) // 此判断语句,格式化输出,便于控制台查看
{
cout << endl;
}
else
{
cout.width(10);
}
//输出所有图片的第一个角点
cout << " -->" << image_points_seq[ii][0].x;
cout << " -->" << image_points_seq[ii][0].y;
}
cout << "角点提取完成!\n";
//以下是摄像机标定
cout << "开始标定………………";
/*棋盘三维信息*/
Size square_size = Size(10, 10); /* 实际测量得到的标定板上每个棋盘格的大小 */
vector> object_points; /* 保存标定板上角点的三维坐标 */
/*内外参数*/
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 摄像机内参数矩阵 */
vector point_counts; // 每幅图像中角点的数量
Mat distCoeffs = Mat(1, 5, CV_32FC1, Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2 */
vector tvecsMat; /* 每幅图像的旋转向量 */
vector rvecsMat; /* 每幅图像的平移向量 */
/* 初始化标定板上角点的三维坐标 */
int i, j, t;
for (t = 0; t tempPointSet;
for (i = 0; i image_points2; /* 保存重新计算得到的投影点 */
cout << "\t每幅图像的标定误差:\n";
fout << "每幅图像的标定误差:\n";
for (i = 0; i tempPointSet = object_points[i];
/* 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 */
projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoeffs, image_points2);
/* 计算新的投影点和旧的投影点之间的误差*/
vector tempImagePoint = image_points_seq[i];
Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
for (int j = 0; j < tempImagePoint.size(); j++)
{
image_points2Mat.at(0, j) = Vec2f(image_points2[j].x, image_points2[j].y);
tempImagePointMat.at(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
}
err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
total_err += err /= point_counts[i];
std::cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
}
std::cout << "总体平均误差:" << total_err / image_count << "像素" << endl;
fout << "总体平均误差:" << total_err / image_count << "像素" << endl << endl;
std::cout << "评价完成!" << endl;
//保存定标结果
std::cout << "开始保存定标结果………………" << endl;
Mat rotation_matrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */
fout << "相机内参数矩阵:" << endl;
fout << cameraMatrix << endl << endl;
fout << "畸变系数:\n";
fout << distCoeffs << endl << endl << endl;
for (int i = 0; i> imageFileName;
filePath += imageFileName;
filePath += ".jpg";
//获取图片路径
Mat imageSource = imread(filePath);//读取图像
Mat newimage = imageSource.clone();//拷贝图像
remap(imageSource, newimage, mapx, mapy, INTER_LINEAR);//把求得的映射应用到图像上
//与initUndistortRectifyMap结合使用,为矫正方法之一
//undistort(imageSource,newimage,cameraMatrix,distCoeffs);//矫正方法二
//第五个参数newCameraMatrix=noArray(),默认跟cameraMatrix保持一致,故可省
imageFileName += "_d.jpg";//矫正后图片命名
imwrite(imageFileName, newimage);//保存矫正后的图片
imshow("Original Image", imageSource);
waitKey(500);//暂停0.5s
imshow("Undistorted Image",newimage);
waitKey(500);
}
fin.close();
fout.close();
getchar();//等待输入以退出
return;
}