Halcon自标定做畸变校正

一、Halcon有个算子可以实现利用单张图像,标定出相机内参,用来做畸变校正。不过对图片有要求,因为畸变越靠近图像边缘,就会越严重。所以要求图片的四周有足够的直线,最好图像中间部分也有足够的直线。提取这些直线,后面标定之后会把这些产生畸变的直线拉直,实现畸变校正。这个功能类似Visionpro里面的CheckBoard标定,只不过CheckBoard标定后,可以直接把像素坐标转换到世界坐标,转换后的图用来测量可以直接输出毫米mm。而Halcon自标定算子标定后,只能用于畸变校正。如需要用于转换到世界坐标,需要另加计算像素当量。
二、算子详解
2.1 radial_distortion_self_calibration(Contours : SelectedContours : Width, Height, InlierThreshold, RandSeed, DistortionModel, DistortionCenter, PrincipalPointVar : CameraParam)

名字:径向畸变自标定
描述:此算子通过XLD轮廓数据来估算镜头的畸变参数和畸变中心。其获得的即便参数通过相机内参数CameraParam返回。此算子不能矫正焦距和比例因子,因此不能用于3D测量中。

参数:
Contours :输入用来矫正的轮廓数据
SelectedContours :矫正后的轮廓数据
Width:获取轮廓数据的图像宽度
Height:获取轮廓数据的图像高度
InlierThreshold:分类阈值
RandSeed:随机种子
DistortionModel:畸变模式
DistortionCenter:畸变中心的估算模式,决定使用何种方式估计失真中心。有 ‘variable’(默认,适用于图像边缘轮廓线很多或者失真应该很高。否则,在寻找畸变中心时可能会出现不适定性,从而导致不稳定性。)‘adaptive’(如果可以假定畸变中心位于图像中心附近,并且只有很少的等值线可用或其他等值线的位置不好(例如等值线方向相同),则应使用这种方法), ‘fixed’(该方法适用于失真很弱或轮廓线少的情况下,在不好的位置。)
PrincipalPointVar :偏差控制,控制畸变中心与图像中心的偏差
CameraParam:输出相机内参数

2.2 change_radial_distortion_cam_par( : : Mode, CamParamIn, DistortionCoeffs : CamParamOut)

名字:矫正畸变参数
描述:根据指定的径向畸变系数,求取理想无畸变的相机内参。
参数:

Mode:畸变模式
CamParamIn:畸变的相机内部参数
DistortionCoeffs :畸变系数值
CamParamOut:已校正的相机内参

2.3 change_radial_distortion_image(Image, Region : ImageRectified : CamParamIn, CamParamOut : )
名字:矫正畸变图像
描述:根据指定图像和指定相加参数来矫正输入图像的畸变。change_radial_distortion_image根据摄像机内部参数CamParamIn和CamParamOut对输入图像图像的径向畸变进行改变。使用CamParamOut将位于区域区域内的输出图像的每个像素转换为图像平面,然后使用CamParamIn将其投影为图像的亚像素。通过双线性插值确定得到的灰度值。如果该亚像素在图像之外,则将图像重建中的对应像素设置为“黑色”并从图像域中消除。

参数:
Image:输入图像
Region :矫正图像的区域
ImageRectified :矫正图像
CamParamIn:输入相机参数
CamParamOut :输出相机参数
2.4 gen_radial_distortion_map(Map, CameraParam, CamParamOut, ‘bilinear’)
map_image(Imagecalib, Map, ImageMapped)
这两个算子联合可以实现2.3的图像畸变校正功能。
三、案例
3.1 Halcon官方案例

