常见的hlacon标定流程及其相关算子的解释

(一)halcon标定步骤


1、创建标定数据模型

使用算子 create_calib_data( : : CalibSetup, NumCameras, NumCalibObjects : CalibDataID)
CalibSetup:创建的内容
NumCameras:相机个数
NumCalibObjects :标定项目数
CalibDataID:标定句柄
例如:
create_calib_data (‘calibration_object’, 1, 1, CalibDataID)


2、设置相机内部初始值

使用set_calib_data_cam_param 算子设置相机内部初始值

set_calib_data_cam_param( : : CalibDataID, CameraIdx, CameraType, CameraParam : )
CalibDataID:标定句柄
CameraIdx:相机序号
CameraType:相机模型种类;面阵相机Division畸变模型’area_scan_division’;polynomial畸变模型’area_scan_polynomial’……

CameraParam :与相机模型种类相对应的参数;面阵相机Division畸变模型’area_scan_division’([Focus, Kappa, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight]);polynomial畸变模型’area_scan_polynomial’([Focus, K1, K2, K3, P1, P2, Sx, Sy, Cx, Cy, ImageWidth, ImageHeight]……


畸变模型选择
division畸变模型只适用于精度不高的,标定图片数量较少的情况:
polynomial畸变模型对径向畸变、切向畸变都进行矫正,精度较高,花费时间较长。

image.png

参数确定技巧
Focus代表焦距,按照我们镜头参数进行填写,远心镜头填写0
Kappa为畸变大小,因为在标定之前,所以默认填写0
Sx, Sy像元的宽高填写相机的像元尺寸。可以查相机手册,或者咨询相机厂家。
Cx, Cy填写图像的中心坐标
ImageWidth, ImageHeight填写图像的宽高

3、标定板初始化

使用算子 set_calib_data_calib_object
例如:
CaltabDescr := ‘caltab_100mm.descr’
set_calib_data_calib_object (CalibDataID, 0, CaltabDescr)


4、获取标定图片

标定板为正方形,尺寸大小为要照射区域宽度的1/3,相机拍摄或者读入9-16张图片,拍摄图片时标定板尽量覆盖整个视场;标定板圆点的直径不能小于10个像素。


5、使用图像进行相机内参标定,得到结果

方式一:

使用标定图像,直接用halcon全自动,进行标定

find_calib_object (Image, CalibDataID, CameraIndex, 0, PoseIndex, [], [])

得到标定数据

get_calib_data (CalibDataID, ‘camera’, 0, ‘type’, CameraType)


方式二:

1、寻找标定板区域,确定圆心,将结果加载到组元中

find_caltab(Image : CalPlate : CalPlateDescr, SizeGauss, MarkThresh, MinDiamMarks : )

find_marks_and_pose(Image, CalPlateRegion : : CalPlateDescr, StartCamParam, StartThresh, DeltaThresh, MinThresh, Alpha, MinContLength, MaxDiamMarks : RCoord, CCoord, StartPose)

set_calib_data_observ_points( : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx, Row, Column, Index, Pose : )

原理:首先find_caltab算子对图像高斯滤波(核大小为SizeGauss),接着阈值分割(阈值大小为MarkThresh)将标定板的区域找出来;
find_marks_and_pose算子对区域中的圆进行分割,找到圆的个数,周长,坐标等应该和标定板描述文件中的一致,
否则会自动调整StartThresh,使得StartThresh按照DeltaThresh步长减小到MinDiamMarks ,直到找到准确的圆心。


进行标定

calibrate_cameras( : : CalibDataID : Error) 返回平均投影误差Error


6、使用图像进行相机外参标定,得到结果

摄像机外参:决定摄像机坐标系与世界坐标系之间相对位置关系

其中Pw为世界坐标,Pc为摄像机坐标,T=(Tx,Ty,Tz)是平移向量,R=(a,b,r)是旋转矩阵,分别是绕摄像机坐标系Z轴旋转角度为r;绕摄像机坐标系Y轴旋转角度为b;绕摄像机坐标系X轴旋转角度为a。6个参数组成摄像机外参(a,b,r,Tx,Ty,Tz)

并且满足下式:

Pc=R*Pw+T


具体步骤:

set_calib_data_cam_param( : : CalibDataID, CameraIdx, CameraType, CameraParam : )

set_calib_data_calib_object( : : CalibDataID, CalibObjIdx, CalibObjDescr : )

find_calib_object(Image : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx, GenParamName, GenParamValue : )

get_calib_data_observ_contours( : Contours : CalibDataID, ContourName, CameraIdx, CalibObjIdx, CalibObjPoseIdx : )

get_calib_data_observ_points( : : CalibDataID, CameraIdx, CalibObjIdx, CalibObjPoseIdx : Row, Column, Index, Pose)

set_origin_pose( : : PoseIn, DX, DY, DZ : PoseNewOrigin)



参考代码:

**创建标定板
gen_caltab(7,7,0.008,0.5,'48_48mm.descr','48_48mm.ps')
           
*=======标定内参
dev_close_window ()
dev_open_window (0, 0, 652, 494, 'black', WindowHandle)
dev_update_off ()
dev_set_draw ('margin')
dev_set_line_width (3)
OpSystem := environment('OS')
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
           
*标定相机
StartCamPar := [0.0,0.0,0.0000299,0.0000299,4896/2,3264/2,4896,3264]
create_calib_data ('calibration_object', 1, 1, CalibDataID)
set_calib_data_cam_param (CalibDataID, 0, 'area_scan_telecentric_division', StartCamPar)
set_calib_data_calib_object (CalibDataID, 0, '48_48mm.descr')
           

for index := 1 to 13 by 1
    read_image (Image, '标定20/' + index + '.png')
    get_image_size(Image, Width, Height)
    dev_display (Image)
    find_calib_object (Image, CalibDataID, 0, 0, index, [], [])
    get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, index)
    dev_set_color ('green')
    dev_display (Caltab)
