ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Halcon标定板标定流程

2021-10-29 14:00:36  阅读:279  来源: 互联网

标签:流程 pose 标定 dev Halcon image 位姿 坐标系


一、相机内参标定

目的:标定内参的目的是消除镜头的畸变。

面阵相机的内参由一个8位的数组组成包括:

startCamPar:=[Focus,Kappa,Sx,Sy,Cx,Cy,ImageWidth,ImageHeight]

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

通过查阅手册我们可以知道除Kappa以外的其他参数,将已知信息填入进去,就是未标定的初始相机内参。

有了初始内参就可以用下面算子设置进去:

set_calib_data_cam_param (CalibDataID, 0, [], startCamPar)

标定完成之后我的会得到标定后的相机内参,和标定前的区别是计算出了Kappa的值,不再是0,其他参数大致不变,所以内参标定就是计算出畸变系数的过程。

二、相机外参标定

目的:决定摄像机坐标系与世界坐标系之间相对位置关系,有了位置关系Pose,就可以将像素坐标系和世界坐标系的点进行互相转化,达到了标定的应用目的,所以外参标定就是求解要定位的产品相对于相机的位姿(位置)。

3D姿态中的7个参数代表的意义:[0,0,0,0,0,0,0]
前六个代表平移和旋转量,最后一个代表OrderOfTransform,OrderOfRotform,ViewOfTransform的组合类型。

位姿pose的参考文章:HALCON中create_pose和位姿中7个参数_m0_37833782的博客-CSDN博客

相机pose的理解-halcon标定-少有人走的路

三、参考代码

一、获取内参,参考例程camera_calibration_internal

ImgPath := '3d_machine_vision/calib/'
dev_close_window ()
dev_open_window (0, 0, 652, 494, 'black', WindowHandle)
dev_update_off ()
dev_set_draw ('margin')
dev_set_line_width (3)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
* 
* Calibrate the camera.
* 
*通过查阅手册等资料,创建初始的内参数据数组
gen_cam_par_area_scan_division (0.016, 0, 0.0000074, 0.0000074, 326, 247, 652, 494, StartCamPar)
*创建一个标定句柄,所有操作都在这个句柄上进行
create_calib_data ('calibration_object', 1, 1, CalibDataID)
*将上面创建的未标定的初始内参数据设置进去
set_calib_data_cam_param (CalibDataID, 0, [], StartCamPar)
*设置标定板的描述文件,用于后面从各个图片中查找标定板
set_calib_data_calib_object (CalibDataID, 0, 'caltab_30mm.descr')
NumImages := 10
* Note, we do not use the image from which the pose of the measurement plane can be derived
*10张标定板在视野中不同位置的图片
for I := 1 to NumImages by 1
    read_image (Image, ImgPath + 'calib_' + I$'02d')
    dev_display (Image)
    *自动查到标定板的位置信息
    find_calib_object (Image, CalibDataID, 0, 0, I, [], [])
endfor
*执行了find_calib_object之后就可以进行标定了,这里执行了10次就是标定了10个位置
calibrate_cameras (CalibDataID, Error)    *启动标定
*标定完成之后就可以用下面算子获得标定后的相机内参了
get_calib_data (CalibDataID, 'camera', 0, 'params', CamParam)
* Write the internal camera parameters to a file
*将标定后的相机内参保存成文件以使用
write_cam_par (CamParam, 'camera_parameters.dat')
Message := 'Interior camera parameters have'
Message[1] := 'been written to file'
disp_message (WindowHandle, Message, 'window', 12, 12, 'red', 'false')

二、获取外参,参考例程camera_calibration_external

*方法一、标定板确定位姿

