HALCON高级篇:3d相机标定(一)基础理论

引言:

勇哥注:所谓的3d相机标定并不是指的3d相机的标定,而是指的是3d空间做相机的标定,这个相机仍然是2D相机。
halcon的这套标定方法,同时可以应对测量、手眼标定。并且由于是在3d空间做标定,
因此你在做测量的时候相机和拍摄平面可以不是完全垂直,
或者物料可以任意方向倾斜(当然你的相机的景深要能做得到)。
如果你是做机器人手眼标定,这套标定方法无论是hand to eye,还是eye in hand,都可以搞定。
另外,你是四轴scara机器人还是串联的6轴机器人都可以的。
对于轴动的标定,也是没有问题的。
halcon的标定方法还可以实现相机标定和确定工作平面位姿进行分离。
这意味着你标定完相机后,你的测量平面可以随时改换。
halcon的这套3d相机标定方法不是一般的强,可以搞定现在工业机器视觉的绝大部分标定方面的应用。
至少勇哥还没发现有啥子应用它还做不到的。



创建标定数据模型


你可以用算子create_calib_data创建一个标定数据模型,指定相机和标定物体的数量。当用一个相机的时候,你也用一个单独的标定物体。

然后,你要做的是:

create_calib_data ('calibration_object', 1, 1, CalibDataID)
  • 指定相机内部参数的初始值

  • 描述标定物体


指定相机内参的初始值


你可以用算子set_calib_data_cam_param来设置相机内部参数。

除了标定数据模型,算子也需要下面的参数作为输入:

gen_cam_par_area_scan_division(0.008, 0, 5.2e-06, 5.2e-06, 640, 512, 1280, 1024, StartCameraParam)
set_calib_data_cam_param(CalibHandle, 0, [], StartCameraParam)
  • CameraIdx:相机的索引(0代表单个相机)

  • CameraType:相机的类型

  • CameraParam:相机内参初始值的一个元组


使用哪种畸变模型


对于面阵相机,两种畸变模型可供使用:划分模型(除法)和多项式模型。划分模型用一个参数来构造径向畸变,多项式模型用5个参数来构造径向和离心畸变。

image.png

划分模型的优势是畸变可以被快速的应用,尤其是对于反向畸变,例如如果世界坐标被映射到图像平面。还有,如果只有几张标定图像被使用或者视野覆盖不足,划分模型则会比多项式模型得到更稳定的结果。多项式模型的主要优势是它可以更精确的构造畸变,因为其用了更高阶的项去构造径向畸变,并且它也构造了离心畸变。需要注意的是,多项式模型不能够反推。因此,反向畸变必须被迭代计算看,其要比划分模型反向畸变的计算要慢。


一般的,划分模型应该被用来标定。如果标定的精度不高,可以用多项式模型。但是需要注意的是,被用于多项式模型的标定序列必须提供一个完整的区域覆盖,这个区域在后边用于测量。畸变可能会在没有被标定板覆盖的区域外边被不准确的构造出来。这种情况发生在图像边缘,也发生在标定板没有覆盖到的视野区域内部。


用算子set_calib_data_calib_object,你可以指定标定物体所需的信息。

如果你用的是HALCON的标定板,对应的描述文件名字就足够了。

set_calib_data_calib_object(CalibHandle, 0, 'E:/Program Files/MVTec/HALCON-19.11-Progress/calib/calplateHG30.cpd')


如何获得一个合适的标定板


确定给CCD相机的相机参数最简单的方法就是利用HALCON的标定板(如图1所示)。在这种情况下,找标定把的整个过程,提取标定标志点,以及决定提取标定标志点和各自3D世界坐标之间的对应关系都可以自动的被执行。更重要的是,标定板更加精确,1um或更小,对于高精度的应用其是前提条件。


两种类型的HALCON标定板是被支持的。尤其是,六角形排列的标志点和矩形排列的标志点的标定板是可行的。具有六角形排列的标定板是在HALCON12中引进的,在大多数应用中被推荐使用,因为相比于矩形排列标志点的标定板,其提供了如下的优点:


