HALCON到OpenCV失真系数的转换

问题描述 投票:1回答:1

我有一个经过校准的多相机系统。内部(焦距,失真等)和外部(姿势)相机参数均已使用基于HALCON的程序进行了估算。现在,目标是编写一个C ++程序,以读取相机参数,尤其是由HALCON估计的失真系数(k1,k2,k3,p1,p2),并使用它们来使用OpenCV消除图像失真。不幸的是,到目前为止,我无法成功:HALCON和OpenCV中使用的相同失真系数会生成非常不同的未失真图像!我想,问题在于HALCON和OpenCV解释失真系数的方式,甚至是它们执行不失真的方式。

这是我的HALCON代码,用于读取失真系数并使用它们使测试图像不失真:

* Read the internal camera calibratino parameters ('area_scan_polynomial' model)
read_cam_par('Calibration.dat', CamParam)

* Estimate camera parameters without distortion: set all distortion coefficients to [k1, k2, k3, p1, p2] = [0, 0, 0, 0, 0] 
change_radial_distortion_cam_par ('fixed', CamParam, [0, 0, 0, 0, 0], CamParamOut)

* Estimate camera matrix of distortion-free parameters (used for OpenCV)
cam_par_to_cam_mat(CamParamOut, CamMatrix, ImageWidth, ImageHeight)

* Generate map to use for undistortion. 
* Note the use of type 'coord_map_sub_pix' which is of type 'vector_field_absolute', 
* i.e. the values are 2D absolute coordinates of the corresponding undistorted pixel location
gen_radial_distortion_map(Map, CamParam, CamParamOut, 'coord_map_sub_pix')

* Read a test image and undistort it using the estimate map
read_image (Image, 'test.jpg')
map_image(Image, Map, ImageRectified)

我正在尝试使用以下代码在OpenCV中做完全相同的事情:

Mat view , rview, mapx, mapy;

// Read the same test image as in HALCON
view = imread("test.jpg");

// Get the image size
const Size viewSize = view.size();

// Generate map to use for undistortion
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
    cameraMatrix, viewSize, CV_16SC2, mapx, mapy);

// Undistort the image using the estimated map
remap(view, rview, mapx, mapy, INTER_LINEAR);

OpenCV中的变量“ cameraMatrix”等于HALCON中的变量“ CamMatrix”。 OpenCV中的失真系数“ distCoeffs”来自HALCON(k1,k2,k3,p1,p2),并按照以下方式按照文档进行重新排列:

distCoeffs = (Mat_<double>(5, 1) << k1, k2, p2, p1, k3)

注意,提供了k3作为第五个参数,并且交换了p2和p1。根据HALCON文档(https://www.mvtec.com/doc/halcon/12/en/calibrate_cameras.html,请参见函数calibrate_cameras),从失真的(u',v')计算图像平面(u,v)中的未失真坐标为:]

u = u'+ u'(k1 r ^ 2 + k2 r ^ 4 + k3 r ^ 6)+ p1(r ^ 2 + 2 u'^ 2)+ 2 p2 u'v'

v = v'+ v'(k1 r ^ 2 + k2 r ^ 4 + k3 r ^ 6)+ p2(r ^ 2 + 2 v'^ 2)+ 2 p1 u'v'

具有r = sqrt(u'^ 2 + v'^ 2)

虽然在OpenCV中[https://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html,请参见函数initUndistortRectifyMap),相同的未失真坐标也类似地估算,只有p1和p2被交换。

显然,OpenCV和HALCON都将像素相似地投影到图像平面中。也就是说,具有像素(x,y)的相应图像平面坐标计算为:

u'= x-cx / fx

v'= y-cy / fy

这些当然可以背投影以重新获得相应的像素坐标:

x = u'* fx + cx

y = v'* fy + cy

根据文档,似乎所有功能都应按预期工作。但是,我不明白为什么HALCON和基于OpenCV的代码仍会输出截然不同的结果。我注意到,要产生与HALCON类似的未失真结果(但不完全相同),我必须缩小(约100倍!)OpenCV中的失真系数。实际上,我注意到HALCON估计了巨大的失真系数。例如,要在未失真的图像中产生可见的变化,我必须在HALCON k1 = 1000中进行设置,而在OpenCV k1 = 1中已经明显地更改了图像。对于某些失真系数,我什至不得不将其值取反(减号),以获得在相似方向上未失真的结果...

我进一步挖掘了HALCON的不失真代码,并尝试根据文档手动估算未失真的坐标(u,v),该坐标应对应于“地图”中的坐标。我这样做是为了确保“地图”确实按照文档中指定的方式/我理解的方式进行了估算。但是,即使在这里,与“地图”中估计的结果相比,我得到的结果也大不相同...为了进行测试,我使用了以下代码:

* Get the camera parameters from the calibration
get_cam_par_data (CamParam, 'k1', k1)
get_cam_par_data (CamParam, 'k2', k2)
get_cam_par_data (CamParam, 'k3', k3)
get_cam_par_data (CamParam, 'p1', p1)
get_cam_par_data (CamParam, 'p2', p2)
get_cam_par_data (CamParam, 'cx', cx)
get_cam_par_data (CamParam, 'cy', cy)
get_cam_par_data (CamParam, 'image_width', width)
get_cam_par_data (CamParam, 'image_height', height)

* Estimate the camera matrix, to read the focal length in pixel
cam_par_to_cam_mat(CamParamOut, CamMatrix, width, height)

* Extract the focal lenths in pixel from the estimated camera matrix (see above)
fx_px := CamMatrix[0]
fy_px := CamMatrix[4]

* Pick a pixel coordinate (I tried different values) in the image domain
x := 350
y := 450

* Convert into image plane coordinates
u_1 := (x - cx) / fx_px
v_1 := (y - cy) / fy_px

* Estimate the undistorted location u_2 and v_2
r2 := u_1 * u_1 + v_1 * v_1
u_2 := u_1 * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2) + 2 * p1 * u_1 * v_1 + p2 * (r2 + 2 * u_1 * u_1)
v_2 := v_1 * (1 + k1 * r2 + k2 * r2 * r2 + k3 * r2 * r2 * r2) + 2 * p2 * u_1 * v_1 + p1 * (r2 + 2 * v_1 * v_1)

* Back to pixel coordinate
x_1 := u_2 * fx_px + cx
y_1 := v_2 * fy_px + cy

* Compare the values with the value in Map (estimated as before). G_found and G_est should match!
G_found := [y_1, x_1]
get_grayval(Map, y, x, G_est)

我尝试一次集中处理几个失真系数,即仅k1> 0,其他设置为0。但是,在大多数情况下(x = cx,y = cy很少例外),未失真的坐标超过了图像大小甚至变成负数。

这不是HALCON估算不失真地图坐标的方式吗?我想念什么吗?如何将这些失真系数转换为OpenCV,以产生完全相同的未失真结果图像?任何帮助将不胜感激!

由于某些软件限制,使用OpenCV进行校准和不失真是有争议的,但是不幸的是,对于我来说,这不是一个可接受的解决方案。

c++ opencv camera-calibration distortion halcon
1个回答
0
投票

不幸的是,HALCON和OpenCV校准参数之间没有直接转换,因为基础模型和参数的估算方式不同。 HALCON参数描述了从扭曲坐标到未扭曲坐标的转换,而OpenCV参数描述了相反的转换。由于多项式等级较高,因此无法进行转换。 OpenCV中不存在可以解析地求逆的除法模型。

© www.soinside.com 2019 - 2024. All rights reserved.