单目相机标定(VS + OpenCV + C++ )加速

  • 单目相机标定(使用OpenCV)

  • 关于相机标定的理论知识和使用Matlab软件进行相机标定请看这篇博文:单目相机标定(使用Matlab)


1.VS的环境配置

单目相机标定(VS + OpenCV + C++ )加速_第1张图片
单目相机标定(VS + OpenCV + C++ )加速_第2张图片
单目相机标定(VS + OpenCV + C++ )加速_第3张图片

2.源码

单目相机标定(VS + OpenCV + C++ )加速_第4张图片
单目相机标定(VS + OpenCV + C++ )加速_第5张图片

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include 
#include 
#include 
#include 

using namespace cv;
using namespace std;
using namespace std::experimental::filesystem;

Size const cornerSize = Size(9, 7);                       //定义标定板每行、每列角点数
Size squareSize = Size(20, 20);                           //实际测量得到的标定板上每个棋盘格的尺寸,单位mm

struct calibrationCache
{
	vector<Point2f> cornerPointBuffer;          //缓存每幅图像上检测到的角点
	vector<vector<Point2f>> cornerPointSequece; //保存检测到的所有角点
	vector<vector<Point3f>> tempCornerPosition;      //保存标定板上角点的三维坐标
	int imageCount = 0;                         //采样图像数量
	int cornerCount = 0;                        //检测到的角点数量
	Size imageSize;                             //输入图像的像素尺寸
												//----结果部分---------//
	Mat intrinsicMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); //摄像机内参数矩阵
	Mat distCoeffs = Mat(1, 12, CV_32FC1, Scalar::all(0));      //摄像机的畸变系数12个:k1,k2,p1,p2,k3
	vector<Mat> tvecsMat;                                      //每幅图像的旋转向量
	vector<Mat> rvecsMat;                                      //每幅图像的平移向量
};
//----函数声明---------//
void drawIMage(Mat img, vector<Point2f> cornerBuffer);
void outPutCornerInfo(calibrationCache& cache);
void calibrationCamera(calibrationCache& cache);
void caculateErrorAndSaveResult(calibrationCache& cache, const string& resultFileName);
void unDistortRectifyImage(calibrationCache& cache);

///显示图像
void drawIMage(Mat img, vector<Point2f> cornerBuffer)
{
	drawChessboardCorners(img, cornerSize, cornerBuffer, false); //用于在图片中标记角点
	imshow("Camera Calibration", img);                           //显示图片
	waitKey(1000);                                               //暂停1
}

void outPutCornerInfo(calibrationCache& cache)
{
	int SampleImageCount = cache.cornerPointSequece.size();
	cout << "采样图像数= " << SampleImageCount << endl;
	if (SampleImageCount < 1)
		exit(1);
	for (int j = 0; j < cache.cornerPointSequece.size(); j++)
	{
		cout << endl;
		cout << "第" << j + 1 << "张图片的角点数据: " << endl;
		for (int i = 0; i < cache.cornerPointSequece[j].size(); i++)
		{
			cout << "(X:" << cache.cornerPointSequece[j][i].x << ",Y:" << cache.cornerPointSequece[j][i].y << ")"
				<< "      ";
			if (0 == (i + 1) % 4) // 格式化输出,便于控制台查看
			{
				cout << endl;
			}
		}
		cout << endl;
	}
	cout << endl;
}
//标定相机
void calibrationCamera(calibrationCache& cache)
{
	int i, j, t;
	for (t = 0; t < cache.imageCount; t++)
	{
		vector<Point3f>CornerPosition;
		for (i = 0; i < cornerSize.height; i++)
		{
			for (j = 0; j < cornerSize.width; j++)
			{
				Point3f cornerPos;
				cornerPos.x = i * squareSize.width;
				cornerPos.y = j * squareSize.height;
				cornerPos.z = 0; //假设标定板放在世界坐标系中z=0的平面上
				CornerPosition.push_back(cornerPos);
			}
		}
		cache.tempCornerPosition.push_back(CornerPosition);
	}
	calibrateCamera(cache.tempCornerPosition, cache.cornerPointSequece, cache.imageSize,
		cache.intrinsicMatrix, cache.distCoeffs, cache.rvecsMat, cache.tvecsMat, CALIB_TILTED_MODEL | CALIB_RATIONAL_MODEL | CALIB_THIN_PRISM_MODEL);
	cout << "标定完成!" << endl
		<< endl;
}

