相机标定软件编写(vs+opencv+qt designer)
程序员文章站
2023-12-27 09:10:51
...
联系方式:QQ:936874728
标定板:棋盘格标定板
标定算法:张正友标定法
模块:登录界面模块、时间显示模块、相机标定模块
闲话不多说,上代码。
ui界面:
登陆界面模块:
void login::on_clicked() //自定义函数
{
if (ui.UserlineEdit->text() == tr("1") && ui.PassWordlineEdit->text() == tr("1")) //用户密码
{
accept();
}
else
{
QMessageBox::warning(this, tr("warning!"), tr("username or password is wrong"),QMessageBox::Yes); //错误提示
}
}
时间显示模块
//显示实时系统时间的函数定义*******************************
void camcali::timerUpdate(void)
{
//获取实时时间
QDateTime time = QDateTime::currentDateTime();
//设置显示的时间日期的格式
QString str = time.toString("yyyy-MM-dd hh:mm:ss dddd");
//显示在label标签上
ui.label->setText(str);
}
读取文件模块
/*读取图片和保存数据的路径获取与规划*/
/************************************/
ifstream inImgPath("cali.txt");//ifstream读操作(输入)标定所用图像文件的路径
vector<string> imgList; //vrter<string>是一种数据类型,字符串
vector<string>::iterator p; //迭代器是一种允许程序员检查容器内元素,并实现元素遍历的数据类型,::是域操作符
string temp;
if (!inImgPath.is_open())//!是非的意思,真的变成假的,假的变成真的
{
cout << "没有找到文件" << endl; //输出字符串“没有没有找到文件”和换行符到屏幕。cout是标准库iostream中定义好的对象,cout 是std的一个成员函数
ui.textEdit_shuchu->append("没有找到文件");
}
//读取文件中保存的图片文件路径,并存放在数组中
while (getline(inImgPath, temp))//getline()是从输入流中读取一行字符,读到终止符时会将'0'存入结果缓冲区中,作为输入的终止。
{
imgList.push_back(temp);//push_back()函数将一个新的元素加到vector的最后面,位置为当前最后一个元素的下一个元素
}
ofstream fout("caliberation_result.txt");//ofstream写操作(输出)保存标定结果的文件,fout()向文件中进行写操作
角点提取模块
/*标定图片上的角点提取,即提取标定用特征点*/
/******************************************/
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
cout << "开始提取角点......" << endl;//输入的图像,必须是8位的灰度或彩色图像
//打印到软件界面的程序输出区(QTextEdit)
ui.textEdit_shuchu->append("开始提取角点......");
ui.textEdit_shuchu->append("遍历每一幅图片......");
//cout.flush();//可以实答现立刻的输出
cv::Size image_size; //保存图片的大小
int x = ui.lineEdit_x->text().toInt();
int y = ui.lineEdit_y->text().toInt();
int Length = ui.lineEdit_Length->text().toInt();
//int x = 8;
//int y = 11;
cv::Size pattern_size = cv::Size(x, y);//标定板上每行、每列的角点数;测试图片中的标定板上内角点数为4*6
vector<cv::Point2f>corner_points_buf;//建一个数组缓存检测到的角点,通常采用Point2f形式,缓存每幅图像上检测到的角点
vector<cv::Point2f>::iterator corner_points_buf_ptr;
vector<vector<cv::Point2f>>corner_points_of_all_imgs;//corner输出角点坐标,通常用cv::Point2f向量来保存,保存检测到的所有角点
int image_num = 0;//定义整型变量,赋初值
string filename;//定义字符串变量
while (image_num < imgList.size())
{
filename = imgList[image_num++];//读取文件
//string str1 = "image_num = ";
//char* name;
//sprintf(name, "%d", image_num);
//string str2 = name;
////string str = str1 + str2 + ".jpg";
//QString qstr;
//qstr = QString::fromStdString(str2);
cout << "image_num = " << image_num << endl;// 用于观察检验输出
/* ui.textEdit_shuchu->append(qstr); */ /* 输出检验*/
cout << filename.c_str() << endl;
//String转QString**
QString qstr;
qstr = QString::fromStdString(filename.c_str());
ui.textEdit_shuchu->append(qstr);
/*ui.textEdit_shuchu->setText("filename.c_str()");*/
cv::Mat imageInput = cv::imread(filename.c_str());
if (image_num == 1) //读入第一张图片时获取图像宽高信息
{
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
cout << "image_size.width = " << image_size.width << endl;
cout << "image_size.height = " << image_size.height << endl;
}
if (findChessboardCorners(imageInput, pattern_size, corner_points_buf) == 0) //寻找图片中的角点
{
cout << "can not find chessboard corners!\n";//找不到角点
ui.textEdit_shuchu->append("can not find chessboard corners!");
exit(1);//非正常运行导致退出程序
}
else
{
cv::Mat gray;
/*转换为灰度图像*/
cv::cvtColor(imageInput, gray, CV_RGB2GRAY);
/* 亚像素精确化 */
cv::find4QuadCornerSubpix(gray, corner_points_buf, cv::Size(Length, Length)); //find4QuadCornerSubpix()函数实现亚像素角点检测,对粗提取的角点进行精确化
corner_points_of_all_imgs.push_back(corner_points_buf); //保存亚像素角点
/* 在图像上显示角点位置 */
cv::drawChessboardCorners(gray, pattern_size, corner_points_buf, true); //在图片上画出检测到的角点。
cv::imshow("camera calibration", gray); //显示图片
cv::waitKey(100);//暂停0.1S
}
}
int total = corner_points_of_all_imgs.size();
cout << "total=" << total << endl;
int cornerNum = pattern_size.width * pattern_size.height;//每张图片上的总的角点数
for (int i = 0; i < total; i++)
{
cout << "-->第" << i + 1 << "幅图片的数据 -->:" << endl;
for (int j = 0; j < cornerNum; j++)
{
//输出所有的角点
cout << "-->" << corner_points_of_all_imgs[i][j].x;
cout << "-->" << corner_points_of_all_imgs[i][j].y;
if ((j + 1) % 3 == 0)
{
cout << endl;
}
else
{
cout.width(10);
}
}
cout << endl;
}
cout << endl << "角点提取完成" << endl;
ui.textEdit_shuchu->append("角点提取完成");
相机标定模块
/*摄像机标定*/
/****************************/
cout << "开始摄像机标定………………" << endl;
ui.textEdit_shuchu->append("开始摄像机标定......");
/*为标定参数分配内存*/
cv::Mat cameraMatrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//内外参矩阵,H--单应性矩阵
cv::Mat 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;//保存所有图片的角点的三维坐标,初始化每一张图片中标定板上角点的三维坐标
int i, j, k;
for (k = 0; k < image_num; k++)//遍历每一张图片
{
vector<cv::Point3f> tempCornerPoints;//每一幅图片对应的角点数组
//遍历所有的角点
for (i = 0; i < pattern_size.height; i++)
{
for (j = 0; j < pattern_size.width; j++)
{
cv::Point3f singleRealPoint;//一个角点的坐标
singleRealPoint.x = i * 10;
singleRealPoint.y = j * 10;
singleRealPoint.z = 0;//假设z=0
tempCornerPoints.push_back(singleRealPoint);
}
}
objectPoints.push_back(tempCornerPoints);
}
cv::calibrateCamera(objectPoints, corner_points_of_all_imgs, image_size, cameraMatrix, distCoefficients, rvecsMat, tvecsMat, 0);
cout << "标定完成" << endl;
ui.textEdit_shuchu->append("标定完成");
保存标定结果
/*开始保存标定结果*/
/***********************************/
cout << "开始保存标定结果" << endl;
ui.textEdit_shuchu->append("开始保存标定结果");
//相机内外参数
cout << endl << "相机相关参数:" << endl;
fout << "相机相关参数:" << endl;
cout << "1.内外参矩阵:" << endl;
fout << "1.内外参矩阵:" << endl;
cout << "大小:" << cameraMatrix.size() << endl;
fout << "大小:" << cameraMatrix.size() << endl;
cout << cameraMatrix << endl;
fout << cameraMatrix << endl;
//相机畸变系数
cout << "2.畸变系数:" << endl;
fout << "2.畸变系数:" << endl;
cout << "大小:" << distCoefficients.size() << endl;
fout << "大小:" << distCoefficients.size() << endl;
cout << distCoefficients << endl;
fout << distCoefficients << endl;
//图像相关参数
cout << endl << "图像相关参数:" << 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++)
{
//旋转矩阵
cout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
fout << "第" << i + 1 << "幅图像的旋转向量:" << endl;
cout << rvecsMat[i] << endl;
fout << rvecsMat[i] << endl;
cout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
fout << "第" << i + 1 << "幅图像的旋转矩阵:" << endl;
cv::Rodrigues(rvecsMat[i], rotation_Matrix);//将旋转向量转换位相对应的旋转矩阵
//平移向量
cout << rotation_Matrix << endl;
fout << rotation_Matrix << endl;
cout << "第" << i + 1 << "幅图像的平移向量:" << endl;
fout << "第" << i + 1 << "幅图像的平移向量:" << endl;
cout << tvecsMat[i] << endl;
fout << tvecsMat[i] << endl;
}
cout << "结果保存完毕" << endl;
ui.textEdit_shuchu->append("结果保存完毕");
结果评价模块
/*对标定结果进行评价*/
/*************************************/
cout << "开始评价标定结果…………" << endl;
ui.textEdit_shuchu->append("开始评价标定结果......");
//计算每幅图像中的角点数量,假设全部角点都检测到了
int corner_points_counts;
/*角点总数*/
corner_points_counts = pattern_size.width * pattern_size.height;
cout << "每幅图像的标定误差:" << endl;
fout << "每幅图像的标定误差:" << endl;
double err = 0;//单张图像的误差
double total_err = 0;//所有图像的平均误差
for (i = 0; i < image_num; i++)
{
vector<cv::Point2f> image_points_calculated;//存放新的计算出得投影点的坐标
vector<cv::Point3f> tempPointSet = objectPoints[i];
/*通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点*/
cv::projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoefficients, image_points_calculated);
/*计算新的投影点与旧的投影点之间的误差*/
vector<cv::Point2f> image_points_old = corner_points_of_all_imgs[i];
/*将两组数据换成Mat格式*/
cv::Mat image_points_calculated_mat = cv::Mat(1, image_points_calculated.size(), CV_32FC2);
cv::Mat image_points_old_mat = cv::Mat(1, image_points_old.size(), CV_32FC2);
for (j = 0; j < tempPointSet.size(); j++)
{
image_points_calculated_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_calculated[j].x, image_points_calculated[j].y);
image_points_old_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_old[j].x, image_points_old[j].y);
}
err = cv::norm(image_points_calculated_mat, image_points_old_mat, cv::NORM_L2);
err /= corner_points_counts;
total_err += err;
cout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
fout << "第" << i + 1 << "幅图像的平均误差:" << err << "像素" << endl;
}
cout << "总体平均误差:" << total_err / image_num << "像素" << endl;
fout << "总体平均误差:" << total_err / image_num << "像素" << endl;
cout << "评价完成" << endl;
ui.textEdit_shuchu->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);
cout << "保存矫正图像" << endl;
ui.textEdit_shuchu->append("保存矫正图像");
string imageFileName;
std::stringstream StrStm;
for (int i = 0; i < image_num; i++)
{
cout << "Frame #" << i + 1 << endl;
cv::initUndistortRectifyMap(cameraMatrix, distCoefficients, R, cameraMatrix, image_size, CV_32FC1, mapx, mapy);
cv::Mat src_image = cv::imread(imgList[i].c_str(), 1);
cv::Mat new_image = src_image.clone();
cv::remap(src_image, new_image, mapx, mapy, cv::INTER_LINEAR);
imshow("original image", src_image);
imshow("Dedistorted image", new_image);
StrStm.clear();
imageFileName.clear();
StrStm << i + 1;
StrStm >> imageFileName;
imageFileName += "_d.jpg";
cv::imwrite(imageFileName, new_image);
cv::waitKey(200);
}
cout << "保存结束" << endl;
ui.textEdit_shuchu->append("保存结束");
cv::waitKey(0);
}
参数显示模块
//显示参数按键函数定义******************************************
void camcali::on_pushButton_canshu_clicked()
{
QString displayString;
QFile file("caliberation_result.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug() << "Can't open the file!" << endl;
ui.textEdit_shuchu->append("Can't open the file!");
}
while (!file.atEnd())
{
QByteArray line = file.readLine();
QString str(line);
qDebug() << str;
ui.textEdit_shuchu->append(str);
displayString.append(str);
}
ui.textEdit_canshu->clear();
ui.textEdit_canshu->setPlainText(displayString);
}