当前位置: 首页 > news >正文

Halcon 相机标定

前言

相机标定是视觉高精度测量的必要过程,每个镜头的畸变程度各不相同,通过相机标定可以矫正这种镜头畸变。在相机标定后就可以得到世界坐标系中物体米制单位的坐标,例如米、毫米、甚至微米。相机标定其实就是确定相机的内参和外参的过程。

  1. Halcon中支持两种畸变矫正模型:Dicision模型和Polynomial模型

    1. Division模型适用于简单的径向畸变:

    ​​​

    1. Polynomial模型适用于各种复杂畸变(径向畸变、切线畸变、透视投影畸变、纵横比畸变) ​​

      ​​

    2. 两种 矫正模型的效果对比:

    ​​

    注:从效果图中可以看出Polynomial模型效果更好,因此在实际应用中,强力推荐适用Polynomial模型校正。

标定过程以及应用

为了进行相机标定,必须已知世界坐标系中足够多的三维空间点坐标,找到这些点在图像中的投影点的二维图像坐标,并建立对应关系,可以适用halcon标定板进行标定。

  1. 使用一个halcon标定板,在平面上有 m * n个圆形标志点,在这些标志点外面有个黑色矩形边界框:

    1. 他们非常易操作

    2. 他们尺寸可以做的非常精确

    3. 他们可以非常方便地应用在背光照明中,只需要使用透明材料制作放置标志点底盘即可

    4. 在标志点周围的黑色矩形框边界框可以一个"三角形"的标志很容易被提取出来并得到其方向

    5. 在标定板表面适用圆形标志点主要因为可以非常提取圆的中心坐标

    6. 所有圆形标志按照行列呈矩形阵列,这样可以使相机标定算法在图像中提取与这些标志点对应的像素点坐标时更加简单

    7. 由于标定板上的黑色矩形框边界框容易将标定板的内部与背景区分开来,因此我们可以利用标定板这个特点在图像中提取标定板位置。在图像中只需要通过一个简单的阈值分割操作就可以找到标定板内部区域。由于正确的阈值取决于图像中标定板的亮度,因此可以在图像中自动尝试不同的阈值,直到做到图一个含m * n个空洞(标定板上的圆形标志点)的区域

    8. 一旦找到标定板上的内部区域,就可以利用亚像素边缘提取方法来提取标定板各个圆形的边缘。

  2. 标定后,可以将图像中的某些点转换到世界坐标系中。

    1. 例如将一维边缘位置或亚像素精度轮廓线转换到世界坐标中。

    2. 有些情况下将图像本身转换到世界坐标中也是非常有价值的。这个转换得到的图像就相当于相机在于相机平面绝对垂直且镜头不存在任何畸变的情况下拍照得到的图像,这种图像校正需要适用图像本身进行处理中非常有用,例如在校正后的图像中进行区域处理、OCR、模板匹配等。

Halcon标定板的说明

  • 标志点行数 * 列数(Y*X)= 7 * 7

  • 标志点直径:1.5mm

  • 标定上的每个空白间隔都是一样的,即C1 = C2

  • 标定点的中心距 = 直线AB = 两个半径 + 一个空白间隔(C1) = 一个直径 + 一个间隔 = 3mm

  • 外围黑框宽度D = 一个半径 = 1.5mm/2 = 0.75mm

  • 整个黑框的宽度K2K4 =

    = (一个半径 + 一个空白间隔 + 一个半径) + AF + (一个半径 + 一个空白间隔 + 一个半径)

    = 一个标定点中心距 + AF +一个标定点中心距

    =一个标定点中心距 + 六个标定点中心距 + 一个标定点中心距

    = 八个标定点中心距离

  • 边角:用来标注标定板的方向(上图的左下角的三角形),它是由黑边外边框向内缩进一个中心边距的长度。

  • 标定板的方向:当三角形边角在左上角时,X轴正方向向右,Y轴正方向向下,Z轴正方向垂直标定板面向下。

Halcon标定板的制作