endfor
           
calibrate_cameras (CalibDataID, Error)
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
get_calib_data (CalibDataID, 'calib_obj_pose', [0,1], 'pose', PoseCalib)
           
*输出计算的相机内参
write_cam_par (CamParam, 'camera_parameters.dat')
           
           
Message:= '相机内参已经写入文件中'
disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false')
clear_calib_data (CalibDataID)
stop()
           
           
*=====标定外参
dev_set_draw ('margin')
dev_set_line_width (1)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
           
*从文件中读取内参 存储文件:camera_parameters.dat
try
    read_cam_par ('camera_parameters.dat', CamParam)
catch (Exception)
    stop ()
endtry
           
*开始计算
open_file('data.csv','output', FileHandle)
fwrite_string(FileHandle,'Dis_pix*0.0299204,Dis_m*1000,Distance')
fnew_line (FileHandle)
close_file(FileHandle)
           
*选择一张作为标定作为最终标定位姿(任意一张都可以)
index:=1
read_image (Image,'标定20/'+index+'.png')
dev_display (Image)
CaltabName := '48_48mm.descr'
create_calib_data ('calibration_object', 1, 1, CalibDataID)

set_calib_data_cam_param (CalibDataID, 0, 'area_scan_telecentric_division', CamParam)
set_calib_data_calib_object (CalibDataID, 0, CaltabName)
find_calib_object (Image, CalibDataID, 0, 0, 1, [], [])
get_calib_data_observ_contours (Caltab, CalibDataID, 'caltab', 0, 0, 1)
get_calib_data_observ_points (CalibDataID, 0, 0, 1, RCoord, CCoord, Index, PoseForCalibrationPlate)
dev_set_color ('green')
dev_display (Caltab)
dev_set_color ('red')
disp_caltab (WindowHandle, CaltabName, CamParam, PoseForCalibrationPlate, 1)
dev_set_line_width (1)
disp_circle (WindowHandle, RCoord, CCoord, gen_tuple_const(|RCoord|,1.5))
* caltab_points (CaltabName, X, Y, Z)
* calibrate_cameras (CalibDataID, Error)
* To take the thickness of the calibration plate into account, the z-value
* of the origin given by the camera pose has to be translated by the
* thickness of the calibration plate.
* Deactivate the following line if you do not want to add the correction.
set_origin_pose (PoseForCalibrationPlate, 0, 0, 0, PoseCalib)
* disp_continue_message (WindowHandle, 'black', 'true')
* stop ()
           
*像素距离
distance_pp(RCoord[0],CCoord[0],RCoord[48],CCoord[48], Dis_pix)
*像素直接转换mm然后计算
pix2mm(RCoord, CCoord,CamParam[2],CamParam[3],newCol,newRow)
distance_pp(newRow[0],newCol[0],newRow[48],newCol[48], Dis_m)
*用同一个世界坐标系来计算
image_points_to_world_plane(CamParam, PoseCalib,[RCoord[0],RCoord[48]], [CCoord[0],CCoord[48]], 'mm', X1, Y1)
distance_pp(Y1[0],X1[0],Y1[1],X1[1],Distance)
           
