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, HeightCorrections[OIdx], WorldPose1)

set_origin_pose (Pose2, -0.14, -0.07, HeightCorrections[OIdx], 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, Borders[0], Borders[1], Borders[2], Borders[3])

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



相关推荐
mit6.82413 分钟前
[AI-video] 数据模型与架构 | LLM集成
开发语言·人工智能·python·微服务
roman_日积跬步-终至千里14 分钟前
【机器学习【6】】数据理解:数据导入、数据审查与数据可视化方法论
人工智能·机器学习
张较瘦_43 分钟前
[论文阅读] 人工智能 + 软件工程 | 开源软件中的GenAI自白:开发者如何用、项目如何管、代码质量受何影响?
论文阅读·人工智能·软件工程
非ban必选1 小时前
spring-ai-alibaba之Rag 增强问答质量
java·人工智能·spring
Lum11041 小时前
MER-Factory:多模态情感识别与推理数据集自动化工厂工具介绍
运维·人工智能·深度学习·计算机视觉·语言模型·自然语言处理·自动化
Codebee1 小时前
OneCode 3.0 自治UI 弹出菜单组件功能介绍
前端·人工智能·开源
肥田大王2 小时前
语音增强论文汇总
人工智能·语音识别
Mikowoo0072 小时前
03_opencv_imwrite()函数
opencv·计算机视觉
空月软件2 小时前
AI文章生成助手综合版,一款聚合了多个AI平台API接口的文章生成软件!
人工智能·ai文章生成助手·ai文章生成助手综合版·ai文章生成
春风LiuK2 小时前
三雄争霸,AI写诗大赛!李白魂穿chatgpt?
人工智能·chatgpt·生活·娱乐·ai写作