*外参的标定流程和内参一样,标定流程结束后内参和外参数据(就是位姿)都已经存在了
*同样用get_calib_data获得外参pose
get_calib_data (CalibHandle, 'calib_obj_pose', [0, 1], 'pose', CameraPose)
*第三个参数ItemIdx由两个参数的元组组成。[0, 1]代表第0号标定板的第1张图片中的标定位姿。
*我们标定了10张标定板在不同位置的图片,所以得到了10个位姿数据,选择其中一个作为参考位姿使用,
*以后我们要定位的产品的位置也要和参考位姿的位置一样,就可以使用该位姿实现像素坐标和世界坐标
*点位的转换
clear_calib_data (CalibDataID)

*方法二、至少3点确定位姿

*世界坐标系中的4个点
X := [0,50,100,80]
Y := [5,0,5,0]
Z := [0,0,0,0]
*对应像素坐标系中的4个点
RCoord := [414,227,85,128]
CCoord := [119,318,550,448]
*加载相机内参
read_cam_par ('camera_parameters.dat', CamParam)
*从图像点和世界坐标系点的对应中直接计算出位姿
vector_to_pose (X, Y, Z, RCoord, CCoord, CamParam, 'iterative', 'error', FinalPose, Errors)


*(可选)set_origin_pose对一个位姿进行平行转换,和仿射变换功能一样
*所有方法最后求出的位姿都是默认在平面上的,没有考虑标定板的厚度,因此可以
*使用此方法在设置标定板的厚度,优化位姿参数
set_origin_pose (FinalPose, 0, 0, 0.00075, FinalPose)
*保存位姿数据为文件
write_pose (FinalPose, 'pose_from_three_points.dat')


三、实际应用

(1)点坐标转换
dev_update_window ('on')
dev_display (Image)
while (1)
    *获取鼠标点像素坐标
    get_mbutton (WindowHandle, Row, Column, Button)
    if (Button == 4)
        break
    endif
    dev_display (Image)
    dev_set_color ('green')
    disp_cross (WindowHandle, Row, Column, 6, 0)
    *使用下面算子,使用指定的内参和外参,将图像坐标转换为世界坐标
    image_points_to_world_plane (CamParam, FinalPose, Row, Column, 1, X1, Y1)
    disp_message (WindowHandle, 'X = ' + X1, 'window', 320, 400, 'red', 'false')
    disp_message (WindowHandle, 'Y = ' + Y1, 'window', 340, 400, 'red', 'false')
endwhile

