Halcon双相机单标定板标定实现拼图

1.Halcon图像拼接算法在之前的文章里也写过,主要是硬拼接和特征点拼接两种方式,今天增加另一种拼接图像的方式。应用场景是多个相机联合一起拍大尺寸的物体,并且相机视野之间存在重叠区域。通过在同一个标定板上面标定,计算两个相机之间位相对外参矩阵实现拼接。

2.代码分析

dev_update_off ()

*

  • Path to the calibration and object images.
    ImagePath := '3d_machine_vision/calibrated_mosaic/'
  • Display workflow explanation text.
    dev_close_window ()
    dev_open_window (0, 0, 600, 300, 'black', WindowHandle1)
    set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')
    dev_disp_workflow_text ()
    stop ()
  • Display calibration explanation text.
    dev_clear_window ()
    dev_disp_calibration_text ()
    stop ()

dev_close_window ()

dev_open_window (0, 0, 600, 480, 'black', WindowHandle1)

dev_open_window (0, 605, 600, 480, 'black', WindowHandle2)

set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')

set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')

*


  • *********** Step 1: Calibration of the cameras ***********

  • Number of calibration images.
    NumCalibImages := 10
  • 从每个摄像头读取一张图像,以获得摄像头的宽度和高度。
    read_image (ImageCam1, ImagePath + '/calib_cam_1_01')
    read_image (ImageCam2, ImagePath + '/calib_cam_2_01')
    get_image_size (ImageCam1, WidthCam1, HeightCam1)
    get_image_size (ImageCam2, WidthCam2, HeightCam2)
  • 设置内部相机参数的初始值。
    gen_cam_par_area_scan_division (0.012, 0, 4.4e-6, 4.4e-6, WidthCam1 / 2, HeightCam1 / 2, WidthCam1, HeightCam1, StartCamParam1)
    gen_cam_par_area_scan_division (0.012, 0, 4.4e-6, 4.4e-6, WidthCam2 / 2, HeightCam2 / 2, WidthCam2, HeightCam2, StartCamParam2)
  • 创建标定模型,并设置参数,此模型同时可以校准两个相机
    create_calib_data ('calibration_object', 2, 1, CalibDataID)
    set_calib_data_cam_param (CalibDataID, 0, \[\], StartCamParam1)
    set_calib_data_cam_param (CalibDataID, 1, \[\], StartCamParam2)
    set_calib_data_calib_object (CalibDataID, 0, 'calplate_160mm.cpd')
  • 依次访问两个相机的标定板图片,进行标定操作
    for I := 0 to NumCalibImages - 1 by 1
    • Read the calibration images.
      read_image (ImageCam1, ImagePath + '/calib_cam_1_' + (I + 1)KaTeX parse error: Double subscript at position 56: ...+ '/calib_cam_2_̲' + (I + 1)'02d')
    • Find the calibration plate and store observations
    • in the calibration data model.
      find_calib_object (ImageCam1, CalibDataID, 0, 0, I, \[\], \[\])
      get_calib_data_observ_contours (ContoursCam1, CalibDataID, 'marks', 0, 0, I)
      find_calib_object (ImageCam2, CalibDataID, 1, 0, I, \[\], \[\])
      get_calib_data_observ_contours (ContoursCam2, CalibDataID, 'marks', 1, 0, I)
    • Display calibration images and observed contours.
      dev_set_window (WindowHandle1)
      dev_display (ImageCam1)
      dev_display (ContoursCam1)
      dev_disp_text ('Image ' + (I + 1) + '/' + NumCalibImages + ' (Camera 1)', 'window', 'top', 'left', 'black', \[\], \[\])
      dev_set_window (WindowHandle2)
      dev_display (ImageCam2)
      dev_display (ContoursCam2)
      dev_disp_text ('Image ' + (I + 1) + '/' + NumCalibImages + ' (Camera 2)', 'window', 'top', 'left', 'black', \[\], \[\])
      disp_continue_message (WindowHandle2, 'black', 'true')
      stop ()
      endfor

