QQ登录

只需一步,快速开始

6.4 halcon相机标定结果的应用

[ 复制链接 ]
相机标定之后,我们会得到相机的内参,和相机的外参。
然而这些结果我们如何在实际项目中使用?当前这个帖子演示使用标定板标定后,
直接测量标定板的宽与标定板标定黑点的圆心
具体思路是 建立 标定 模型,加载设定相机的初始化信息及标定 板描述文件,
找到标定板并进行多张图像的标定 ,得到相机内参与外参数。
对要测量的区域 进行像素 处理和拟合测量,得像素 距离。
根据 相机内参 外参及像素距离求出对应世界坐标系下点的坐标及对应轮廓长度。

6.4 halcon相机标定结果的应用

6.4 halcon相机标定结果的应用

下面是实例源代码及注释:
  1. *关闭当前打开的窗口
  2. dev_close_window ()
  3. *打开背景黑色窗口,左上角,右下角坐标为0, 0, 768, 576
  4. dev_open_window (0, 0, 768, 576, 'black', WindowHandle)
  5. *关闭窗口更新功能
  6. dev_update_off ()
  7. *设置绘制边缘模式
  8. dev_set_draw ('margin')
  9. *设置线宽为3
  10. dev_set_line_width (3)
  11. set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
  12. *定义变量指向标定板描述文件。
  13. CalTabDescrFile := 'caltab_big.descr'
  14. *定义数组并初始化
  15. StartCamPar := [0.008, 0, 0.0000086, 0.0000086, 384, 288, 768, 576]
  16. *创建标定板数据模型,用于存储标定数据,标定 文件,标定过程中的设置等。
  17. *参数'calibration_object'表示标定类型,这里表示 一般的相机标定,如果是手眼标定
  18. *则是其他类型,可以参考帮助文档的各种标定类型,参数2表示相机数据为1,
  19. *参数3表示标定板数量为1,CalibDataID为输出句柄,表示标定模型句柄。
  20. create_calib_data ('calibration_object', 1, 1, CalibDataID)
  21. *设置用于标定的相机参数与类型,CalibDataID为前面创建的模型句柄,
  22. *0为相机索引,当有多个相机时,通过此参数与相机对应, []表示相机类型,这里默认表示面扫相机,
  23. *StartCamPar表示相机内参,按照顺序分别对应内参为【f, k, Sx, Sy, Cx, Cy, w, h】
  24. set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar)
  25. *设置标定板的描述文件,0为标定板索引,CalTabDescrFile为标定板文件名。
  26. set_calib_data_calib_object (CalibDataID, 0, CalTabDescrFile)
  27. *循环读入10张图处理。
  28. NumImages := 10
  29. for I := 1 to NumImages by 1
  30.     read_image (Image, 'calib/calib-3d-coord-' + I

  31. 02d')
  32.     dev_display (Image)
  33.     Message := 'Find calibration plate in\nall calibration images (' + I + '/' + NumImages + ')'
  34.     disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
  35.     * 在图中找到标定板获得相关信息,Image为输入图像, CalibDataID为输入标定模型句柄
  36.     *0, 0分别表示相机和标定板索引为0, I - 1表示标定板姿态索引,从0开始计数,
  37.     *[], []为要设置的参数及参数所对应的数值,这里留空不使用。
  38.     find_calib_object (Image, CalibDataID, 0, 0, I - 1, [], [])
  39.    *获取标定数据,CalibDataID为输入的模型句柄, 'camera'为模型中数据 项类型为相机类型,
  40.    *参数三为数据类型的索引,参数四为数据项名称,也就是想得到哪个数据,'init_params'表示
  41.    *我们想得到相关初始化参数,StartCamPar为所得到的数据项值。
  42.     get_calib_data (CalibDataID, 'camera', 0, 'init_params', StartCamPar)
  43.     *得到模型中的标定信息,CalibDataID, 0, 0分别人模型输入句柄,相机和标定板对应索引为0.
  44.     *I - 1为标定板姿态索引,从0计数。 Row, Column, Index, Pose为输出参数,分别表示为
  45.     *标定点圆心坐标,索引及预估的相机外参。
  46.     get_calib_data_observ_points (CalibDataID, 0, 0, I - 1, Row, Column, Index, Pose)
  47.    *获取轮廓信息,Contours为输出得到的轮廓, CalibDataID为标定模句柄,
  48.    *'caltab'表示要得到哪种轮廓,这里是标定板的轮廓, 0, 0, I - 1,三项分别为相机,标定板,姿态索引。
  49.     get_calib_data_observ_contours (Contours, CalibDataID, 'caltab', 0, 0, I - 1)
  50.     *生成亚像素精度的十字叉
  51.     gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)
  52.     dev_set_color ('green')
  53.     dev_display (Contours)
  54.     dev_set_color ('yellow')
  55.     dev_display (Cross)
  56. endfor
  57. disp_continue_message (WindowHandle, 'black', 'true')
  58. *暂停程序执行,可以方便查看前面代码效果,按F5后,继续执行代码。
  59. stop ()
  60. *执行相机标定
  61. calibrate_cameras (CalibDataID, Error)
  62. *算子介绍如上,这里获取的是索引为0的'camera'的'params'参数,参数值保存在CamParam
  63. get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
  64. * 上面代码为标定部分,标定好后,就可以使用标定的结果进行测量。
  65. for I := 1 to NumImages by 1
  66.     read_image (Image, 'calib/calib-3d-coord-' + I

  67. 02d')
  68.     * 获取测量位置,Image为输入图像, PlateRegion为输出区域, CalibDataID为标定模型句柄,
  69.     *I, Distance, Phi, RowCenter, ColumnCenter分别为位姿索引,区域,距离值,旋转角度,中心行列坐标。
  70.     get_measure_positions (Image, PlateRegion, CalibDataID, I, Distance, Phi, RowCenter, ColumnCenter)
  71.     *使用上面得到的数据生成矩形区域
  72.     gen_rectangle2_contour_xld (Rectangle, RowCenter, ColumnCenter, Phi, Distance * 0.52, 8)
  73.     *创建测量矩形RowCenter, ColumnCenter为矩形直剖面线中心点行列坐标,
  74.     *Phi为直剖面线方向, Distance * 0.52, 8为测量矩形的半宽半高,
  75.     *768, 576为要处理图像 的宽高, 'nearest_neighbor'表示使用近邻插值方法, MeasureHandle为输出的矩形句柄
  76.     gen_measure_rectangle2 (RowCenter, ColumnCenter, Phi, Distance * 0.52, 8, 768, 576, 'nearest_neighbor', MeasureHandle)
  77.     * 测量边缘间距,Image, MeasureHandle为输入图像和矩形句柄,
  78.     *1, 40为高斯平滑系数和最小边缘幅度值, 'all'表示检测所有正负边缘,
  79.     *'all'表示选中所有边缘, RowEdge, ColumnEdge为边缘中心行列坐标,
  80.     *Amplitude, Distance1为边缘幅度大小和相邻边缘间距
  81.     measure_pos (Image, MeasureHandle, 1, 40, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance1)
  82.     close_measure (MeasureHandle)
  83.     Rows := [RowEdge[0],RowEdge[|RowEdge| - 1]]
  84.     Columns := [ColumnEdge[0],ColumnEdge[|RowEdge| - 1]]
  85.     gen_cross_contour_xld (Cross, Rows, Columns, 16, Phi)
  86.     * 获取相机外参,CalibDataID为标定模型句柄, 'calib_obj_pose'为数据类型,这里表示 要获得相机外部参数,
  87.     *[0,I - 1]为对应数据类型的索引, 'pose'表示 要获得的是姿态 参数, Pose为输出的相机参数。
  88.     get_calib_data (CalibDataID, 'calib_obj_pose', [0,I - 1], 'pose', Pose)
  89.     *此函数是求实际 空间姿态 坐标的关键函数。主要根据前面求得的相机内外 参数和像素 坐标点,求出对应的实际 点的世界坐标系
  90.     *CamParam为相机内参, Pose为相机外参, Rows, Columns为上边求得的首末边缘行列坐标,
  91.     *'m'表示实际距离单位为米, SX, SY为输出的世界坐标系下对应点实际XY坐标。
  92.     image_points_to_world_plane (CamParam, Pose, Rows, Columns, 'm', SX, SY)
  93.     *求两点间距Width为输出结果间距。
  94.     distance_pp (SY[0], SX[0], SY[1], SX[1], Width)
  95.     *
  96.     *下面为显示结果
  97.     dev_display (Image)
  98.     dev_set_color ('white')
  99.     dev_set_line_width (3)
  100.     dev_display (Rectangle)
  101.     dev_set_color ('green')
  102.     dev_set_draw ('fill')
  103.     dev_set_line_width (2)
  104.     dev_display (Cross)
  105.     dev_set_draw ('margin')
  106.     disp_message (WindowHandle, 'Width = ' + (Width * 100)

  107. 8.3f' + 'cm', 'window', 12, 12, 'black', 'true')
  108.     disp_continue_message (WindowHandle, 'black', 'true')
  109.     stop ()
  110.     * 下面再进一步提取黑点的大小
  111.     *用半径为17.5的圆形结构进行区域腐蚀处理。
  112.     erosion_circle (PlateRegion, ROI, 17.5)
  113.     *在图像上获取区域ROI对应的子图像ImageReduced
  114.     reduce_domain (Image, ROI, ImageReduced)
  115.     *在子图像中提取亚像素精度边缘。ImageReduced, Edges分别为输入图像输出边缘,
  116.     *'canny'为提取算法你称, 1高斯平滑系数,这里越大边缘细节越少,
  117.     *20, 60表示canny算法中,低高阈值。
  118.     edges_sub_pix (ImageReduced, Edges, 'canny', 1, 20, 60)
  119.     *对提取的边缘进行筛选,选择周长范围在20, 99999999的边缘,后面两参数在这里无效。
  120.     select_contours_xld (Edges, SelectedEdges, 'contour_length', 20, 99999999, -0.5, 0.5)
  121.     *进行椭圆的拟合。SelectedEdges为输入轮廓变量, 'fitzgibbon'为拟合算法名称,
  122.     *-1表示所有点参与拟合, 2表示轮廓首尾相互距离小于2为封闭,
  123.     *0表示轮廓开始结束点参与拟合个数, 200表示使用VOSS方法时分割圆弧的个数,
  124.     *3为最大迭代次数, 2为离群值剪切因子,越小表示 忽略离群值越多,
  125.     *Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder分别表示输出的椭圆中心行列坐标,
  126.     *主轴角度,椭圆长短半轴长度,开始与结束点角度,椭圆边界点次序。
  127.     fit_ellipse_contour_xld (SelectedEdges, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, Radius1, Radius2, StartPhi, EndPhi, PointOrder)
  128.     MeanRadius1 := mean(Radius1)
  129.     MeanRadius2 := mean(Radius2)
  130.     DevRadius1 := deviation(Radius1)
  131.     DevRadius2 := deviation(Radius2)
  132.     *将椭圆转到世界坐标系下,它们将会是圆形状态,再将圆的单位从米转为毫米
  133.     *将一个亚像素精度轮廓转换到世界坐标系去,此时这些世界坐标系X为0.
  134.     *SelectedEdges为输入轮廓, WorldCircles为输出轮廓, CamParam为相机内参, Pose为相机外参,
  135.     *'mm'表示世界坐标系单位为mm
  136.     contour_to_world_plane_xld (SelectedEdges, WorldCircles, CamParam, Pose, 'mm')
  137.     * 在世界坐标系下进行椭圆拟合。
  138.     fit_ellipse_contour_xld (WorldCircles, 'fitzgibbon', -1, 2, 0, 200, 3, 2, Row, Column, Phi, RadiusW1, RadiusW2, StartPhi, EndPhi, PointOrder)
  139.     MeanRadiusW1 := mean(RadiusW1)
  140.     MeanRadiusW2 := mean(RadiusW2)
  141.     DevRadiusW1 := deviation(RadiusW1)
  142.     DevRadiusW2 := deviation(RadiusW2)
  143.     *
  144.     * 显示结果
  145.     dev_display (Image)
  146.     dev_set_color ('yellow')
  147.     dev_set_line_width (3)
  148.     dev_display (SelectedEdges)
  149.     Message := 'Measured dimensions of the ellipses'
  150.     Message[0] := '                    Mean Radius1; Mean Radius2; (Standard deviations [%])'
  151.     Message[1] := 'Image coordinates:       ' + MeanRadius1

  152. 5.2f' + 'px; ' + MeanRadius2

  153. 5.2f' + 'px            (' + (DevRadius1 / MeanRadius1 * 100)

  154. 4.2f' + ', ' + (DevRadius2 / MeanRadius2 * 100)

  155. 4.2f' + ')'
  156.     Message[2] := 'World coordinates:       ' + (MeanRadiusW1 / 10)

  157. 5.2f' + 'cm; ' + (MeanRadiusW2 / 10)

  158. 5.2f' + 'cm            (' + (DevRadiusW1 / MeanRadiusW1 * 100)

  159. 4.2f' + ', ' + (DevRadiusW2 / MeanRadiusW2 * 100)

  160. 4.2f' + ')'
  161.     disp_message (WindowHandle, Message, 'window', 12, 12, 'black', 'true')
  162.     if (I < 10)
  163.         disp_continue_message (WindowHandle, 'black', 'true')
  164.         stop ()
  165.     endif
  166. endfor
  167. clear_calib_data (CalibDataID)
复制代码


回复

使用道具 举报

快速回复 返回列表 客服中心 搜索