具有矩形排列标志点的标定板应该充满图像视野的四分之一。为了覆盖包括不同倾斜的整个视野,许多图像(至少10到20)是需要。因为六角形排列的标定板包含了众多数目的标志点,因此用单个图像就能够覆盖整个图像面积,更少的图像(6到7张)被需要去得到可比较的标定结果。

矩形排列标志点的标定板必须在图像全部可见的,然而六角形排列的标定板可以伸出图像的边缘。进而,当放置标定板的时候,后者就不需要太多的在意。标定板图像的获取就变的更快和方便,而没有稳定性的损失。

一个六边形排列的标定板在单张图像上应该充满整个图像区域。一个矩形排列的标定板应该至少覆盖图像区域的9分之一。为了提高标定的质量,我们推荐一个标定板至少覆盖图像区域的四分之一。


image.pngimage.png  image.png

图1:不同材质和尺寸的HALCON标定板:

(a)六角排列的标志板(蜂窝标定板)(b)矩形排列的标志板(矩阵标定板)


使用你自己的标定物体


利用HALCON,你不受限于使用一个平面标定板,例如HALCON标定板。你可以使用一个3D标定板或者甚至任意特征点(自然的标志)。仅有要求就是模型点的3D世界位置是已知的,并且具有很高的精度。

然后,你就简单将标定物体的所有点(标志点)的3D坐标作为一个元组传到算子set_calib_data_calib_object中的CalibObjeDescr。所有点的x,y,z坐标必须以【x,y,z】元组的顺序进行打包。

然而,需要主要的是,如果你用自己的标定物,你就不能再用find_calib_object。相反,你必须自己来确定模型点的2D位置和对3D点的对应关系。


在多位姿上观察标定物


标定的主要输入数据是所谓的观察。为此,标定物在不同的位姿被放置。对于每一个位姿,相机获取一张图像。在这张图像上,标定物的标志点被提取,还有他们的(像素)坐标,连同相机的索引,标定物,标定物的位姿,包含响应标志点的索引,都被存储在标定数据模型中。


如果你使用标准的HALCON标定板,你可以用算子find_calib_object去提取坐标,其将自动存储获得的信息到标定数据模型,包括标志点的坐标和标志点对应的列表。

for Index := 0 to |ImageFiles|-1 by 1
    read_image (Image, ImageFiles[Index])
    find_calib_object (Image, CalibHandle, 0, 0, Index, TmpCtrl_FindCalObjParNames, TmpCtrl_FindCalObjParValues)
endfor


如果你用的是自己的标定物,你必须提取其标志点和确定其对应关系,然后用set_calib_data_observ_points将信息存储在标定数据模型中。


获取标定图像的规则


如果你想获得准确的结果,请准照下面的规则:


  • 用一个干净的标定板

  • 用多个图像覆盖整个视野,例如在视野所有区域至少放置标定一次

  • 变换标定板的方向,包含标定板绕着x轴和y轴旋转,这样标定图案的透视畸变是清晰可见的。没有一些倾斜的标定板,焦距是不能够被合理的计算出来(接近45度的倾斜角度是被推荐的)

  • 对于六角形排列的标定板,至少使用6张图像,矩形排列的标定板10到15张

  • 对于矩形排列的标定板,用一个背景比标定板更暗的光照

  • 标定把亮的部分的灰度值至少为100

  • 标定板的亮暗对比应该超过100

  • 用一个使标定板均匀的光照

  • 图像不能过曝(图像亮的部分应该严格低于255)

  • 圆的直径应该至少20个像素

  • 圆的直径的像素至少20个像素

  • 对于标定板大小的选取,六角形排列的标定板应该覆盖整个图像,对于矩形排列的标定板,至少覆盖整个图像的1/4

  • 六角形排列的标定板,至少一个定位图像在图像中是完全可见的。如果至少两个定位图是可见的,可能去检测是否标定板是反射的。对于矩形排列的标定把,标定应该在图像中完全可见的。

  • 图像应该尽可能的包含一点噪声

  • 图像应该被严格聚焦,例如在物体之间的过度应该被清晰的界定开。