*同时校准两个摄像头.

calibrate_cameras (CalibDataID, Errors)

dev_set_window (WindowHandle1)

dev_disp_text ('Calibration successful', 'window', 'top', 'left', 'green', \[\], \[\])

dev_set_window (WindowHandle2)

dev_disp_text ('Calibration successful', 'window', 'top', 'left', 'green', \[\], \[\])

disp_continue_message (WindowHandle2, 'black', 'true')

stop ()

*


  • ******************* Step 2: Mosaicking *******************

  • Display mosaicking explanation text.
    dev_close_window ()
    dev_close_window ()
    dev_open_window (0, 0, 600, 300, 'black', WindowHandle1)
    set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')
    dev_disp_mosaicking_text ()
    stop ()
  • Number of objects.
    NumObjects := 2
  • Number of images per object.
    NumObjImages := 2
  • 获取两个相机各自的标定好的参数,相机内参
    get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam1)
    get_calib_data (CalibDataID, 'camera', 1, 'params', CamParam2)
  • 获取相对于第一个相机(参考相机)的位姿
    get_calib_data (CalibDataID, 'calib_obj_pose', 0,0, 'pose', Pose1)
    *设置标定板厚度4mm,注意算子需要用的单位是米m
    set_origin_pose (Pose1, 0, 0, 0.004, Pose1)
  • 获取第二台相机相对于第一台相机的位姿.
    get_calib_data (CalibDataID, 'camera', 1, 'pose', RelPose2)
    *为了获得第二个相机的绝对姿态,它的相对姿态需要
    *以被反转并与第一相机的绝对姿态相结合。
    pose_invert (RelPose2, RelPose2Inverted)
    pose_compose (RelPose2Inverted, Pose1, Pose2)

*设置目标图像宽度、高度和比例,以便整个对象

*映射后图像拟合良好。

TargetWidth := 1340

TargetHeight := 800

*像素当量(1颗像素0.0002m),注意单位是m/pixel

Scale := 0.0002

  • 设置区域,可以裁剪掉有黑边的图像区域
    Borders := 125,110,665,1222

*为了映射对象图像,需要校正相机的姿态

*再次取决于物体的厚度。这里我们使用两个不同的对象:

*一把厚度约为2.5mm的尺子和一本薄薄的小册子,可以

*近似为0mm厚度。

HeightCorrections := -0.0025,0

*

dev_close_window ()

dev_open_window (0, 0, 600, 480, 'black', WindowHandle1)

dev_open_window (0, 605, 600, 480, 'black', WindowHandle2)

dev_open_window (535, 0, 740, 360, 'black', WindowHandle3)

set_display_font (WindowHandle1, 16, 'mono', 'true', 'false')

set_display_font (WindowHandle2, 16, 'mono', 'true', 'false')

set_display_font (WindowHandle3, 16, 'mono', 'true', 'false')

for OIdx := 0 to NumObjects - 1 by 1

* 设置矫正图像原点位置和标定板厚度

set_origin_pose (Pose1, -0.14, -0.07, HeightCorrectionsOIdx, WorldPose1)

set_origin_pose (Pose2, -0.14, -0.07, HeightCorrectionsOIdx, WorldPose2)

*

* 生成矫正矩阵

gen_image_to_world_plane_map (Map1, CamParam1, WorldPose1, WidthCam1, HeightCam1, TargetWidth, TargetHeight, Scale, 'bilinear')

gen_image_to_world_plane_map (Map2, CamParam2, WorldPose2, WidthCam1, HeightCam1, TargetWidth, TargetHeight, Scale, 'bilinear')

*

* 矫正图像

for IIdx := 1 to NumObjImages by 1

ObjImageIdx := 2 * OIdx + IIdx

