天天看點

Halcon标定參數(畸變系數)轉OpenCV标定資料源檔案

标定闆的品質對标定精度影響也是非常大的,我手上有一個陶瓷的Halcon原點标定闆,使用Halcon标定效果很好。但由于想轉用OpenCV開發,且不想放棄已有的圖像資料,是以想将Halcon标定的資料(内參、外參,畸變系數),轉換到OpenCV中。

當然,其參數不是一一對應的(也就是說,Halcon中的畸變系數與OpenCV中的畸變系數并不一一對應,按照官方的說法是其求解的畸變參數的形式是不一樣的。一個是由校正前到校正後求解得到,一個是由校正後到校正前求解得到)。

依據Stack Overflow中的資料,寫了一個轉換的類,輸入Halcon中的标定資料,就可以得到OpenCV中的參數,可以實作校正畸變,具體精度還有待進一步研究。

源位址:https://stackoverflow.com/questions/58606394/halcon-to-opencv-distortion-coefficients-convertion/58991972#58991972

————————————————————————————————————————

更正:第一版中畸變計算出現錯誤(低級錯誤),内參矩陣誤乘了一個尺度因子。

OpenCV中的畸變參數排列為 K1 K2 P1 P2 K3(Halcon中是 K1 K2 K3 P1 P2)大坑啊!

輸入參數(畸變系數)

k 1 o p e n c v = k 1 h a l c o n ∗ f m m ∗ f m m ; k 2 o p e n c v = k 2 h a l c o n ∗ f m m ∗ f m m ∗ f m m ∗ f m m ; k 3 o p e n c v = k 3 h a l c o n ∗ f m m ∗ f m m ∗ f m m ∗ f m m ∗ f m m ∗ f m m ; p 1 o p e n c v = p 2 h a l c o n ∗ f m m ; ( 注 意 這 裡 是 p 2 ) p 2 o p e n c v = p 1 h a l c o n ∗ f m m ; \begin{aligned} k1_{opencv} &= k1_{halcon} * fmm * fmm; \\ k2_{opencv} &= k2_{halcon} * fmm * fmm * fmm * fmm; \\ k3_{opencv} &= k3_{halcon} * fmm * fmm * fmm * fmm * fmm * fmm; \\ p1_{opencv} &= p2_{halcon} * fmm; (注意這裡是p_{2}) \\ p2_{opencv} &= p1_{halcon} * fmm; \\ \end{aligned} k1opencv​k2opencv​k3opencv​p1opencv​p2opencv​​=k1halcon​∗fmm∗fmm;=k2halcon​∗fmm∗fmm∗fmm∗fmm;=k3halcon​∗fmm∗fmm∗fmm∗fmm∗fmm∗fmm;=p2halcon​∗fmm;(注意這裡是p2​)=p1halcon​∗fmm;​

f m m fmm fmm指代焦距Focal Length。

從Halcon中讀入參數,轉化為OpenCV中的标定參數

  1. 預先使用Halcon标定,得到标定參數模型(畸變模型選用多項式模型,不要用除法模型kappa),使用算子write_camera_setup_model儲存參數模型,當然也可以直接讀取,不儲存參數~。
Halcon标定參數(畸變系數)轉OpenCV标定資料源檔案
  1. 讀取參數模型中的參數,得到焦距、Sx、Sy、Cx、Cy、k1、k2、k3、p1、p2以及R、T
* 讀取參數模型
read_camera_setup_model ('stereo_camera_setupOpenCV.csm', CameraSetupModelID)

get_camera_setup_param (CameraSetupModelID,  0, 'params', CamParam0) // 提取相機的内參數
get_cam_par_data (CamParam0, 'focus', focus0) // 焦距
get_cam_par_data (CamParam0, 'sx', sx0) // Sx 像元尺寸
get_cam_par_data (CamParam0, 'sy', sy0) // Sy 像元尺寸
get_cam_par_data (CamParam0, 'cx', cx0) // 主點坐标 cx
get_cam_par_data (CamParam0, 'cy', cy0) // 主點坐标 cy
get_cam_par_data (CamParam0, 'k1', k10) // 畸變系數
get_cam_par_data (CamParam0, 'k2', k20) // 畸變系數
get_cam_par_data (CamParam0, 'k3', k30) // 畸變系數
get_cam_par_data (CamParam0, 'p1', p10) // 畸變系數
get_cam_par_data (CamParam0, 'p2', p20) // 畸變系數
change_radial_distortion_cam_par ('adaptive', CamParam0, [0,0,0,0,0], CamParamOut) // 為了生成内參矩陣
cam_par_to_cam_mat (CamParamOut, CamParam0Out, ImageWidth, ImageHeight) // 内參矩陣

* ** 外參數
* 0号相機
get_camera_setup_param (CameraSetupModelID,  0, 'pose', Pose3)
pose_to_hom_mat3d (Pose3, HomMat3D_0)
           