制作标定板只需要使用一个算子就可以了

  • gen_caltab( : : XNum, YNum, MarkDist, DiameterRatio, CalTabDescrFile, CalTabPSFile : )​ 根据传递的参数生成标定板文件

    XNum:X方向标志点数量

    YNum:Y方向标志点数量

    MarkDist:标志点间距(即圆心距)单位是m(米)

    DiameterRatio:标志点直径与标志点间距比值

    CalTabDescrFile:用于保存标定描述文件的路径,该描述文件在进行标定时需要用到。扩展名为:.descr

    工业标准命名规则:caltab_XXXmm.descr

    CalTabPSFile:保存标定板图形文件路径,该图形用于制作标定板,扩展名为.ps。可以用GhostView打开。也可以使用一些在线的工具将ps文件转换为图片文件,自行使用打印机进行打印(精度不高)

    工业标准命名规则:caltab_XXXmm. ps

XXXmm指的是标定板的尺寸,是黑色边框的大小

注意事项:

  1. 如果对精度要求不高,用于学习和功能实现。可以直接打印生成的 .ps 文件出来,最好用图片模式打印。

  2. 如果制作高精度的标定板,把 .ps 文件发给标定板厂商定制。现阶段制作标定板的材质主要是玻璃和陶瓷。陶瓷的价格比玻璃贵很多。标定板的厚度尽可能小

  3. 用在背光场合,选择玻璃材质

  4. 用在前光场合,光照尽量均匀,有限选择玻璃标定板。如果不能满足应用的时候可以选择陶瓷材质标定板。

  5. Halcon标定只支持白色背景,黑色边框和标志点,所以必要时需要进行图像取反,在进行标定。

