環境:VS2019+OpenCV4.4+Qt5.12.3
軟體打包軟體:Inno Setup Compiler
連結庫搜尋軟體:Everything
實作功能:相機标定;圖像校正
界面分布:标定區;校正區;控制台;操作回報;參數顯示 工程下載下傳連結
界面實作
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiI0gTMx81dsQWZ4lmZf1GLlpXazVmcvwFciV2dsQXYtJ3bm9CX9s2RkBnVHFmb1clWvB3MaVnRtp1XlBXe0xCMy81dvRWYoNHLwEzX5xCMx8FesU2cfdGLwMzX0xiRGZkRGZ0Xy9GbvNGLpZTY1EmMZVDUSFTU4VFRR9Fd4VGdsYTMfVmepNHLrJXYtJXZ0F2dvwVZnFWbp1zczV2YvJHctM3cv1Ce-cmbw5CMyEjM4MDM5MDZiF2YjZjZyYzX5UjN1UDMzEzLchDMyIDMy8CXn9Gbi9CXzV2Zh1WavwVbvNmLvR3YxUjLyM3Lc9CX6MHc0RHaiojIsJye.png)
軟體功能實作
告警提示,魯棒性增強
工程
#聯系方式:936874728
#include "CamCali.h"
#pragma execution_character_set("utf-8")// 解決漢字亂碼問題
#include <opencv2\imgproc\types_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:\windows\system32\cmd.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() {
...
}