read_image (ImageCam1, ImagePath + '/obj_cam_1_' + ObjImageIdxKaTeX parse error: Double subscript at position 62: ...h + '/obj_cam_2_̲' + ObjImageIdx'02d')

*

* Display input images and camera poses.

dev_set_window (WindowHandle1)

dev_display (ImageCam1)

dev_disp_text ('Camera 1 image', 'window', 'top', 'left', 'black', \[\], \[\])

disp_3d_coord_system (WindowHandle1, CamParam1, Pose1, 0.05)

dev_set_window (WindowHandle2)

dev_display (ImageCam2)

dev_disp_text ('Camera 2 image', 'window', 'top', 'left', 'black', \[\], \[\])

disp_3d_coord_system (WindowHandle2, CamParam2, Pose2, 0.05)

*

* 通过将图像映射到世界坐标系来优化图像。

map_image (ImageCam1, Map1, ImageWorld1)

map_image (ImageCam2, Map2, ImageWorld2)

*

* 将映射的图像拼接在一起。

get_domain (ImageWorld1, Domain1)

get_domain (ImageWorld2, Domain2)

intersection (Domain1, Domain2, RegionIntersection)

paint_region (RegionIntersection, ImageWorld1, ImageWorld1Blackended, 0, 'fill')

full_domain (ImageWorld1Blackended, ImagePart1)

full_domain (ImageWorld2, ImagePart2)

add_image (ImagePart1, ImagePart2, ImageFull, 1, 0)

*

* Rotate image and remove the black borders for display.

rotate_image (ImageFull, ImageRotated, 12, 'constant')

gen_rectangle1 (RectangleDomain, Borders0, Borders1, Borders2, Borders3)

reduce_domain (ImageRotated, RectangleDomain, ImageReduced)

crop_domain (ImageReduced, ImageReduced)

mirror_image (ImageReduced, ImageReduced, 'row')

mirror_image (ImageReduced, ImageResult, 'column')

*

* Display the result image.

dev_set_window (WindowHandle3)

dev_display (ImageResult)

dev_disp_text ('Result image', 'window', 'top', 'left', 'black', \[\], \[\])

if (ObjImageIdx < NumObjects * NumObjImages)

disp_continue_message (WindowHandle3, 'black', 'true')

stop ()

else

dev_disp_text ('End of program', 'window', 'bottom', 'right', 'black', \[\], \[\])

endif

endfor

endfor



相关推荐
阿虎儿1 分钟前
dify Agent插件报错:save data failed: allocated size is greater than max storage size
人工智能
ZZZMMM.zip9 分钟前
鸿蒙生态新征程:基于鸿蒙Flutter框架的AI菜谱营养应用深度解析
人工智能·flutter·华为·harmonyos·鸿蒙·鸿蒙系统
Starmoon_dhw10 分钟前
题解:P16108 「o.OI R-1」基础博弈练习题
c++·算法·图论
美团技术团队14 分钟前
直播回放·含 ACL'26 杰出论文 | 美团 AI 顶会论文 32 篇精讲
人工智能
无心水16 分钟前
【全域智能营销实战】10、三大引擎协同工作流:从用户消息到智能决策的完整链路
人工智能·springai·openclaw·顶尖架构师·全域智能营销·harmess·herness
ClickHouseDB19 分钟前
简化 Langfuse 的规模化应用
人工智能·数据挖掘
中微极客20 分钟前
从提示词到产品级视频:生成式AI的工程化实践与工具栈选型(LTX Studio实战)
人工智能·chatgpt·音视频
@陈小鱼21 分钟前
MATLAB+Python:基于小样本卷积神经网络的 PPG 血压预测
人工智能·python·机器学习·matlab·脉搏波·血压·一维卷积神经网络
大鱼>23 分钟前
AI+快递分拣:视觉识别+自动分拣+异常检测
人工智能·深度学习·算法·机器学习
具身新纪元26 分钟前
ECCV 2026|MATCH用Flow Matching重做多视角工业质检
人工智能·计算机视觉·视觉检测