Halcon相机标定使用

  1. 使用gen_caltab​​​算子制作并生成标定板文件

  2. 将标定图像打印并放在相机视野中

  3. 打开标定助手(助手 => 打开新的 Calibration)

  4. 选择描述文件、输入相机和镜头信息

    1:生成标定文件时的描述文件,一般应该是caltab_XXXmm.descr​​​

    2:标定模型,推荐多项式,也就是Polynomial模型

    3:相机的像元尺寸,从相机的资料中查询

    4:镜头的焦距,从镜头的资料中查询,一般再镜头上也有标注(如果是远心镜头,将投影模型设置为远心,并设置放大倍率)

  5. 选择图像文件,可以加载保存再计算机中的标定板图像,也可以使用图像采集助手采集的相机画面

    选择或者拍照后,再点击对应的图片,会自动进行识别,显示标志点中心和标定板区域,可以移动标定板并拍摄多张图像进行标定,更加准确

    可以在显示参数区域设置显示的颜色等信息

  6. 设置标定板提取参数

    这些参数用于提取定位标定板的,一般情况下,当采集到第一张标定图像时,这些参数会自动设置。但有时提起的效果不佳,需要手调。

  7. 处理品质问题

    由于光源照的不够均匀,标定板没有放在最清晰平面,加载的标定的图片太少等因素。会引起标定质量不佳。Halcon标定助手中会提示相关的问题。这些问题警告级别默认是70%,当这个品质问题大于70%才会消失

    1. 品质问题1:视野没有完全被标定板覆盖到 由于图片太少,整个视野中有些地方没有被标定板覆盖。可以点击后面的"show"按钮,出现下图,绿色区域表示该区域已被标定板覆盖,绿色越深,表示越靠近标定板,矫正效果越好。红色表示该区域没有 被标定板覆盖,红色越深,表示离标定板越远。 ​

      ​ 注:当点击"show"显示这个绿红区域时,要点击界面中的"更新"按钮画面才会切换到标定图片。

    2. 品质问题2:旋转角度没有被先后覆盖到 将相机进行标定得到的是相机与二维测量平面的位姿,旋转角度、深度时候被覆盖对于二维测量平面标定来说不是最重要的,它们的作用是优化相机参数,如果能覆盖尽量多的角度、深度,当然更好。

    3. 其他品质问题: 如品质评估出错、检测出某些图片品质有问题等一些品质问题,通过调"五、标定提取参数设置"的参数很难把这些品质问题去掉,解决方案是,通过相机实时采集图片,改变灯光亮度、景深大小等外部环境,进到标定中显示"确定"字样,而不是"检测出品质问题"时,就采集这张图像作为标定图像。

    出现品质问题时,可以从以下几个方面来改进:

    (1)、使用标定板的有效区域(黑色方框区域)要足够大,尽量在视野的1/4以上

    (2)、圆心标志点的最小直径不能低于10个像素

    (3)、标定板为白色背景,黑色的圆心标志点和黑色边框

    (4)、标定板的白色背景的灰度值不能低于100

    (5)、黑色标志点和边框与白色背景的灰度对比度最好大于100

    (6)、使用均匀的光源照明

    (7)、图像不能过曝

    (8)、要用尽量多的图像来覆盖整个视野,图像越多越好,覆盖图像的四个角,这主要原因是角落处的镜头畸变最大,这样可以得到畸变系数最准确的值。

    (9)、在景深范围内发改各种旋转角度和尽量多的深度,可以通过标定板绕它的x轴和y轴旋转或者将标定板放置在与相机不同距离的位置上。

    (10)、用于标定的有效图像尽量不低于10张,最好在10到20张图像,图像越多越好

    (11)、标定好后,相机和镜头不能动,若果再调节相机和镜头、调节镜头的光圈、焦距,调节后需要重新标定。

    (12)、在任何情况下只要相机和物品的距离和位置发生了变化,就应该重新标定。

  8. 设置参考位姿

    如果在用来标定的其中一幅图像中的标定板直接放在测量平面(如传送带),那么这幅图像中标定板的外参基本等同于测量平面的位姿。

    选取一张图像,该图像中的标定板尽量在视野中间,而且图像横平竖直的对齐

    如下图,点击后前面有个"*",表示以当前图像的位姿作为参考位姿,点击标记即可标定完成。

    注: 若没有选定,则系统自动选择这个列表图像中的第一张作为参考位姿.

  9. 结果

    通过上述步骤,点击"标定"按钮后,页面即跳到"结果"中。可以点击保存按钮保存相关参数。

  10. 代码生成

    • 生成的模式

      • 标定函数:生成完整的标定过程代码

      • 标定数据(Tuple):将标定助手标定的摄像机参数摄像机位姿以Tuple的数据形式插入代码

      • 标定数据(File):设置好保存的摄像机参数摄像机位姿的文件的路径,程序会按照设置的路径保存参数文件和位姿文件,然后再使用算子读取文件形式的摄像机参数摄像机位姿

  11. 插入代码

    选择标定函数时:

     * 加载标定图像ImageFiles := []ImageFiles[0] := 'C:/Users/Public/Documents/MVTec/HALCON-17.12-Progress/examples/images/self_calib/calib_01.png'...ImageFiles[9] := 'C:/Users/Public/Documents/MVTec/HALCON-17.12-Progress/examples/images/self_calib/calib_10.png'
    ​TmpCtrl_ReferenceIndex := 0
    ​* 标定板描述文件路径TmpCtrl_PlateDescription := 'E:/MVTec/HALCON-17.12-Progress/calib/caltab_6mm.descr'
    ​* 标定助手中的 ”安装 => 摄像机参数“ 中设定的参数StartParameters := ['area_scan_polynomial',0.008,0,0,0,0,0,8.3e-006,8.3e-006,326,247,652,494]
    ​* 标定助手中的 ”标定 => 标定板提取参数“ 中设定的参数,分别是: 间距容许因子、平滑、最大标志点直径TmpCtrl_FindCalObjParNames := ['gap_tolerance','alpha','max_diam_marks','skip_find_caltab']TmpCtrl_FindCalObjParValues := [1,1,100,'false']
    ​* Calibration 01: 创建用于管理校准数据的校准模型create_calib_data ('calibration_object', 1, 1, CalibHandle)
    ​* 设置”摄像机参数“set_calib_data_cam_param (CalibHandle, 0, [], StartParameters)
    ​* 设置标定文件参数set_calib_data_calib_object (CalibHandle, 0, TmpCtrl_PlateDescription)
    ​* Calibration 01: 循环所有的图像,并收集各个图像的标志点位置和位姿for Index := 0 to |ImageFiles|-1 by 1read_image (Image, ImageFiles[Index])find_calib_object (Image, CalibHandle, 0, 0, Index, TmpCtrl_FindCalObjParNames, TmpCtrl_FindCalObjParValues)endfor
    ​* Calibration 01: 执行校准calibrate_cameras (CalibHandle, TmpCtrl_Errors)
    ​* 获取校准后的”摄像机参数“get_calib_data (CalibHandle, 'camera', 0, 'params', CameraParameters)* 获取校准后的”摄像机位姿“get_calib_data (CalibHandle, 'calib_obj_pose', [0, TmpCtrl_ReferenceIndex], 'pose', CameraPose)* Calibration 01: 设置校准板原点位置set_origin_pose (CameraPose, 0.0, 0.0, 0.001, CameraPose)
    ​* Calibration 01: 工作完成后清除校准句柄clear_calib_data (CalibHandle)stop ()

    以前的写法代码:

     ImageFiles := []ImageFiles[0] := 'H:/biaoding/BDpicture/image_01.png'...ImageFiles[84] := 'H:/biaoding/BDpicture/image_86.png'TmpCtrl_AllMarkRows := []TmpCtrl_AllMarkColumns := []TmpCtrl_StartPoses := []TmpCtrl_ReferenceIndex := 9TmpCtrl_PlateDescription := 'H:/biaoding/标定板制作/caltab.descr'
    ​
     * 这里的参数的个数内部就会自动选择标定算法为'area_scan_polynomial'StartParameters := [0.035,0,0,0,0,0,4.8e-006,4.8e-006,640,480,1280,960]
    ​* 收集所有图像的标记位置和估计姿势
    ​
     for Index := 0 to |ImageFiles| - 1 by 1read_image (Image, ImageFiles[Index])
    ​* 输入标定板描述文件,查找标定板,结果只输出一个标定板的区域TmpObj_PlateRegionfind_caltab (Image, TmpObj_PlateRegion, TmpCtrl_PlateDescription, 3, 112, 5)
    ​* 输入 标定板区域、标定板描述文件(主要利用该标定板有多少行多少列)、初始相机参数* 输出该图像每个标志点的像素坐标,和该图片的位姿find_marks_and_pose (Image, TmpObj_PlateRegion, TmpCtrl_PlateDescription, StartParameters, 128, 10, 18, 0.9, 15, 100, TmpCtrl_MarkRows, TmpCtrl_MarkColumns, TmpCtrl_EstimatedPose)
    ​* 把计算出的该图像的所有标志点像素坐标存入到点数组中TmpCtrl_AllMarkRows := [TmpCtrl_AllMarkRows, TmpCtrl_MarkRows]TmpCtrl_AllMarkColumns := [TmpCtrl_AllMarkColumns, TmpCtrl_MarkColumns]
    ​* 把计算出的该图像位姿存入到数组中TmpCtrl_StartPoses := [TmpCtrl_StartPoses, TmpCtrl_EstimatedPose]endfor
    ​* 解析标定板(该标定板有多少行、多少列、以及每个点的真实坐标单位m)caltab_points (TmpCtrl_PlateDescription, TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z)
    ​* 输入解析标定板得到的数据、所有标定板图像中的像素点坐标、所有标定板图像的位姿* 输出相机内参CameraParameters,N组矫正后的位姿TmpCtrl_FinalPoses(一张图像对应一个位姿),误差camera_calibration (TmpCtrl_X, TmpCtrl_Y, TmpCtrl_Z, TmpCtrl_AllMarkRows, TmpCtrl_AllMarkColumns, StartParameters, TmpCtrl_StartPoses, 'all', CameraParameters, TmpCtrl_FinalPoses, TmpCtrl_Errors)
    ​* 从N组矫正后的位姿TmpCtrl_FinalPoses选出一个来设置为参考位置。tuple_select_range (TmpCtrl_FinalPoses, 7 * TmpCtrl_ReferenceIndex, 7 * TmpCtrl_ReferenceIndex + 6, CameraPose)set_origin_pose (CameraPose, 0.0, 0.0, 0, CameraPose)
    ​stop ()