得到參數:

Halcon标定參數(畸變系數)轉OpenCV标定資料源檔案
  1. 導入到C++程式中
Halcon标定參數(畸變系數)轉OpenCV标定資料源檔案

其實,setcameraMatrix_Halcon沒什麼用,可以不用添加。

  1. 使用轉化後的OpenCV畸變系數實作校正
Halcon标定參數(畸變系數)轉OpenCV标定資料源檔案

源檔案

main.cpp主檔案

設定參數并測試

//
// Created by zzl on 10/21/20.
//
#include <iostream>
#include "opencv2/opencv.hpp"
#include "ParamsConvert.h"  // 轉化用的頭檔案


using namespace std;
using namespace cv;


int main(int argc,char** argv) {
    CameraParams camera0; // 聲明類
    camera0.setcameraMatrix_Halcon(2284.79, 2273.73, 444.25, 579.716); // 導入參數,這個函數沒什麼用
    camera0.setcameraParams_Halcon(0.00861914, 3.75142e-06, 3.75e-06, 445.868, 582.908); // 導入Halcon中的資料,内參
    camera0.setcameraDistCoeffs_Halcon(954.86, 2.8045e+08, -2.35577e+13, 0.451309, 0.457282); // 導入Halcon中的資料,畸變系數(5參數,注意p2,p1位置交換了)
    camera0.setcameraRotation(0.0808079, 0.0137326, 0.996635, 0.996676, -0.0114733, -0.0806531, 0.0103271, 0.99984, 
                              -0.0146141); // 導入Halcon中的資料,旋轉矩陣
    camera0.setcameraTranspose(-0.129098 , -0.00118334 , 0.122701 ); // 導入Halcon中的資料,平移向量(注意機關)

    // Camera0
    // Read Image and Test 
    Mat src_0 = imread("./0-0.bmp", 1);
    namedWindow("Input_0", WINDOW_NORMAL);
    imshow("Input_0", src_0);
    // Convert Params
    camera0.Halcon2OpenCV();
    Mat cameraMatrix0_OpenCV = camera0.cameraMatrix_OpenCV; // 讀取類中的内參矩陣
    Mat cameraDist0_OpenCV = camera0.distCoeffs_OpenCV; // 讀取類中的畸變矩陣
    Mat dst_0;
    undistort(src_0, dst_0, cameraMatrix0_OpenCV, cameraDist0_OpenCV, noArray());
    namedWindow("Output_0", WINDOW_NORMAL);
    imshow("Output_0", dst_0);

    waitKey();
    cout<<"Hello World"<<endl;
    return 0;
}

           

轉換用的頭檔案ParamsConvert.h:

// header
// Created by zzl on 10/20/20.
//
#include "opencv2/opencv.hpp"
#include "opencv2/calib3d.hpp"


#ifndef HALCONPARAMS2OPENCV_PARAMSCONVERT_H
#define HALCONPARAMS2OPENCV_PARAMSCONVERT_H

class CameraParams {
 // 轉換畸變系數
public:
    void Halcon2OpenCV();
    void setcameraMatrix_Halcon(float fx,float fy,float cx,float cy); // 導入Halcon中的資料
    void setcameraParams_Halcon(float focal_Halcon,float sx_Halcon,float sy_Halcon,float Cx,float Cy);  // 導入Halcon中的資料
    void setcameraDistCoeffs_Halcon(float k1,float k2,float k3,float p2,float p1); // 導入Halcon中的資料,注意畸變系數p1、p2
    void setcameraRotation(float x1,float x2,float x3,float y1,float y2,float y3,float z1,float z2,float z3); // 設定旋轉矩陣
    void setcameraTranspose(float t1,float t2,float t3); // 設定平移矩陣

    cv::Mat cameraMatrix_OpenCV = cv::Mat::zeros(3, 3, CV_32F); // 輸出的相機内參矩陣
    cv::Mat distCoeffs_OpenCV = cv::Mat::zeros(1, 5, CV_32F); // 輸出的相機畸變系數
    cv::Mat cameraRotation= cv::Mat::zeros(3,3,CV_32F); // 輸出的相機旋轉矩陣
    cv::Mat cameraTrans = cv::Mat::zeros(3,1,CV_32F); // 輸出的相機平移向量


private:
    // 定義Halcon的基本參數
    cv::Mat cameraMatrix_Halcon = cv::Mat::zeros(3, 3, CV_32F);
    cv::Mat distCoeffs_Halcon = cv::Mat::zeros(1, 5, CV_32F); //  以k1,k2,k3,p2,p1
    double focal_Halcon, sx_Halcon, sy_Halcon, Cx, Cy;

};