需要注意的是,一个好的标定结果仅仅是在相机视野中标定标志点均匀分布的情况下才能获得。你可以想象一下相对于视野的3D空间的一部分作为一个标定体积,如图2所示,这里展示了,当从不同角度看时,标定板的两个位姿和它们标定标志点的位置。可以看到,例如从面1看,更大的部分没有被标志点所覆盖。为了获得更标志点的均匀分布,进而得到一个好的标定结果,你必须在你其他的图像中放置标定板,进而对于整个视角,标定容积空的部分被最小化。注意的是,当有一个非常小的标定板(相比于视野而言),这就意味着比推荐的更多的标定图像数量被需要使用。


如果一张图像被用于标定过程或者如果标定板的方向在不同的标定图像不发生变化,就不可能很好的确定焦距和相机的位姿;在这种情况下,仅仅聚焦之间的比率和标定板和相机之间的距离被确定下来。然而,在标定板平面进行世界坐标的测量是可能,但是不可能去让相机参数去适应在另一个面上进行测量,例如标定板被放置的面。

image.png


图2: 标定容积的查看:(左)具有两个标定位姿的标定容积和

(右)当不同角度看时,标定标志点相对应的分布。

对于一个好的标定结果,没有标定标志点的区域(尤其从面1视角则更大)必须通过更多标定板位姿的谨慎选择达到最小化。


结果世界坐标的精度,除了在图像中的测量精度外,非常依赖被用来标定进程中所用的图像的数量。越多图像(具有更大不同的标定板位姿)被使用,更精确的结果将被获取。


提取HALCON标定板上的标志点


算子find_calib_object寻找标定板,决定了标定标志点的图像坐标,并具有很高的精度,最后将结果存储在标定数据模型中。

需要注意的是find_caltab和find_marks_and_pose仅仅被用于矩形排列的标定板。还有,它们需要复杂的参数调整。相反的是,可以用于所有标准的HALCON标定板,自动选择合适的参数,因此更容易去使用。


限制标定到特定的参数


如果某相机参数已知了,你可以用算子set_calib_data从标定中排除它们,类似的,你可以限制标定到某些参数。


执行标定


在准备了标定数据模型以后,可以通过调用calibrate_cameras来执行标定,用标定数据模型作为输入:

calibrate_cameras (CalibHandle, Errors)


作为一个直接结果是,仅仅是标定错误被返回。你可以用算子get_calib_data来更进一步的去分析标定结果的质量。

主要的标定结果,例如相机的内参,被存储在标定数据模型中。


访问标定结果


算子calibrate_cameras的主要结果由相机内参和每一张图像标定板的位姿组成。算子将它们存储在标定数据模型中,可以用算子get_calib_data来访问它们。

get_calib_data(CalibHandle, 'camera', 0, 'params', DataValue)
write_cam_par(DataValue, '内参.cal')


相机外参并不能直接被获取,因为所需的世界坐标系统的信息没有存储在标定数据模型中。然而,如果标定板被直接放置在测量平面上,其位姿可以被用来很容易的得到相机的外参,其是测量平面的位姿。


确定相机外参


相机外参描述了测量平面和相机的关系,例如如果仅仅外参是已知,就可能将相机坐标系统(CCS)转化到测量平面的坐标系统,反之亦然。在HALCON中,测量平面被定义为世界坐标系统(WCS)z=0的平面。


相机外参可以用不同的方法来确定:


1. 利用从某一个标定图像获取的位姿,其中标定图像中标定板被直接放置在测量平面上。在这种情况下,你就可以用算子get_calib_data来获得其位姿。

2. 通过一个标定板被直接放置在测量平面的额外图像,将相机内参的确定从相机外参的确定分离出来。应用find_calib_object去提取标定标志点和位姿。

3. 自己去确定3D世界点和它们在图像映射的对应关系,然后调用vector_to_pose。

如果你仅仅需要去精确地测量一个物体的尺寸,而不是在一个给定坐标系统的物体的绝对位置,前两种方法中一种就可以使用。


后两种情况具有相机外参的决定不依赖相机内参的优势。如果用单个相机在数个平面上做测量,或者不能在原地标定相机,这将是更加灵活和有用。

下面将对不同的情况做详细的讲解。


在标定图像之一将标定板放置在测量平面上


第一种情况是一种最容易决定外参的方法。标定板必须直接放置在测量平面上,例如流水线。