halcon标定相关示例文件.zip

标定的使用

  • image_points_to_world_plane( : : CameraParam, WorldPose, Rows, Cols, Scale : X, Y)​​​ 把图像坐标系的像素转换到世界坐标系中Z=0平面中XY坐标

    CameraParam:输入摄像机参数(外参)

    WorldPose:输入位姿参数(内参)

    Rows:输入图像坐标系中的像素坐标Y(数组)

    Cols:输入图像坐标系中的像素坐标X(数组)

    Scale:输入测量单位:'m', 'cm', 'mm', 'microns', 'um'

    X:输出世界坐标系Z=0平面的X坐标 (数组)

    Y:输出世界坐标系Z=0平面的Y坐标 (数组)

  • contour_to_world_plane_xld(Contours : ContoursTrans : CameraParam, WorldPose, Scale : )​​​ 把图像坐标系的xld轮廓转换到世界坐标系中Z=0平面

    Contours:输入转换前图像坐标系的xld轮廓

    ContoursTrans:输出转换到世界坐标系中Z=0平面上的xld轮廓

    CameraParam:输入摄像机参数(外参)

    WorldPose:输入位姿参数(内参)

    Scale:输入测量单位:'m', 'cm', 'mm', 'microns', 'um'

  • change_radial_distortion_cam_par( : : Mode, CamParamIn, DistortionCoeffs : CamParamOut)​​ 根据指定的径向畸变确定新的摄像机参数。gen_radial_distortion_map( : Map : CamParamIn, CamParamOut, MapType : )​​ 生成描述对应于变化的径向失真的图像的映射的投影映射,map_image(Image, Map : ImageMapped : : )​​​ 利用畸变矫正映射矫正图像

  • Image:输入畸变图像(原图像)

    Map:输入畸变矫正映射图像

    ImageMapped:输出畸变矫正后的图像(无畸变图像)

