//闲话先不说,直接上一段完整源码
#include "opencv2/core.hpp"
#include
#include "opencv2/imgproc.hpp"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/videoio.hpp"
#include "opencv2/highgui.hpp"
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
static double computeReprojectionErrors(
const vector<vector<Point3f> >& objectPoints,
const vector<vector<Point2f> >& imagePoints,
const vector<Mat>& rvecs, const vector<Mat>& tvecs,
const Mat& cameraMatrix, const Mat& distCoeffs
)
{
vector<Point2f> imagePoints2;
int i, totalPoints = 0;
double totalErr = 0, err;
for (i = 0; i < (int)objectPoints.size(); i++)
{
projectPoints(Mat(objectPoints[i]), rvecs[i], tvecs[i],
cameraMatrix, distCoeffs, imagePoints2);
err = norm(Mat(imagePoints[i]), Mat(imagePoints2), NORM_L2);
int n = (int)objectPoints[i].size();
totalErr += err*err;
totalPoints += n;
}
return std::sqrt(totalErr / totalPoints);
}
int main(int argc, char** argv)
{
vector<string> files;
glob("E:\\images", files);
// 定义变量
vector<vector<Point2f>> imagePoints;//像点
vector<vector<Point3f>> objectPoints;//物点
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.001);//进行亚像素精度的调整,获得亚像素级别的角点坐标
int numCornersHor = 7;//heigh
int numCornersVer = 9;//width
int numSquares = 13;//单位mm
vector<Point3f> obj;
//存放每张图的角点坐标,并存入obj中(物点)
for (int i = 0; i < numCornersHor; i++)
for (int j = 0; j < numCornersVer; j++)
obj.push_back(Point3f((float)j * numSquares, (float)i * numSquares, 0));
//发现与绘制棋盘格
//遍历每张图片
Size s;
//像点
for (int i = 0; i < files.size(); i++) {
printf("image file : %s \n", files[i].c_str());
Mat image = imread(files[i]);
s = image.size();
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);//转灰度
vector<Point2f> corners;
bool ret = findChessboardCorners(gray, Size(9, 7), corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FILTER_QUADS);//该函数的功能就是判断图像内是否包含完整的棋盘图,若能检测完全,就把他们的角点坐标(从上到下,从左到右)记录,并返回true,否则为false,CALIB_CB_FILTER_QUADS用于去除检测到的错误方块。
if (ret) {
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);//用于发现亚像素精度的角点位置
drawChessboardCorners(image, Size(9, 7), corners, ret);//将每一个角点出做标记,此为物点对应的像点坐标
imagePoints.push_back(corners);//将角点坐标存入imagePoints中,此为像点坐标
objectPoints.push_back(obj);//把存放在每张图的所有角点坐标,存在objectPoints中,物点坐标
//imshow("calibration-demo", image);
waitKey(500);
}
}
//计算内参与畸变系数
Mat intrinsic = Mat(3, 3, CV_32FC1);
Mat distCoeffs;//畸变矩阵
vector<Mat> rvecs;//旋转向量R
vector<Mat> tvecs;//平移向量T
//内参矩阵
intrinsic.ptr<float>(0)[0] = 1;
intrinsic.ptr<float>(1)[1] = 1;
calibrateCamera(objectPoints, imagePoints, s, intrinsic, distCoeffs, rvecs, tvecs);
FileStorage fs("E:\\images\\out_calibration.yml", FileStorage::WRITE);//存储标定结果,这里可以选择自己的存放路径
fs << "intrinsic" << intrinsic;//存放内参矩阵
fs << "distCoeffs" << distCoeffs;//存放畸变矩阵
fs << "board_width" << 9;//存放标定板长度信息
fs << "board_height" << 7;//存放标定板宽度信息
fs << "square_size" << 0.013;//存放标定板格子尺寸信息
fs << "R" << rvecs;//R
fs << "T" << tvecs;//T
printf("Done Calibration\n");
cout << "Calibration error: " << computeReprojectionErrors(objectPoints, imagePoints, rvecs, tvecs, intrinsic, distCoeffs) << endl;//输出投影的误差
//Mat intrinsic,distCoeffs= calibration();
//校正图像
Mat dst;
Mat image = imread("E:\\images\\cal 13.jpg");
undistort(image, dst, intrinsic, distCoeffs);
imshow("image", image);
imshow("undistort image", dst);
waitKey(10000);
}
//相信不少人看晕了,别怕分段讲解
1.首先定义一些容器,存放物点,像点。这两个点极为重要,通过他们的映射关系找到内参矩阵
2.TermCriteria 亚像素级别角点检测与findChessboardCorners()配合使用
vector<string> files;
glob("E:\\images", files);
// 定义变量
vector<vector<Point2f>> imagePoints;//像点
vector<vector<Point3f>> objectPoints;//物点
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.001);//进行亚像素精度的调整,获得亚像素级别的角点坐标
3.最重要的两个for 循环:找到像点,物点。并用pushback()将其存到容器中。
//找到物点
//存放每张图的角点坐标,并存入obj中(物点)
for (int i = 0; i < numCornersHor; i++)
for (int j = 0; j < numCornersVer; j++)
obj.push_back(Point3f((float)j * numSquares, (float)i * numSquares, 0));
//找到像点
for (int i = 0; i < files.size(); i++) {
printf("image file : %s \n", files[i].c_str());
Mat image = imread(files[i]);
s = image.size();
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);//转灰度
vector<Point2f> corners;
bool ret = findChessboardCorners(gray, Size(9, 7), corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FILTER_QUADS);//该函数的功能就是判断图像内是否包含完整的棋盘图,若能检测完全,就把他们的角点坐标(从上到下,从左到右)记录,并返回true,否则为false,CALIB_CB_FILTER_QUADS用于去除检测到的错误方块。
if (ret) {
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);//用于发现亚像素精度的角点位置
drawChessboardCorners(image, Size(9, 7), corners, ret);//将每一个角点出做标记,此为物点对应的像点坐标
imagePoints.push_back(corners);//将角点坐标存入imagePoints中,此为像点坐标
objectPoints.push_back(obj);//把存放在每张图的所有角点坐标,存在objectPoints中,物点坐标
//imshow("calibration-demo", image);
4.calibrationCamera()标定相机(R,T,内参,畸变矩阵).
//输入就是像点,物点,图像尺寸
calibrateCamera(objectPoints, imagePoints, s, intrinsic, distCoeffs, rvecs, tvecs);
5.给大家列入需要自行更改的API:
//glob("E:\\images", files); 输入自己图像路径
,注意是\
6.校正图像
//undistort函数,输入内参和畸变矩阵
Mat dst;
Mat image = imread("E:\\images\\cal 13.jpg");
undistort(image, dst, intrinsic, distCoeffs);
imshow("image", image);
imshow("undistort image", dst);
waitKey(10000);