天天看點

代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)

環境:VS2019+OpenCV4.4+Qt5.12.3

軟體打包軟體:Inno Setup Compiler

連結庫搜尋軟體:Everything

實作功能:相機标定;圖像校正

界面分布:标定區;校正區;控制台;操作回報;參數顯示 工程下載下傳連結​

界面實作

代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)

軟體功能實作

代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)

告警提示,魯棒性增強

代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)
代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)
代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)
代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)

工程

代碼:相機标定與圖像校正助手(VS+OpenCV+Qt實作)
#聯系方式: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() {

  ...

}      

繼續閱讀