相机标定与图像校正助手(VS+OpenCV+Qt实现)

环境:VS2019+OpenCV4.4+Qt5.12.3
软件打包软件:Inno Setup Compiler
链接库搜索软件:Everything
实现功能:相机标定;图像校正
界面分布:标定区;校正区;控制台;操作反馈;参数显示
作者联系方式:936874728

界面实现
在这里插入图片描述
软件功能实现
在这里插入图片描述
告警提示,鲁棒性增强

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
工程
在这里插入图片描述
核心代码展示:

#联系方式:936874728
#include "CamCali.h"
#pragma execution_character_set("utf-8") // 解决汉字乱码问题 
#include <opencv2imgproctypes_c.h>
#include <QtWidgets/QMessageBox> // 提示信息
#include <string>
#include <fstream> //文件流操作的头文件
#include <vector>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QTextStream>
#include <QString>

CamCali::CamCali(QWidget* parent)
	: QWidget(parent)
{
	ui.setupUi(this);
	// 标定板尺寸提示字样
	ui.lineEdit_brd_x->setPlaceholderText("宽:8");
	...
	ui.lineEdit_brd_size->setPlaceholderText("尺寸:5");

	// 添加槽链接,链接按键与按键函数
	QObject::connect(ui.in_btn_sel, SIGNAL(clicked()), this, SLOT(in_btn_sel())); // 选择标定图片
	...
	QObject::connect(ui.save_btn_adjust, SIGNAL(clicked()), this, SLOT(save_btn_adjust())); // 保存矫正图
}


// convertAbsolutePathToRelative()函数具体实现如下
QString convertAbsolutePathToRelative(const QString& absolute_path)
{
	QString current_path = QDir::currentPath(); // 当前路径,如 C:windows的形式
	QString tmp_str = absolute_path;  // 绝对路径,如 C:windowssystem32cmd.exe的形式
	...
	return tmp_str;  // 返回相对路径
}

// 按键功能实现

// 选择标定图片
void CamCali::in_btn_sel() {
	//QString strs;
	//QStringList file_list, output_name;
	QStringList str_path_list = QFileDialog::getOpenFileNames(this, tr("选择标定文件"), tr("./"), tr("图片文件(*.jpg *.bmp *png);;所有文件(*.*);;"));
	if (str_path_list.empty()) {
		ui.opera_edit->append("没有选定标定文件");
		return;
	}
	...
	file.close();
}