代码示例

矫正图像的畸变

dev_update_off ()
dev_close_window ()
​
* 标定结果
CameraParameters := ['area_scan_division',0.00839071,-1987.62,8.35072e-006,8.3e-006,362.432,291.711,768,576]
CameraPose := [0.0303729,-0.0241966,2.62246,359.814,0.315663,0.0268478,0]
​
​
* 根据径向畸变确定摄像机参数(二选一)
* 对于area(diversion)相机模型(7个参数)
change_radial_distortion_cam_par('adaptive', CameraParameters, 0, CamParamChange)
* 对于area(多项式)相机模型(12个参数)
change_radial_distortion_cam_par('adaptive', CameraParameters, [0,0,0,0,0], CamParamChange)
​
​
* 生成基于径向畸变的投影映射
gen_radial_distortion_map (Map, CameraParameters, CamParamChange, 'bilinear')
​
* 打开窗口
dev_open_window (0, 0, 512, 512, 'black', WindowHandle1)
dev_open_window (0, 0, 512, 512, 'black', WindowHandle2)
dev_set_window_extents (-1, 512, 512, 512)
​
for Index := 1 to 10 by 1* 读取图像read_image (Image, 'calib/calib-3d-coord-' + Index$'.2' +'.png')dev_set_window (WindowHandle1)dev_display (Image)* 矫正图像map_image (Image, Map, ImageMapped)dev_set_window (WindowHandle2)dev_display (ImageMapped)stop ()
endfor

http://www.dtcms.com/a/389171.html

相关文章:

  • 腾讯混元发布集成翻译模型Hunyuan-MT-Chimera-7B,已开放体验
  • mybatis-plus扩展
  • 从x.ai到VSCode:一个AI编程助手的意外之旅
  • SQLite vs MySQL:核心SQL语法差异全面解析
  • 【每日算法】两数相加 LeetCode
  • ActiveMQ底层原理与性能优化
  • Ceph IO流程分段上传(1)——InitMultipart
  • 大数据毕业设计选题推荐-基于大数据的农作物产量数据分析与可视化系统-Hadoop-Spark-数据可视化-BigData
  • 【回归之作】学校实训作业:Day04面向对象思想编程
  • Ubuntu20.04或者Ubuntu24.04 TypeC-连接屏幕不显示问题
  • 【SQLSERVER】SQL Server 表导出与导入
  • postgresql和mongodb谁的地位更高
  • RK3588+复旦微JFM7K325T工业控制解决方案
  • RabbitMQ全方位解析
  • 云望无人机图传原理,无人机图传方式哪种好
  • 无人机50公里遥控模块技术要点与难点
  • 【三维重建】Octree-GS:基于LOD的3DGS实时渲染(TPAMI2025)
  • 《深度拆解3D开放世界游戏中角色攀爬系统与地形碰撞网格动态适配的穿透卡顿复合故障》
  • 数据库mysql连接池:从原理到实践的全面解析
  • # 深入理解栈、栈帧与递归:从迭代与递归归并排序双视角解析
  • Django 完整项目开发:博客系统
  • FPGA部署视觉模型
  • 课后实验实验拓扑:
  • 二阶段 docker 构建
  • React原理二
  • 116.block design 设计中设置的DDR起始地址的作用是什么
  • 报名中|2025 Maple 用户大会
  • 深入解析Channel:数据流动的秘密通道
  • 一键快速发布服务
  • 栈-394.字符串解码-力扣(LeetCode)