(2)测量直线距离
* 该例程在世界坐标系中划出一个范围,测量包含在其中的多个直线的距离
*思路:在世界坐标系中确定ROI范围,转换到图像坐标系中的ROI,在图像中测量直线间的
*像素距离,将像素点转化位世界坐标系中的点,求出实际距离
dev_set_color ('red')
dev_display (Image)
* 设置世界坐标系中的ROI区域
ROI_X_WCS := [-2,-2,112,112]
ROI_Y_WCS := [0,0.5,0.5,0]
ROI_Z_WCS := [0,0,0,0]
*将位姿转换为3D变换矩阵,hom_mat3d_to_pose:3D变换矩阵转换为位姿
pose_to_hom_mat3d (FinalPose, CCS_HomMat_WCS)
*将世界坐标系中的点转换到相机坐标系中
affine_trans_point_3d (CCS_HomMat_WCS, ROI_X_WCS, ROI_Y_WCS, ROI_Z_WCS, CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ)
*将相机坐标系中的点转换到图像坐标系中
project_3d_point (CCS_RectangleX, CCS_RectangleY, CCS_RectangleZ, CamParam, RectangleRow, RectangleCol)
*到这里就把世界坐标系中绝对ROI范围的点转换到了图像坐标系
*生成图像中的ROI
gen_region_polygon_filled (ROI, RectangleRow, RectangleCol)
*求最小外接矩形
smallest_rectangle2 (ROI, RowCenterROI, ColCenterROI, PhiROI, Length1ROI, Length2ROI)
* 准备测量,创建测量工具
gen_measure_rectangle2 (RowCenterROI, ColCenterROI, PhiROI, Length1ROI, Length2ROI, 652, 494, 'bilinear', MeasureHandle)
*启动测量
measure_pairs (Image, MeasureHandle, 0.4, 5, 'all_strongest', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
close_measure (MeasureHandle)
dev_display (Image)
disp_message (WindowHandle, 'Measuring the position of the pitch lines', 'window', 450, 25, 'red', 'false')
dev_set_color ('green')
*求出每条直线线宽的中点
RowPitchLine := (RowEdgeFirst + RowEdgeSecond) / 2.0
ColPitchLine := (ColumnEdgeFirst + ColumnEdgeSecond) / 2.0
disp_cross (WindowHandle, RowPitchLine, ColPitchLine, 6, 0)
*将图像坐标系中的直线上的点转换到世界坐标系
image_points_to_world_plane (CamParam, FinalPose, RowPitchLine, ColPitchLine, 1, X1, Y1)
for I := 1 to |X1| by 1
    *设置文本在窗体的输出位置
    set_tposition (WindowHandle, RowEdgeFirst[I - 1] + 5, ColumnEdgeFirst[I - 1] - 20)
    if (I == |X1|)
        set_tposition (WindowHandle, RowEdgeFirst[I - 1], ColumnEdgeFirst[I - 2])
    endif
    *展示信息
    write_string (WindowHandle, X1[I - 1]$'.3f' + 'mm')
endfor
disp_continue_message (WindowHandle, 'black', 'true')
stop ()


(3)以指定点为中心,将图像转换成指定位姿的位置
dev_close_inspect_ctrl (YOfContour)
dev_close_inspect_ctrl (XOfContour)
* Now, transform the whole image
WidthMappedImage := 652
HeightMappedImage := 494
dev_display (Image)
* First, determine the scale for the mapping
* (here, the scale is determined such that in the
* surroundings of the points P0 and P1, the image scale of the
* mapped image is similar to the image scale of the original image)
*分别计算出世界坐标系和相应的图像坐标系中两点的距离
distance_pp (X[0], Y[0], X[1], Y[1], DistP0P1WCS)
distance_pp (RCoord[0], CCoord[0], RCoord[1], CCoord[1], DistP0P1PCS)
*求出世界坐标和图像坐标的比例关系
Scale := DistP0P1WCS / DistP0P1PCS
* Then, determine the parameter settings for set_origin_pose such
* that the point given via get_mbutton will be in the center of the
* mapped image
dev_display (Image)
disp_message (WindowHandle, 'Define the center of the mapped image', 'window', 12, 12, 'red', 'false')
*提取屏幕中的一点,后期以图像中这一点像素的位置将图片移动到屏幕中心
get_mbutton (WindowHandle, CenterRow, CenterColumn, Button1)
*将点转换为世界坐标系坐标
image_points_to_world_plane (CamParam, FinalPose, CenterRow, CenterColumn, 1, CenterX, CenterY)
*设置图片要转换的位姿,并将根据上面选的点平移图像
set_origin_pose (FinalPose, CenterX - Scale * WidthMappedImage / 2.0, CenterY - Scale * HeightMappedImage / 2.0, 0, PoseNewOrigin)
*生成一个从图像到世界坐标系的投影
gen_image_to_world_plane_map (Map, CamParam, PoseNewOrigin, 652, 494, WidthMappedImage, HeightMappedImage, Scale, 'bilinear')
*对图像应用投影
map_image (Image, Map, ImageMapped)
dev_clear_window ()
dev_display (ImageMapped)
* In the case that only one image has to be mapped, the operator
* image_to_world_plane can be used instead of the operators
* gen_image_to_world_plane_map and map_image.
*(可选)在只需要映射一个图像的情况下,可以使用操作符image_to_world_plane
*来代替操作符gen_image_to_world_plane_map和map_image。
image_to_world_plane (Image, ImageMapped, CamParam, PoseNewOrigin, WidthMappedImage, HeightMappedImage, Scale, 'bilinear')

四、补充,获取标定板的描述文件

标签:流程,pose,标定,dev,Halcon,image,位姿,坐标系
来源: https://blog.csdn.net/stephon_100/article/details/121007294

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有