*这个程序展示了如何radial_distortion _selfcalibration可以用来
*校准径向畸变系数和中心
*扭曲。在程序的第一部分,从边缘提取
*一个图像用于校准。结果表明
*径向畸变提取相当准确的从单一
*图像。为了提高准确性,程序的第二部分显示
*如何从20张图像中提取的边缘可以用来执行
*校准。因为这些边出现在很多不同的方向
* 20张图片,主点可以确定的明显更多
*准确。
dev_update_off ()
read_image (Image, 'board/board-01')
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
disp_message (WindowHandle, 'Image with radial distortions', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* Extract subpixel-precise edges using the Canny filter.
edges_sub_pix (Image, Edges, 'canny', 1, 10, 40)
* Segment the edges into lines and circular arcs.
segment_contours_xld (Edges, SplitEdges, 'lines_circles', 5, 4, 2)
* Select edges that are long enough to be useful for the calibration.
select_shape_xld (SplitEdges, SelectedEdges, 'contlength', 'and', 30, 100000)
dev_display (Image)
dev_set_colored (12)
dev_display (SelectedEdges)
disp_message (WindowHandle, 'Extracted edges', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
disp_message (WindowHandle, 'Performing self-calibration...', 'window', 0, 0, 'black', 'true')
*执行径向畸变的自我校准。
radial_distortion_self_calibration (SelectedEdges, CalibrationEdges, 646, 492, 0.08, 42, 'division', 'variable', 0, CamParSingleImage)
*校正图像,即去除径向畸变。
get_domain (Image, Domain)
change_radial_distortion_cam_par ('fixed', CamParSingleImage, 0, CamParSingleImageRect)
change_radial_distortion_image (Image, Domain, ImageRectified, CamParSingleImage, CamParSingleImageRect)
* Display the distorted and undistorted image five times to visualize the
* differences between the images.
dev_display (Image)
dev_display (CalibrationEdges)
disp_message (WindowHandle, 'Edges used for calibration', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_display (ImageRectified)
disp_message (WindowHandle, 'Image without radial distortions', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* Now perform the self-calibration using edges extracted from 20 images.
* The variable Edges will accumulate the edges extracted from the images.
gen_empty_obj (Edges)
for J := 1 to 20 by 1
    read_image (Image, 'board/board-' + J$'02d')
    * Extract subpixel-precise edges using the Canny filter.
    edges_sub_pix (Image, ImageEdges, 'canny', 1, 10, 40)
    * Segment the edges into lines and circular arcs.
    segment_contours_xld (ImageEdges, SplitEdges, 'lines_circles', 5, 4, 2)
    * Select edges that are long enough to be useful for the calibration.
    select_shape_xld (SplitEdges, SelectedEdges, 'contlength', 'and', 30, 100000)
    * Accumulate the edges.
    concat_obj (Edges, SelectedEdges, Edges)
    dev_display (Image)
    dev_set_colored (12)
    dev_display (SelectedEdges)
    disp_message (WindowHandle, 'Edges extracted from image ' + J$'d', 'window', 0, 0, 'black', 'true')
endfor
dev_clear_window ()
dev_set_colored (12)
dev_display (Edges)
disp_message (WindowHandle, 'Collected edges from multiple images', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
disp_message (WindowHandle, 'Performing self-calibration...', 'window', 0, 0, 'black', 'true')
*执行径向畸变的自我校准。
radial_distortion_self_calibration (Edges, CalibrationEdges, 646, 492, 0.08, 42, 'division', 'variable', 0, CamParMultiImage)
dev_clear_window ()
dev_set_colored (12)
dev_display (CalibrationEdges)
disp_message (WindowHandle, 'Edges used for calibration', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*计算未失真图像的相机参数。
change_radial_distortion_cam_par ('fixed', CamParMultiImage, 0, CamParMultiImageRect)
for J := 1 to 20 by 1
    read_image (Image, 'board/board-' + J$'02d')
    get_domain (Image, Domain)
    *校正图像,即去除径向畸变。
    change_radial_distortion_image (Image, Domain, ImageRectified, CamParMultiImage, CamParMultiImageRect)
    * Display the distorted and undistorted image to visualize the
    * differences between the images.
    dev_display (Image)
    disp_message (WindowHandle, 'Image with radial distortions', 'window', 0, 0, 'black', 'true')
    wait_seconds (0.5)
    dev_display (ImageRectified)
    disp_message (WindowHandle, 'Image without radial distortions', 'window', 0, 0, 'black', 'true')
    wait_seconds (0.5)
endfor

原图
Halcon自标定做畸变校正_第1张图片
用来畸变校正的XLD
Halcon自标定做畸变校正_第2张图片
畸变校正后的图
Halcon自标定做畸变校正_第3张图片
3.2 个人编写案例

dev_update_off ()
read_image (Image, 'C:/Users/Dell/Desktop/Halocn自标定畸变校正/畸变校正.jpg')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_display (Image)
disp_message (WindowHandle, 'Image with radial distortions', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* Extract subpixel-precise edges using the Canny filter.
edges_sub_pix (Image, Edges, 'canny', 1, 10, 40)
* Segment the edges into lines and circular arcs.
segment_contours_xld (Edges, SplitEdges, 'lines_circles', 5, 4, 2)
* Select edges that are long enough to be useful for the calibration.
select_shape_xld (SplitEdges, SelectedEdges, 'contlength', 'and', 30, 100000)
dev_display (Image)
dev_set_colored (12)
dev_display (SelectedEdges)
disp_message (WindowHandle, 'Extracted edges', 'window', 0, 0, 'black', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_clear_window ()
disp_message (WindowHandle, 'Performing self-calibration...', 'window', 0, 0, 'black', 'true')
*名字:径向畸变自标定
*描述:此算子通过XLD轮廓数据来估算镜头的畸变参数和畸变中心。其获得的即便参数通过相机内参数CameraParam返回。
*此算子不能矫正焦距和比例因子,因此不能用于3D测量中。
*若相机模型为area(division),则相机参数为7个,若area(多项式),则相机参数12个。
*InlierThreshold值在0.010.5之间。值越小,精度越高,但是运算耗时长;值越大,越能容忍偏差。默认值0.05radial_distortion_self_calibration (SelectedEdges, CalibrationEdges, Width, Height, 0.08, 42, 'division', 'fixed', 0, CameraParam)
*名字:校正畸变参数
*描述:根据指定的径向畸变系数,求取理想无畸变的相机内参。
get_domain (Image, Domain)
change_radial_distortion_cam_par ('fixed', CameraParam, 0, CamParamOut)
*名字:校正畸变图像方法1
*描述:根据指定图像和指定相加参数来矫正输入图像的畸变。
change_radial_distortion_image (Image, Domain, ImageRectified, CameraParam, CamParamOut)
dev_display (Image)
dev_display (CalibrationEdges)

*校正畸变图像方法2,效果与方法1完全相同
gen_radial_distortion_map(Map, CameraParam, CamParamOut, 'bilinear')
map_image(Image, Map, ImageMapped)
dev_display (Image)
dev_display (ImageMapped)


*读写参数
* write_cam_par (CameraParam, 'D:/CameraParam.dat')
* write_cam_par (CamParamOut, 'D:/CamParamOut.dat')
* read_cam_par ('D:/CameraParam.dat', CameraParam1)
* read_cam_par ('D:/CamParamOut.dat', CamParamOut1)

原图
Halcon自标定做畸变校正_第4张图片

用来畸变校正的XLD
Halcon自标定做畸变校正_第5张图片
畸变校正后的图
Halcon自标定做畸变校正_第6张图片
原图
Halcon自标定做畸变校正_第7张图片
用来畸变校正的XLD
Halcon自标定做畸变校正_第8张图片
畸变校正后的图
Halcon自标定做畸变校正_第9张图片
四、遇到的问题
执行到radial_distortion_self_calibration函数的时候,报这个错误 No stable solution found: please change the inlier threshold or select contours manually (HALCON错误代码: 3661) 。
Halcon自标定做畸变校正_第10张图片
解决方法:
把算子radial_distortion_self_calibration的DistortionCenter参数设置为’fixed’或者’adaptive’即可
如果改成了’fixed’或者’adaptive’仍然报错,那么:
(1)把InlierThreshold的数值需要适当增大
(2)棋盘格的行与列数目需要适当增大
五、总结
halcon自标定的算子,它可以在不用标定板的情况下,标定出相机内参(无焦距),相对于多幅标定无法获取相机的外参。因为畸变一般在图像的边缘更严重,所以需要保证在图像的四周边缘有足够的直线线段。在实际项目中拍摄物体不可能都像例程中一样有理想的直线边缘,替代方法是:用菲林片制作一张网格黑色印制(10*10,可以根据自己实际情况调整)充满整个视野。求出了相机内参就可以进行畸变校正,因而自标定相对于多幅标定,在畸变校正方面更快捷,这样设备在现场更容易操作、维护。在畸变校正以后我们同样可以放置一个参考物求取像素当量,构建XY世界坐标系,以用于测量、定位等应用。后续若需要将像素单位换算至公有制单位,也可使用棋盘格、标准物、菲林片等进行转换,便可应用于测量项目;也可以利用一定网格构建XY坐标系,用于定位项目,这样在不借助标定板的情况下就可以畸变校正和测量类的项目。

你可能感兴趣的:(人工智能,算法,图像处理,计算机视觉)