标定板的质量对标定精度影响也是非常大的,我手上有一个陶瓷的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}
k1opencvk2opencvk3opencvp1opencvp2opencv=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中的标定参数
预先使用Halcon标定,得到标定参数模型(畸变模型选用多项式模型,不要用除法模型kappa),使用算子write_camera_setup_model保存参数模型,当然也可以直接读取,不保存参数~。
读取参数模型中的参数,得到焦距、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
)
get_cam_par_data
(CamParam0
, 'sy', sy0
)
get_cam_par_data
(CamParam0
, 'cx', cx0
)
get_cam_par_data
(CamParam0
, 'cy', cy0
)
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
)
得到参数:
导入到C++程序中
其实,setcameraMatrix_Halcon没什么用,可以不用添加。
使用转化后的OpenCV畸变系数实现校正
源文件
main.cpp主文件
设置参数并测试
#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);
camera0
.setcameraDistCoeffs_Halcon(954.86, 2.8045e+08, -2.35577e+13, 0.451309, 0.457282);
camera0
.setcameraRotation(0.0808079, 0.0137326, 0.996635, 0.996676, -0.0114733, -0.0806531, 0.0103271, 0.99984,
-0.0146141);
camera0
.setcameraTranspose(-0.129098 , -0.00118334 , 0.122701 );
Mat src_0
= imread("./0-0.bmp", 1);
namedWindow("Input_0", WINDOW_NORMAL
);
imshow("Input_0", src_0
);
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:
#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
);
void setcameraParams_Halcon(float focal_Halcon
,float sx_Halcon
,float sy_Halcon
,float Cx
,float Cy
);
void setcameraDistCoeffs_Halcon(float k1
,float k2
,float k3
,float p2
,float p1
);
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:
cv
::Mat cameraMatrix_Halcon
= cv
::Mat
::zeros(3, 3, CV_32F
);
cv
::Mat distCoeffs_Halcon
= cv
::Mat
::zeros(1, 5, CV_32F
);
double focal_Halcon
, sx_Halcon
, sy_Halcon
, Cx
, Cy
;
};
void CameraParams
::Halcon2OpenCV() {
distCoeffs_OpenCV
.at
<float>(0, 0) = distCoeffs_Halcon
.at
<float>(0, 0) * focal_Halcon
* focal_Halcon
;
distCoeffs_OpenCV
.at
<float>(0, 1) =
distCoeffs_Halcon
.at
<float>(0, 1) * focal_Halcon
* focal_Halcon
* focal_Halcon
* focal_Halcon
;
distCoeffs_OpenCV
.at
<float>(0, 4) =
distCoeffs_Halcon
.at
<float>(0, 2) * focal_Halcon
* focal_Halcon
* focal_Halcon
* focal_Halcon
*
focal_Halcon
* focal_Halcon
;
distCoeffs_OpenCV
.at
<float>(0, 2) = distCoeffs_Halcon
.at
<float>(0, 3) * focal_HalconMM
;
distCoeffs_OpenCV
.at
<float>(0, 3) = distCoeffs_Halcon
.at
<float>(0, 4) * focal_HalconMM
;
cameraMatrix_OpenCV
.at
<float>(0, 0) = (focal_Halcon
/ sx_Halcon
) ;
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
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
} )
具体精度有待进一步研究!~