*输出计算结果比较
open_file('data.csv','append', FileHandle)
fwrite_string(FileHandle, Dis_pix*0.0299+','+Dis_m*1000+','+Distance+'\n')
close_file(FileHandle)    
           
Message:= '计算完毕'
disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false')
stop()




(二)halcon标定中常见算子


勇哥把几个常见的halcon标定相关的算子,机译了官方文档并适当修改,以方便查阅。


find_calib_object  http://www.skcircle.com/?id=1578


get_calib_data http://www.skcircle.com/?id=1579


get_calib_data_observ_points   http://www.skcircle.com/?id=1582


image_points_to_world_plane   http://www.skcircle.com/?id=1580

把图像坐标转化成Z=0平面的世界坐标,输出为世界坐标的X,Y


set_origin_pose   http://www.skcircle.com/?id=1581


calibrate_hand_eye  http://www.skcircle.com/?id=1568


affine_trans_point_3d

进行两个坐标系之间的3D坐标的仿射变换。


hom_mat3d_rotate_local

相对于新坐标系统,增加一个绕着某个坐标轴的旋量到齐次矩阵HomMat3D中,输出为新的齐次矩阵。


hom_mat3d_translate_local

相对于新坐标系统,增加一个平移量到齐次矩阵HomMat3D中,输出为新的齐次矩阵。


hom_mat3d_to_pose

把齐次矩阵转化为3D位姿态。利用0类代码,即先平移顺序RPT,旋转gba,以点的形式表达位姿。


pose_to_hom_mat3d

把3D位姿转化成齐次变换矩阵。


gen_image_to_world_plane_map

生成一个投影映射图,它描述了在一个世界坐标系中图像平面与z=0平面(测量平面)之间的映射。此映射可用于使用map_image操作符对图像进行校正。校正后的图像既无径向畸变,也无透视畸变;它对应于由垂直于测量平面的无畸变相机获取的图像


map_image

对图像进行校正,输出为校正后的图像。


pose_invert


hom_mat3d_compose

输出两个齐次矩阵的乘积。


project_3d_point

把3D点映射到图像坐标系,返回图像坐标系中该点的行列坐标。

即把摄像机坐标下的点投影到图像坐标系,输出为图像坐标系下的行列坐标


create_pose


disp_3d_coord_system


vector_to_pose

计算世界坐标和图像坐标之间关系的绝对位姿参数。其中世界坐标至少选择不在同一条直线上的三个点。
世界坐标上的点如果在一个平面上,应该选择'planar_analytic' 作为Method的参数。输出位姿和位姿质量。


disp_caltab

利用相机内外参数,把标定板模型投影到图像平面,显示标定点和连接线,X,Y轴也被显示出来。



get_cam_par_names

外部用户过程 ,用来按名称字符串取相机内参。内参名称如下:

['camera_type', 'focus', 'kappa', 'sx', 'sy', 'cx', 'cy', 'image_width', 'image_height']


contour_to_world_plane_xld

转换XLD轮廓进入Z=0的世界坐标平面,输出形式为xld_cont(-array) → object


3D位姿相关算子


create_pose                

创建3D位姿


hom_mat3d_to_pose         

齐次变换矩阵转换为3D位姿


pose_to_hom_mat3d        

3D位姿转换为齐次变换矩阵


convert_pose_type          

改变位姿类型


write_pose                 

将位姿写入本地文件


read_pose                 

从本地文件读取位姿


set_origin_pose       

沿着新轴转换位姿;


pose_invert              

翻转一个位姿


pose_compose               

两个位姿相乘



--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:
  • 评论列表:
  •  访客1225
     发布于 2020-12-25 22:19:17  回复该评论
  • 您好,勇哥,我又来了。在看您的第一部分相机标定时,有一点不太明白,为什么第二步中已经将摄像机内参输入进去了,后面还要进行摄像机的内参标定并返回误差呢,这误差是怎么求的呢?然后根据hand_eye_movingcam_calibration_poses.hdev这个示例,他的程序也是将相机内参文件输入了,然后又重新标定了一次,相机内参标定的意义不就是获取相机内参么,那既然有了为啥还要标定,有点晕了,希望得到您的帮助
    •  访客
       发布于 2020-12-26 11:07:35  回复该评论
    • 刚开始输入内参是初始值,后面计算出来的是修正值,因为你的相机位置、角度,焦点,光源等因素造成最终的内参跟硬件上标的会不一样
  •  访客
     发布于 2020-12-26 13:23:16  回复该评论
  • 勇哥, 我也是搞工业视觉这块, 如何联系上你, 方便加微信(18775342574)吗

发表评论:

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

会员中心
搜索
«    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