// 相机标定按键功能实现
void CamCali::out_btn_cali() { // 输出相机标定图片

	// 读取标定板尺寸信息
	int x = ui.lineEdit_brd_x->text().toInt();
	...

	// 判断是否输入标定板尺寸信息
	if (ui.lineEdit_brd_x->text().isEmpty() && ui.lineEdit_brd_y->text().isEmpty() && ui.lineEdit_brd_size->text().isEmpty())
	{
		QMessageBox::warning(this, tr("warning!"), tr("请输入棋盘格的宽度x,长度y,尺寸length"), QMessageBox::Yes);
		return;
	}
	else
	{
		// 读取图像文件的路径
		ifstream inImgPath("cali.txt");//ifstream读操作(输入)标定所用图像文件的路径
		...

		// 标定板角点提取
		ui.opera_edit->append("开始提取角点......");
		ui.opera_edit->append("遍历每一幅图片......");
		...
			if (findChessboardCorners(imageInput, pattern_size, corner_points_buf) == 0)	//寻找图片中的角点
			{
				//找不到角点
				ui.opera_edit->append("提取不到角点");
				QMessageBox::warning(this, tr("warning!"), tr("找不到角点"), QMessageBox::Yes);
				return;
			}
			else
			{
				...
			}
		}
		int total = corner_points_of_all_imgs.size();
		int cornerNum = pattern_size.width * pattern_size.height;//每张图片上的总的角点数
		...
		ui.opera_edit->append("角点提取完成");

		// 摄像机标定
		ui.opera_edit->append("开始摄像机标定......");
		/*为标定参数分配内存*/
		cameraMatrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//内外参矩阵,H--单应性矩阵
		distCoefficients = cv::Mat(1, 5, CV_32FC1, cv::Scalar::all(0));//摄像机的5个畸变系数:k1,k2,p1,p2,k3

		vector<cv::Mat>tvecsMat;//每幅图像的平移向量,t
		vector<cv::Mat>rvecsMat;//每幅图像的旋转向量(罗德里格旋转向量)
		vector<vector<cv::Point3f>> objectPoints;//保存所有图片的角点的三维坐标,初始化每一张图片中标定板上角点的三维坐标

		...
		ui.opera_edit->append("标定完成");

		// 开始保存标定结果
		ui.opera_edit->append("开始保存标定结果");
		//相机内外参数
		fout << "相机相关参数:" << endl;
		fout << "1.内外参矩阵:" << endl;
		fout << "大小:" << cameraMatrix.size() << endl;
		fout << cameraMatrix << endl;

		//相机畸变系数
		fout << "2.畸变系数:" << endl;
		fout << "大小:" << distCoefficients.size() << endl;
		fout << distCoefficients << endl;

		//图像相关参数
		fout << endl << "图像相关参数:" << endl;
		cv::Mat rotation_Matrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//旋转矩阵
		for (i = 0; i < image_num; i++)
		{
			//旋转矩阵
			fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
			fout << rvecsMat[i] << endl;
			fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
			cv::Rodrigues(rvecsMat[i], rotation_Matrix);//将旋转向量转换位相对应的旋转矩阵
														//平移向量
			fout << rotation_Matrix << endl;
			fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
			fout << tvecsMat[i] << endl;
		}

		ui.opera_edit->append("结果保存完毕");

		// 对标定结果进行评价
		ui.opera_edit->append("开始评价标定结果......");

		//计算每幅图像中的角点数量,假设全部角点都检测到了
		int corner_points_counts;
		/*角点总数*/
		corner_points_counts = pattern_size.width * pattern_size.height;

		fout << "每幅图像的标定误差:" << endl;
		...
		ui.opera_edit->append("评价完成");

		fout.close();

		// 矫正图像
		cv::Mat mapx = cv::Mat(image_size, CV_32FC1);
		cv::Mat mapy = cv::Mat(image_size, CV_32FC1);
		cv::Mat R = cv::Mat::eye(3, 3, CV_32F);
		ui.opera_edit->append("保存矫正图像");
		...
		ui.opera_edit->append("保存结束");
		cv::waitKey(0);
	}

	// 显示标定参数
	QString displayString;
	QFile file("caliberation_result.txt");
	if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
	{
		ui.opera_edit->append("没有找到参数文件");
	}
	while (!file.atEnd())
	{
		QByteArray line = file.readLine();
		QString str(line);
		//ui.opera_edit->append(str);
		displayString.append(str);
	}
	ui.para_edit->clear();
	ui.para_edit->setPlainText(displayString);
}


// 图像校正功能实现
void CamCali::out_btn_adjust() { // 输出校正图像

	if (cameraMatrix.empty()) {
		ui.opera_edit->append("没有相机内参,请标定");
		return;
	}
	
	if (distCoefficients.empty()) {
		ui.opera_edit->append("没有相机畸变参数,请标定");
		return;
	}

	...
		//
		cv::Mat mapx = cv::Mat(image_size, CV_32FC1);
		cv::Mat mapy = cv::Mat(image_size, CV_32FC1);
		cv::Mat R = cv::Mat::eye(3, 3, CV_32F);
		ui.opera_edit->append("保存矫正图像");
		string imageFileName;
		std::stringstream StrStm;

		cv::initUndistortRectifyMap(cameraMatrix, distCoefficients, R, cameraMatrix, image_size, CV_32FC1, mapx, mapy);
		...
		ui.show_outadjustpic->setPixmap(QPixmap::fromImage(Qtemp));
		ui.show_outadjustpic->setScaledContents(true);
		ui.show_outadjustpic->show();

		adjustPic = new_image;
	}
	else {
		ui.opera_edit->append("畸变图像打开失败");
	}


}


// 保存校正图像
void CamCali::save_btn_adjust() {

	...

}





本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>