引言:
勇哥注:所谓的3d相机标定并不是指的3d相机的标定,而是指的是3d空间做相机的标定, 这个相机仍然是2D相机。 halcon的这套标定方法,同时可以应对测量、手眼标定。 并且由于是在3d空间做标定,因此你在做测量的时候相机和拍摄平面可以不是完全垂直, 或者物料可以任意方向倾斜(当然你的相机的景深要能做得到)。 如果你是做机器人手眼标定,这套标定方法无论是hand to eye,还是eye in hand,都可以搞定。 另外,你是四轴scara机器人还是串联的6轴机器人都可以的。 对于轴动的标定,也是没有问题的。 halcon的标定方法还可以实现相机标定和确定工作平面位姿进行分离。 这意味着你标定完相机后,你的测量平面可以随时改换。 halcon的这套3d相机标定方法不是一般的强,可以搞定现在工业机器视觉的绝大部分标定方面的应用。 至少勇哥还没发现有啥子应用它还做不到的。
径向畸变校准
首先要谈一下畸变的模形。
畸变主要分为径向畸变、切向畸变和薄棱镜畸变。
1.径向畸变
径向畸变主要由透镜本身导致的,远离透镜中心的光线比靠近中心的光线弯曲的更严重。图1显示矩形网格因镜像畸变而产生的位移。从前面看,光心越向外,矩形网格上的点的位移越大。


(图1.1)

(图1.2)
图1.1 透镜的径向畸变图,箭头显示径向畸变图像上外部矩形网格的偏移
图1.2 注解

图2显示了两种典型的径向畸变,分别为桶形畸变和枕形畸变
2.切向畸变
切向畸变主要由镜头安装导致,当透镜不完全平行于图像平面的时候产生切向畸变。下图显示了某透镜的切向畸变图像。



3.薄棱镜畸变
薄棱镜畸变一般由镜头设计和加工安装误差导致,一般情况下,可忽略此畸变。
径向畸变的校正方法
有两种:
(1)仅使用内参
(2)使用内参与位姿
(1) 仅使用内参
算子 change_radial_distortion_cam_par 根据指定的径向变形确定新的相机参数。
详细见:https://www.skcircle.com/?id=1595
change_radial_distortion_image 更改图像的径向变形。详细见:https://www.skcircle.com/?id=1598
演示代码是halcon的例程:change_radial_distortion_image.hdev
read_image (Image, 'pioneer')
rgb1_to_gray (Image, GrayImage)
gen_cam_par_area_scan_division (0.00219846, -78129.2, 5.46495e-06, 5.5e-06, 318.206, 236.732, 640, 480, CamParIn)
change_radial_distortion_cam_par ('adaptive', CamParIn, 0, CamParOut)
change_radial_distortion_image (GrayImage, GrayImage, ImageRectified, CamParIn, CamParOut)

另一种打法是:
change_radial_distortion_cam_param() 更新径向畸变参数 gen_radial_distorition_map() 形成映射矩阵 map_image() 图像映射
勇哥把上面例子改写一下:
read_image (Image, 'pioneer')
rgb1_to_gray (Image, GrayImage)
gen_cam_par_area_scan_division (0.00219846, -78129.2, 5.46495e-06, 5.5e-06, \
318.206, 236.732, 640, 480, CamParIn)
change_radial_distortion_cam_par ('adaptive', CamParIn, 0, CamParOut)
*change_radial_distortion_image (GrayImage, GrayImage, ImageRectified, CamParIn, CamParOut)
gen_radial_distortion_map(Map, CamParIn, CamParOut, 'bilinear')
map_image(Image, Map, ImageMapped)效果是一样的,只不过不是直接对图片进行处理,而是先生成一个映射图像,然后再用map_image校正图像。
使用这种方式主要是批量处理图片时占有速度上的优势,这个时候你可以用一张Map循环校正全部图片。
即map_image速度上优于直接change_radial_distortion_image。

