流程:
//1.找多副棋盘格图像角点,存入2D图像点及3D坐标点
//2.进行相机标定 获取标定参数:相机矩阵 畸变矩阵 旋转向量和平移向量
//3.映射相应矩阵 获取x y映射函数 (像高hi/物高h0=焦距f/物距d0)
//4.应用映射函数,输出未畸变图像
main 函数:
#include <QCoreApplication>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp> //引用cv::KeyPoint 特征检测器通用接口
# include <opencv2/calib3d/calib3d.hpp>
//#include <opencv2/legacy/legacy.hpp> //引用cv::cornerSubPix()
#include "CameraCalibrator.h"
#include <iostream>
#include <iomanip>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//2.使用CameraCalibritor类对图像进行矫正
//cv::Mat image = cv::imread("../../aTestImage/chessboards/chessboard01.jpg", 0);
//cv::namedWindow("Image");
cv::Mat image;
std::vector<std::string> filelist ; //????初始化
for (int i = 1; i <= 20; i++)//将指定文件夹中20张图片添加到filelist中
{
std::stringstream str;
str << "../TestPic/chessboards/chessboard" << std::setw(2) << std::setfill('0') << i << ".jpg";
std::cout << str.str() << std::endl;
filelist.push_back(str.str());
image = cv::imread(str.str(), 0);
//cv::imshow("Image", image);
//cv::waitKey(100);
}
CameraCalibrator calibr;
cv::Size boardSize(6, 4);
calibr.addChessboardPoints(filelist, boardSize);:imread( filelist[0]);
cv::Size cvsize =cv::Size(320,240);
//指定标定文件夹 标定尺寸
//image =cv: calibr.calibrate(cvsize); //进行标定image.size()
image =cv::imread( filelist[11]);
cv::Mat result = calibr.remap(image); //进行矫正
cv::namedWindow("image"); //显示src
cv::imshow("image", image);
cv::namedWindow("result"); //显示结果
cv::imshow("result", result);
cv::waitKey(0);
return a.exec();
}
CameraCalibrator.h 头文件:
#pragma once
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/features2d/features2d.hpp> //引用cv::KeyPoint 特征检测器通用接口
#include <opencv2/imgproc/imgproc.hpp>
# include <opencv2/calib3d/calib3d.hpp>
//#include <opencv2/legacy/legacy.hpp> //引用cv::cornerSubPix()
class CameraCalibrator
{
public:
CameraCalibrator() ;
~CameraCalibrator();
//提取 文件中各个图像 指定数目 棋盘格角点
int addChessboardPoints(const std::vector<std::string>&filelist, cv::Size &boardSize);
//添加角点到2D图像点和3D场景点坐标系中
void addPoints(const std::vector<cv::Point2f> &imageCorners, const std::vector<cv::Point3f> &objectCorners);
//进行标定,并返回投影误差(相机矩阵,畸变矩阵,旋转向量,平移向量)
double calibrate(cv::Size &imageSize);
//标定后去除图像中的畸变
cv::Mat remap(const cv::Mat &image);
private:
std::vector< std::vector<cv::Point3f> >objectPoints; //存储世界坐标点
std::vector< std::vector<cv::Point2f> >imagePoints; //存储像素坐标点
cv::Mat cameraMatrix; //输出相机矩阵
cv::Mat distCoeffs; //输出畸变矩阵
int flag; //标定方式
cv::Mat map1, map2; //去图像畸变的x y 映射函数
bool mustInitUndistort; //是否初始化失真
};
CameraCalibrator.cpp:
#include "CameraCalibrator.h"
//#include <opencv2/core/core.hpp>
//#include <opencv2/highgui/highgui.hpp>
//#include <opencv2/features2d/features2d.hpp> //引用cv::KeyPoint 特征检测器通用接口
//# include <opencv2/calib3d/calib3d.hpp>
//#include <opencv2/legacy/legacy.hpp> //引用cv::cornerSubPix()
CameraCalibrator::CameraCalibrator()
{
flag=0;
mustInitUndistort=true;
}
CameraCalibrator::~CameraCalibrator()
{
}
int CameraCalibrator::addChessboardPoints(const std::vector<std::string>& filelist, cv::Size & boardSize)
{
std::vector< cv::Point2f> imageCorners; //对应图像上(i, j)棋盘格角点
std::vector< cv::Point3f> objectCorners; //对应世界坐标系(X,Y,Z)棋盘格角点
//获取3D场景中的点
for (int i = 0; i < boardSize.height; i++)
{
for (int j = 0; j < boardSize.width; j++)
{
objectCorners.push_back(cv::Point3f(i, j, 0.0f));
}
}
//获取2D图像中的点
cv::Mat image;
int successes = 0;
for (int i = 0; i < filelist.size(); i++)
{
image = cv::imread(filelist[i], 0);
bool found = cv::findChessboardCorners(image, boardSize, imageCorners); //获取棋盘格角点 ?? under VS "block type is valid"
// cv::cornerSubPix(image, imageCorners, cv::Size(5, 5), cv::Size(-1, -1), //获取亚像素精度
// cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 30, 0.1)); //终止条件为迭代30次或达到精度0.1
if (imageCorners.size() == boardSize.area())
{
addPoints(imageCorners, objectCorners);
successes++;
}
}
return successes; //block type is valid
}
void CameraCalibrator::addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners)
{
imagePoints.push_back(imageCorners);
objectPoints.push_back(objectCorners);
}
double CameraCalibrator::calibrate(cv::Size &imageSize)
{
mustInitUndistort = true; //必须重新去畸变
std::vector<cv::Mat> rvecs, tvecs; //输出旋转向量和平移向量
return calibrateCamera(objectPoints,imagePoints,imageSize,cameraMatrix,distCoeffs,rvecs,tvecs,flag);
}
cv::Mat CameraCalibrator::remap(const cv::Mat & image)
{
cv::Mat undistorted; //未畸变图像
if (mustInitUndistort)
{
//初始化未畸变矫正映射图像(相机矩阵,畸变矩阵,可选矫正矩阵,生成的未畸变相机矩阵,生成的未畸变相机矩阵的尺寸,输出的映射图像类型,X坐标映射函数,Y坐标映射函数)
cv::initUndistortRectifyMap(cameraMatrix, distCoeffs, cv::Mat(), cv::Mat(),cv::Size(320,240), CV_32FC1, map1, map2);
mustInitUndistort = false;
}
cv::remap(image, undistorted, map1, map2,cv::INTER_LINEAR); //应用映射函数,输出未畸变图像 | 差值类型
return undistorted;
}