//评估误差并保存结果
void caculateErrorAndSaveResult(calibrationCache& cache, const string& resultFileName)
{
	int cornerCount = cornerSize.width * cornerSize.height;
	double totalError = 0.0;
	double sigleError = 0.0;
	vector<Point2f> reprojectPoints;
	ofstream fout(resultFileName);
	cout << "每幅图像的标定误差:" << endl;
	fout << "每幅图像的标定误差:\n";
	for (int i = 0; i < cache.imageCount; i++)
	{
		vector<Point3f> tempPointSet = cache.tempCornerPosition[i];
		projectPoints(tempPointSet, cache.rvecsMat[i], cache.tvecsMat[i], cache.intrinsicMatrix, cache.distCoeffs, reprojectPoints);
		vector<Point2f> oldImagePoint = cache.cornerPointSequece[i];
		Mat oldImagePointMatrix = Mat(1, oldImagePoint.size(), CV_32FC2);
		Mat reprojectPointsMatrix = Mat(1, reprojectPoints.size(), CV_32FC2);
		for (int j = 0; j < oldImagePoint.size(); j++)
		{
			reprojectPointsMatrix.at<Vec2f>(0, j) = Vec2f(reprojectPoints[j].x, reprojectPoints[j].y);
			oldImagePointMatrix.at<Vec2f>(0, j) = Vec2f(oldImagePoint[j].x, oldImagePoint[j].y);
		}
		sigleError = norm(reprojectPointsMatrix, oldImagePointMatrix, NORM_L2);
		totalError += (sigleError /= cornerCount);
		cout << "第" << i + 1 << "幅图像的平均误差:" << sigleError << "像素" << endl;
		fout << "第" << i + 1 << "幅图像的平均误差:" << sigleError << "像素" << endl;
	}
	cout << "总体平均误差:" << totalError / cache.imageCount << "像素" << endl;
	fout << "总体平均误差:" << totalError / cache.imageCount << "像素" << endl
		<< endl;
	cout << "评价完成!" << endl
		<< endl;

	cout << "开始保存定标结果..." << endl;
	Mat rotationMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); //保存每幅图像的旋转矩阵
	fout << "相机内参数矩阵:" << endl;
	cout << "相机内参数矩阵:" << endl;
	fout << "【其中,焦距(0, 0):fx,(1, 1):fy; 像主点(0, 2):ux,(1, 2):uy】" << endl;
	fout << cache.intrinsicMatrix << endl
		<< endl;
	cout << cache.intrinsicMatrix << endl
		<< endl;
	fout << "畸变系数:\n";
	cout << "畸变系数:" << endl;
	fout << "【其中,(0, 0):k1,(0, 1):k2,(0, 2):p1,(0, 3):p2,(0, 4):k3,(0, 5):k4,(0, 6):k5,(0, 7):k6,(0, 8):s1,(0, 9):s2,(0, 10):s3,(0, 11):s4】" << endl;
	fout << cache.distCoeffs << endl
		<< endl
		<< endl;
	cout << cache.distCoeffs << endl
		<< endl
		<< endl;
	for (int i = 0; i < cache.imageCount; i++)
	{
		fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
		cout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
		fout << cache.rvecsMat[i] << endl;
		cout << cache.rvecsMat[i] << endl;
		Rodrigues(cache.rvecsMat[i], rotationMatrix);
		fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
		cout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
		fout << rotationMatrix << endl;
		cout << rotationMatrix << endl;
		fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
		cout << "第" << i + 1 << "幅图像的平移向量:" << endl;
		fout << cache.tvecsMat[i] << endl
			<< endl;
		cout << cache.tvecsMat[i] << endl
			<< endl;
	}
	cout << "完成保存" << endl
		<< endl;
	fout << endl;
}

void LoadImages_txt(std::string filename, std::vector<std::string>& imageNames)
{
	// step 1 : open file
	std::ifstream file(filename);

	if (!file) {
		std::cout << "Wrong File !" << filename << " dose not exist!" << std::endl;
		return;
	}

	// step 2 : load data
	imageNames.clear();

	while (!file.eof()) {
		std::string imageName;
		file >> imageName;

		if (file.eof())
			break;

		imageNames.push_back(imageName);
		std::cout << "Load Image, imageName: " << imageName << std::endl;
	}

	file.close();
	return;
}

int main(int argc, char* argv[])
{
	std::string dataFileName = "calibdata.txt"; //所有标定图片的存放路径
	std::vector<std::string> imageNames;
	LoadImages_txt(dataFileName, imageNames);


	clock_t start_time, end_time;
	start_time = clock();

	cout << "开始读取图像..." << endl;
	calibrationCache calibCache;

	string imageName;
	for (int i = 0; i < imageNames.size(); i++)
	{
		std::cout << imageNames[i] << std::endl;
		Mat imageInput = imread(imageNames[i]);
		if (0 == findChessboardCorners(imageInput, cornerSize, calibCache.cornerPointBuffer, cv::CALIB_CB_ADAPTIVE_THRESH))
		{
			cout << imageNames[i] << "图像有问题" << endl;
			calibCache.imageCount--;
			continue;
		}
		else
		{
			Mat grayImage;
			if (calibCache.imageCount == 1)
			{
				calibCache.imageSize.width = imageInput.cols;
				calibCache.imageSize.height = imageInput.rows;
			}
			cv::cvtColor(imageInput, grayImage, cv::COLOR_BGR2GRAY);
			cornerSubPix(grayImage, calibCache.cornerPointBuffer, Size(5, 5), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.01));
			calibCache.cornerPointSequece.push_back(calibCache.cornerPointBuffer);

			calibCache.imageCount++;
		}
	}
	cout << "角点提取完成!" << endl << endl;
	outPutCornerInfo(calibCache);


	cout << "开始标定..." << endl;
	calibrationCamera(calibCache);

	cout << "开始评价标定结果..." << endl;
	std::string result = "result.txt";
	caculateErrorAndSaveResult(calibCache, result);

	end_time = clock();
	double Times = (double)(end_time - start_time) / CLOCKS_PER_SEC;
	printf("%f seconds\n", Times);

	return 0;
}

3.加速标定速度

将VS编译器由Debug改为Release。
在这里插入图片描述
对比:

  • Debug
    单目相机标定(VS + OpenCV + C++ )加速_第6张图片
  • Release
    单目相机标定(VS + OpenCV + C++ )加速_第7张图片

你可能感兴趣的:(海康威视工业相机,手眼标定,opencv,c++,相机标定)