opencv相机标定(可输出内参、畸变系数和外参)

#include <iostream>
#include <iomanip>
#include <vector>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/features2d.hpp>
#include "opencv2/calib3d.hpp"
using namespace std;
using namespace cv;

//将相机标定过程封装到CameraCalibrator类中
class CameraCalibrator {
private:
	// 输入点:
	// 世界坐标系中的点
	//(每个正方形为一个单位)
	std::vector<std::vector<cv::Point3f>> objectPoints;
	// 点在图像中的位置(以像素为单位)
	std::vector<std::vector<cv::Point2f>> imagePoints;
	// 输出矩阵
	cv::Mat cameraMatrix;//相机矩阵
	cv::Mat distCoeffs;//畸变系数摄像机的5个畸变系数,(k1,k2,p1,p2[,k3[,k4,k5,k6]])
	// 输出旋转量和平移量
	std::vector<cv::Mat> rvecs, tvecs;
	//x 和y 映射功能
	Mat map1;
	Mat map2;
	// 指定标定方式的标志
	int flag;
	bool mustInitUndistort;
	//保存点数据
	void addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners)
	{
		//一个视图中的二维图像
		imagePoints.push_back(imageCorners);
		// 对应的三维场景点
		objectPoints.push_back(objectCorners);
	}
public:
	CameraCalibrator() :flag(0), mustInitUndistort(true) {}
	// 打开棋盘图像,提取角点
	int addChessboardPoints(
		const std::vector<std::string> & filelist1, // 文件名列表
		cv::Size & boardSize)
	{ // 标定面板的大小
		// 棋盘上的角点
		std::vector<cv::Point2f> imageCorners;
		std::vector<cv::Point3f> objectCorners;
		// 场景中的三维点:
		// 在棋盘坐标系中,初始化棋盘中的角点
		// 角点的三维坐标(X,Y,Z)= (i,j,0)
		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));
			}
		}
		// 图像上的二维点:
		cv::Mat image; // 用于存储棋盘图像
		int successes = 0;
		// 处理所有视角
		for (int i = 1; i <filelist1.size(); i++) {
			// 打开图像
			image = cv::imread(filelist1[i], 0);
			// 取得棋盘中的角点
			bool found = cv::findChessboardCorners(
				image, // 包含棋盘图案的图像
				boardSize, // 图案的大小
				imageCorners); // 检测到角点的列表
				// 取得角点上的亚像素级精度
			if (found) {
				cv::cornerSubPix(image, imageCorners,
					cv::Size(5, 5), // 搜索窗口的半径
					cv::Size(-1, -1),
					cv::TermCriteria(cv::TermCriteria::MAX_ITER +
						cv::TermCriteria::EPS, 30, // 最大迭代次数
						0.1)); // 最小精度
						// 如果棋盘是完好的,就把它加入结果
				if (imageCorners.size() == boardSize.area()) {
					// 加入从同一个视角得到的图像和场景点
					addPoints(imageCorners, objectCorners);
					successes++;
				}
			}
			//画出角点
			cv::drawChessboardCorners(image, boardSize, imageCorners, found);
			cv::imshow("Corners on Chessboard", image);
			cv::waitKey(100);
		}
		return successes;
	}

	// 标定相机