另外一个生成校正映射图的算子是gen_arbitrary_distortion_map 生成投影图,该投影图描述任意失真的图像和校正后的图像之间的映射。
这个算子其效果上来看有点像透视畸变校正,勇哥也有点搞晕了,以后搞清楚区别再写一篇介绍一下吧。
(2) 使用内参与位姿
程序演示了如何校准径向畸变的图像,及怎么样把一个畸变图上的点转换为没有畸变的位置。
演示代码:
*该程序演示如何从径向畸变图像中提取点坐标进行校正。这是通过使用存储在相机参数(CamParam)
*中的径向畸变参数来更改“径向畸变”点来完成的
dev_close_window ()
dev_update_off ()
read_image (Image, 'calib/calib_distorted_01.png')
dev_open_window_fit_image (Image, 0, 0, [600,800], [400,600], WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_line_width (2)
* Read camera parameters and prepare radially corrected camera parameters
* 读取摄像机参数并准备径向修正的摄像机参数
gen_cam_par_area_scan_polynomial (0.00506526, 5142.64, -1.98485e+08, -4.26734e+12,\
0.0462524, 0.114147, 9.30055e-06, 9.3e-06, 276.713, 266.078, 640, 512, CamParam)
change_radial_distortion_cam_par ('fixed', CamParam, [0.0,0.0,0.0,0.0,0.0], CamParamOut)
*
for I := 18 to 34 by 1
Filename := 'calib/calib_distorted_' + I$'02'
read_image (Image, Filename)
* Convert image to 'byte'
min_max_gray (Image, Image, 0, Min, Max, Range)
scale_image_range (Image, ImageScaled, Min, Max)
convert_image_type (ImageScaled, ByteImage, 'byte')
* Find mark centers
find_caltab (ByteImage, Caltab, 'caltab_100mm.descr', 3, 112, 5)
find_marks_and_pose (ByteImage, Caltab, 'caltab_100mm.descr', CamParam,\
128, 10, 18, 0.9, 15, 100, Row, Column, StartPose)
* Rectify the mark centers
* 校正标记中心
change_radial_distortion_points (Row, Column, CamParam, CamParamOut, RowChanged, ColChanged)
* Prepare output points
gen_cross_contour_xld (Cross, Row, Column, 12, rad(45))
gen_cross_contour_xld (CrossChanged, RowChanged, ColChanged, 12, rad(45))
* Show results
dev_display (ByteImage)
dev_set_color ('magenta')
dev_display (Cross)
dev_set_color ('green')
dev_display (CrossChanged)
**
*Extracted centers 提取中心
*Corrected centers 校正中心
disp_message (WindowHandle, ['Extracted centers (magenta \'x\')',\
'Corrected centers (green \'x\')'], 'window', 10, 10, ['magenta','forest green'], 'true')
wait_seconds (0.2)
endfor
disp_continue_message(WindowHandle, 'black', 'true')
stop ()
change_radial_distortion_image (ByteImage, ByteImage, ImageRectified, CamParam, CamParamOut)
dev_display (ByteImage)
dev_set_color ('magenta')
dev_display (Cross)
disp_message (WindowHandle, 'Original image and extracted centers', 'window',\
10, 10, 'magenta', 'true')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
dev_display (ImageRectified)
dev_set_color ('green')
dev_display (CrossChanged)
disp_message (WindowHandle, 'Corrected image and centers', 'window', 10, 10,\
'forest green', 'true')下图中桃红色的点是提出的点,绿色是畸变校准后的点的位置。

这是原图及标定板上提取的点。

image被校正了径向畸变的效果。现在的绿色点都是被校正后的位置。可以理解为原来桃红色点与绿色点现在已经重合了。

最后谈几个问题:
(1) halcon能校准切向畸变吗
不知道,在网上根本没有人谈过halcon怎么进行切向畸变校准,到是opencv中有人谈到过。
(2) 定位应用中是先图像校正畸变再进行像素世界坐标的转换吗
是的。在要获取内参的位置请使用经过change_radial_distortion_cam_par修改后的内参。
(3) 怎么判断你的CCD拍出来的畸变类型?
不知道,没人谈论这个话题。
下面这篇文章谈到如果看你的图像是否畸变,但没有谈畸变类型。
如何测试成像畸变 https://www.skcircle.com/?id=1190
(4) 透视畸变什么情况下用?
透视是个正常的现象,勇哥现在也不知道啥时候需要做透视畸变校准。上节课举的一个例子实际上只是演示有这么一个功能。
看了一下opencv中的透视畸变校正的例子,例如下图这样:

但是我们halcon是搞的机器视觉,不是用来搞这样的生活图片应用。如果有兄弟知道透视畸变的修正什么项目能用得上,麻烦告诉我,感谢。
真正需要校正的畸变,目前看只有径向畸变。
总结:畸变这个话题看来还是有一些不解的地方,知道的朋友请不吝赐教!
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!