因为通过算子calibrate_cameras,标定板的位姿可以确定下来,你可以通过算子get_calib_data简单的访问其位姿。这样,用一个单一的标定步骤,内参和外参就能确定下来。这里,在第一个标定图像中标定板(标定物索引0)的位姿被确定。请注意的是每一个位姿是由7个值组成的。

get_calib_data(CalibHandle, 'calib_obj_pose', [0,1], 'pose', DataValue1)


如果标定把是无限的薄的,结果位姿将是测量平面的真实位姿。因为真实的标定板有一个厚度d>0,标定板的位姿通过一个垂直于测量平面的量d的移动,例如沿着WCS的z轴。为了矫正它,我们需要沿着WCS的z轴去移动位姿d个单位。为了执行这个移动,使用算子set_origin_pose:

set_origin_pose (CameraPose, 0, 0, 0.003, CameraPose)


一般地,只要标定板和测量平面的空间关系是已知的,标定板在WCS中就可以任意地锁定方向(如图3所示)。然后,为了从标定板位姿中获得测量平面的位姿,一个刚性转换时必须的。在下面的例子中,标定板的位姿沿着y轴平移,接着绕着x轴旋转。

pose_to_hom_mat3d(TmpCtrl_RectificationPose, HomMat3D)
hom_mat3d_translate_local(HomMat3D, 0, 1, 0, HomMat3DTranslate)
hom_mat3d_rotate_local(HomMat3D, rad(180), 'z', HomMat3DRotate)
hom_mat3d_to_pose(HomMat3DRotate, TmpCtrl_RectificationPose)


在一个单独图像中放置标定板在测量平面上


如果用HALCON标定板的优势可以将相机内参和外参分离所具有的灵活性相结合,第二种相机外参确定的方法可以使用。

首先,相机按照标定步骤进行标定。这可以优先于相机在最终使用点安装之前完成。

然后,在最终使用点安装完相机以后,外参就可以被确定。仅仅需要做的就是取一张图,图中标定被直接放在了测量平面上。从这张图中,外参就可以被确定下来。这里,内参,标定板被直接放在测量平面上的图像和标定标志点的世界坐标可从文件中读取。

read_cam_par('camera_parameters.data',CamParam)
read_image(Image,ImgPath+'calib_11')


然后,标定标志点和标定板的位姿被提取:

find_calib_object(Image,CalibDataID,0,0,1,[],[])


最后,考虑到标定板的厚度,被给相机位姿原点的值平移标定板厚度个单位。

set_origin_pose(PoseForCalibrationPlate,0,0,0.00075,PoseForCalibrationPlate)


image.png

图3标定板和测量平面的关系


需要注意的是,如果你想将标定步骤分为两个部分来完成的话,相机的聚焦是很重要的,因为改变焦点就相当于改变焦距,其是内参的一部分。


利用已知的3D点和它们对应的图像点


如果在给定的世界坐标系统中执行测量是必要的,对于外参的确定,第三种情况就可以使用。这里,你需要知道至少不再一条直线上3个点的3D世界坐标,然后,你必须确定这些点映射后相对应的图像坐标。现在,算子vector_to_pose可以被用来确定相机的外参。


下面的程序作为一个确定外参的例子。


首先,三个点的世界坐标被设定。

X:=[0,50,100,80]
Y:=[5,0,5,0]
Z:=[0,0,0,0]


然后,在图像上这些点映射后的图像坐标被确定。在这个例子中,它们被很简单的设定位一些接近的值。实际上,它们应该以亚像素的精度确定下来,因为他们定义了相机外参。

RCoord:=[414,227,85,128]
CCoord:=[119,318,550,448]


最后,算子vector_to_pose在已知对应关系和相机内参的情况下,被调用。

vector_to_pose(X,Y,Z,RCoord,CCoord,CamParam,'iterative','error',FinalPose,Errors)


从标定数据模型中删除观测图


为了确定有关标定的观测效果,或者从标定数据模型中移除坏质量的观测数据,可以用算子remove_calib_data_observ删除一个观测图。

当再次执行相机标定的时候,需要注意标定错误的改变。


保存结果和销毁标定数据模型


在访问结果(或者用算子write_cam_par和write_pose来存储它们),你可以借助算子clear_calib_data销毁标定数据模型。


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864