// 返回重投影误差
	double calibrate(const cv::Size &imageSize) {
		mustInitUndistort = true;
		
		// 开始标定
		return
calibrateCamera(objectPoints, // 三维点
				imagePoints, // 图像点
				imageSize, // 图像尺寸
				cameraMatrix, // 输出相机矩阵
				distCoeffs, // 输出畸变矩阵
				rvecs, tvecs, // Rs、Ts(外参)
				flag); // 设置选项
	
	}
	// 去除图像中的畸变(标定后)
	cv::Mat remap(const cv::Mat &image) {
		cv::Mat undistorted;
		if (mustInitUndistort) { // 每个标定过程调用一次
			cv::initUndistortRectifyMap(
				cameraMatrix, // 计算得到的相机矩阵
				distCoeffs, // 计算得到的畸变矩阵
				cv::Mat(), // 可选矫正项(无)
				cv::Mat(), // 生成无畸变的相机矩阵
				image.size(), // 无畸变图像的尺寸
				CV_32FC1, // 输出图片的类型
				map1, map2); // x 和y 映射功能
			mustInitUndistort = false;
		}
		// 应用映射功能
		cv::remap(image, undistorted, map1, map2,
			cv::INTER_LINEAR); // 插值类型
		return undistorted;
	}
	void setCalibrationFlag(bool radial8CoeffEnabled, bool tangentialParamEnabled) {

		// Set the flag used in cv::calibrateCamera()
		flag = 0;
		if (!tangentialParamEnabled) flag += CV_CALIB_ZERO_TANGENT_DIST;//设定切向畸变参数(p1,p2)为零。 
		if (radial8CoeffEnabled) flag += CV_CALIB_RATIONAL_MODEL;//计算k4,k5,k6三个畸变参数。如果没有设置,则只计算其它5个畸变参数。标定函数使用倾斜传感器模型并返回14个系数
	}
	// 常成员函数,获得相机内参数矩阵、投影矩阵数据
	cv::Mat getCameraMatrix() const{ return cameraMatrix; }
	cv::Mat getDistCoeffs() const{ return distCoeffs; }
	std::vector<cv::Mat> getrvecs() { return rvecs; }
	std::vector<cv::Mat> gettvecs() { return tvecs; }
};
//主程序
int main()
{
	cv::Mat image;
	vector<string> filelist;//vector是容器

	// 生成棋盘图像文件名列表
	// 命名棋盘01至棋盘27棋盘子目录
	for (int i = 0; i <20; i++) {

		std::stringstream str;//批量读取图片
		str << "D:\\vs2017project\\ConsoleApplication1\\ConsoleApplication1\\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("Board Image", image);
		cv::waitKey(100);
		
	}
	// 创造标定对象
	CameraCalibrator cameraCalibrator;
	// 在棋盘中标记角点
	cv::Size boardSize(6, 4);
	cameraCalibrator.addChessboardPoints(
		filelist,	// 棋盘图像的文件名
		boardSize);	// 棋盘大小

	// 标定相机
	cameraCalibrator.setCalibrationFlag(false,true);
	cameraCalibrator.calibrate(image.size());
	Mat rotation_matrix;
	std::vector<cv::Mat> rvecs1 = cameraCalibrator.getrvecs();
	std::vector<cv::Mat> tvecs1 = cameraCalibrator.gettvecs();
	//输出外参
	for (int i = 0; i < 19; i++)
	{
		
		cout << "第" << i+1 << "幅图像的旋转向量:" << endl;
		cout << rvecs1[i] << endl;
		Rodrigues(rvecs1[i], rotation_matrix);
		cout << "第" << i+1 << "幅图像的旋转矩阵:" << endl;
		cout << rotation_matrix << endl;
		
		cout << "第" << i+1 << "幅图像的平移向量:" << endl;
		cout << tvecs1[i] << endl;

	}
		
	//图像失真举例
	Mat image1 = cv::imread(filelist[14], 0);
	cv::Size newSize(static_cast<int>(image1.cols*1.5), static_cast<int>(image1.rows*1.5));
	cv::Mat uImage = cameraCalibrator.remap(image1);

	// 显示摄像机矩阵
	cv::Mat cameraMatrix = cameraCalibrator.getCameraMatrix();
	std::cout << " Camera intrinsic: " << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl;//相机内参
	std::cout << cameraMatrix.at<double>(0, 0) << " " << cameraMatrix.at<double>(0, 1) << " " << cameraMatrix.at<double>(0, 2) << std::endl;
	std::cout << cameraMatrix.at<double>(1, 0) << " " << cameraMatrix.at<double>(1, 1) << " " << cameraMatrix.at<double>(1, 2) << std::endl;
	std::cout << cameraMatrix.at<double>(2, 0) << " " << cameraMatrix.at<double>(2, 1) << " " << cameraMatrix.at<double>(2, 2) << std::endl;

	cv::namedWindow("Original Image");
	cv::imshow("Original Image", image1);
	cv::namedWindow("Undistorted Image");
	cv::imshow("Undistorted Image", uImage);
	//打印畸变系数矩阵(1*5矩阵)
	Mat distCoeffs = cameraCalibrator.getDistCoeffs();
	std::cout << "畸变系数矩阵:" << distCoeffs.rows << "x" << distCoeffs.cols << std::endl;
	for (int i = 0; i < distCoeffs.rows; i++)
		for (int j = 0; j < distCoeffs.cols; j++)
			cout << distCoeffs.at<double>(i, j) << "\t";

	// 把所有文件存储在xml文件
	cv::FileStorage fs("calib.xml", cv::FileStorage::WRITE);
	fs << "Intrinsic" << cameraMatrix;
	fs << "Distortion" << cameraCalibrator.getDistCoeffs();
	

	cv::waitKey();
	return 0;
}

该程序有一个缺陷,不能输出最后一张照片的外参,望高手赐教。

  • 3
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值