// 函數實作
void CameraParams::Halcon2OpenCV() {
    //cv::Mat OpenCVMatrix = cv::Mat::zeros(1,5,CV_32F);
    // DistCoeffs
    distCoeffs_OpenCV.at<float>(0, 0) = distCoeffs_Halcon.at<float>(0, 0) * focal_Halcon * focal_Halcon; // K1

    distCoeffs_OpenCV.at<float>(0, 1) =
            distCoeffs_Halcon.at<float>(0, 1) * focal_Halcon * focal_Halcon * focal_Halcon * focal_Halcon; // K2

    distCoeffs_OpenCV.at<float>(0, 4) =
            distCoeffs_Halcon.at<float>(0, 2) * focal_Halcon * focal_Halcon * focal_Halcon * focal_Halcon *
                    focal_Halcon * focal_Halcon; // K3為OpenCV畸變中的最後一個

    // P1
    distCoeffs_OpenCV.at<float>(0, 2) = distCoeffs_Halcon.at<float>(0, 3) * focal_HalconMM; // P2
    distCoeffs_OpenCV.at<float>(0, 3) = distCoeffs_Halcon.at<float>(0, 4) * focal_HalconMM; // P1
    // CameraMatrix
    cameraMatrix_OpenCV.at<float>(0, 0) = (focal_Halcon / sx_Halcon) ; // 尺度因子 focal_Halcon機關為mm,Sx_Halcon為 mm/像素 注意機關 mm還是um
    cameraMatrix_OpenCV.at<float>(0, 1) = 0.0;
    cameraMatrix_OpenCV.at<float>(0, 2) = Cx;
    cameraMatrix_OpenCV.at<float>(1, 0) = 0.0;
    cameraMatrix_OpenCV.at<float>(1, 1) = (focal_Halcon / sy_Halcon)  ;
    cameraMatrix_OpenCV.at<float>(1, 2) = Cy;
    cameraMatrix_OpenCV.at<float>(2, 0) = 0.0;
    cameraMatrix_OpenCV.at<float>(2, 1) = 0.0;
    cameraMatrix_OpenCV.at<float>(2, 2) = 1.0;
}

void CameraParams::setcameraMatrix_Halcon(float fx,float fy,float cx,float cy){
    cameraMatrix_Halcon.at<float>(0,0) = fx;
    cameraMatrix_Halcon.at<float>(0,2) = cx;
    cameraMatrix_Halcon.at<float>(1,1) = fy;
    cameraMatrix_Halcon.at<float>(1,3) = cy;
}

void CameraParams::setcameraParams_Halcon(float focal_HalconIN, float sx_HalconIN, float sy_HalconIN, float CxIN, float CyIN) {
    focal_Halcon = focal_HalconIN;
    sx_Halcon = sx_HalconIN;
    sy_Halcon = sy_HalconIN;
    Cx = CxIN;
    Cy = CyIN;
}
void CameraParams::setcameraDistCoeffs_Halcon(float k1, float k2, float k3, float p2, float p1) {
    distCoeffs_Halcon.at<float>(0,0) = k1;
    distCoeffs_Halcon.at<float>(0,1) = k2;
    distCoeffs_Halcon.at<float>(0,2) = k3;
    distCoeffs_Halcon.at<float>(0,3) = p2;
    distCoeffs_Halcon.at<float>(0,4) = p1;

}

void CameraParams::setcameraRotation(float x1,float x2,float x3,float y1,float y2,float y3,float z1,float z2,float z3){
    cameraRotation.at<float>(0,0) = x1;
    cameraRotation.at<float>(0,1) = x2;
    cameraRotation.at<float>(0,2) = x3;
    cameraRotation.at<float>(1,0) = y1;
    cameraRotation.at<float>(1,1) = y2;
    cameraRotation.at<float>(1,2) = y3;
    cameraRotation.at<float>(2,0) = z1;
    cameraRotation.at<float>(2,1) = z2;
    cameraRotation.at<float>(2,2) = z3;
}

void CameraParams::setcameraTranspose(float t1, float t2, float t3) {
    cameraTrans.at<float>(0,0) = t1;
    cameraTrans.at<float>(1,0) = t2;
    cameraTrans.at<float>(2,0) = t3;
}

#endif //HALCONPARAMS2OPENCV_PARAMSCONVERT_H
           

CMakeLists.txt檔案:

cmake_minimum_required(VERSION 3.10)
project(HalconParams2OpenCV)

set(CMAKE_CXX_STANDARD 14)
find_package(OpenCV REQUIRED)


message(STATUS "OpenCV Version:\t " ${OpenCV_VERSION})
include_directories(${OpenCV_INCLUDES})


add_executable(HalconParams2OpenCV main.cpp ParamsConvert.h )
target_link_libraries(HalconParams2OpenCV ${OpenCV_LIBS} )
           

具體精度有待進一步研究!~