Halcon routine (based on 3D shape matching recognition method) detailed explanation-create_shape_model_3d_lowest_model_level.hdev

1. Introduction to routines

Recently, I was researching on 3D recognition. I checked a lot of information and found that there are many routines for 3D object recognition in halcon. Here is a detailed explanation of one of them. This routine is based on the three-dimensional matching method, because there is a three-dimensional model SM3, so you don’t need to create it yourself; in addition, because the images in the routine have many different poses, the memory required to build a three-dimensional model will be large, so set The lowest model level significantly reduces the algorithm running time, but relatively, it will lose the algorithm's robustness and retrieval time.
Insert picture description here

Second, the routine details

dev_update_off ()
* 设置面扫相机参数,参数可通过相机校正来获取。此算子为库函数,通过Division畸变模型生成一个相机参数元组。
* 其中参数含义为(焦距,模拟径向透镜畸变的畸变系数,传感器上两个相邻单元之间的水平距离,传感器上两个相邻单元之间的垂直距离,光心列坐标,光心行坐标,图宽,图高,输出相机参数)
gen_cam_par_area_scan_division (0.0269462, -354.842, 1.27964e-005, 1.28e-005, 254.24, 201.977, 512, 384, CamParam)
{ CameraParam :=['area_scan_division',Focus,Kappa,Sx,Sy,Cx,Cy,ImageWidth,ImageHeight]
return () }
* 获取相机参数,返回要求的图像宽参数。
get_cam_par_data (CamParam, 'image_width', IWidth)
{
*返回相机的类型和参数名
get_cam_par_names (CameraParam, CameraType, CameraParamNames)
* 
* 找到相机数据的索引并返回对应的值。
ParamValue := []
*依次读取参数名,ParamName在get_cam_par_names已被赋值,为'image_width'
for Index := 0 to |ParamName| - 1 by 1
    ParamNameInd := ParamName[Index]
    if (ParamNameInd == 'camera_type')
        ParamValue := [ParamValue,CameraType]
        continue
    endif
    * I为'image_width'在CameraParamNames的索引值,为7
    I := find(CameraParamNames,ParamNameInd)
    if (I != -1)
    *将图宽值赋值给ParamValue
        ParamValue := [ParamValue,CameraParam[I]]
    else
        throw ('Unknown camera parameter ' + ParamNameInd)
    endif
endfor
return () }
get_cam_par_data (CamParam, 'image_height', IHeight)
* 
read_image (Image, 'tile_spacers/tile_spacers_color_01')
dev_close_window ()
dev_open_window (0, 0, 512 * 1.5, 384 * 1.5, 'white', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_line_width (3)
dev_clear_window ()
disp_message (WindowHandle, 'Reading the 3D shape model file from disk ...', 'window', 12, 12, 'black', 'false')
* 如果磁盘没有可用的话就创建3D模型
try
*  读取3D形状模型,具体地址在C盘MVTec文件夹下examples\hdevelop\3D-Matching\Shape-Based。
    read_shape_model_3d ('tile_spacer.sm3', ShapeModel3DID)
catch (Exception)
    * 读目标3D模型的DXF文件,CAD格式,但因为上一步可以运行,所以这一部分没用了。
    * 参数(文件名,文件单位的转换尺度(单位为100um),参数名,参数值,3D模型句柄,状态信息)
    read_object_model_3d ('tile_spacer.dxf', 0.0001, [], [], ObjectModel3DID, DXFStatus)
    *为指定操作准备3D模型,可以计算所需要的值并储存在objectModel3D
    *参数(3D模型句柄,目的,指定是否应覆盖已存在的数据,参数名,参数值)
    prepare_object_model_3d (ObjectModel3DID, 'shape_based_matching_3d', 'true', [], [])
    disp_message (WindowHandle, 'Reading the 3D shape model file from disk ... not found!', 'window', 12, 12, 'red', 'false')
    disp_message (WindowHandle, 'Creating the 3D shape model (may take a few seconds) ...', 'window', 42, 12, 'black', 'false')
    count_seconds (S1)
    * 创建3D形状模型,是通过计算三维物体模型在用户指定的姿势范围内的不同视图而生成的。通过在三维物体模型周围放置虚拟摄像机,并将三维物体模型投影到每个虚拟摄像机位置的图像平面上,自动生成视图;
    * 因此,在生成三维形状模型时,不使用对象的图像,只使用在objectModel3D中传递的三维对象模型,所有视图的形状表示都存储在三维形状模型中,该模型返回到shapeModel3DID中。在创建三维形状模型之前,必须校准相机,以防止畸变。
    * 参数(3D模型句柄,相机参数,沿x轴/x分量旋转的罗德里格斯矢量,y轴,z轴,参考向量的旋转值,模型视图的最小经度,
    * 最大经度,模型视图的最小纬度,最大纬度,模型视图的最小摄影机滚动角度,最大角度,模型视图的最小摄影机对象距离,最大距离,搜索图像中对象的最小对比度,用于控制运算符行为的(可选)参数的名称(最低模型级别),可选参数值,句柄)
    create_shape_model_3d (ObjectModel3DID, CamParam, 0, 0, 0, 'gba', -rad(60), rad(60), -rad(60), rad(60), 0, rad(360), 0.26, 0.27, 10, 'lowest_model_level', 3, ShapeModel3DID)
    count_seconds (S2)
    T := S2 - S1
    disp_message (WindowHandle, 'Creation time: ' + T$'.3' + ' s', 'window', 72, 12, 'black', 'false')
    try
        disp_message (WindowHandle, 'Writing model to disk ...', 'window', 102, 12, 'black', 'false')
        *存储3D模型
        write_shape_model_3d (ShapeModel3DID, 'tile_spacer.sm3')
    catch (Exception)
        disp_message (WindowHandle, 'Writing model to disk ... failed!', 'window', 102, 12, 'red', 'false')
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endtry
endtry
*显示模型信息
disp_lowest_model_level_info (WindowHandle)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 匹配
Times := []
NumImages := 12
for I := 1 to NumImages by 1
    read_image (Image, 'tile_spacers/tile_spacers_color_' + I$'02')
    dev_display (Image)
    * 
    * 查找三个三维模型的实例,将“border”模型设置为“true”,因为对象可能会接触图像边界
    * 程序开始到现在过去的时间
    count_seconds (Seconds1)
    *在图像中找出一个3D模型的最佳匹配
    *参数(输入图像,3D模型的句柄,最低分数(值越大,搜索速度越快),贪婪度(值越大,搜索越快,但更容易失败),
    (该值决定搜索过程中金字塔层的数量,设为0,则数量为创建模型时的指定值),
    控制操作行为的参数名,参数值,模型的3D位姿,姿态参数的36个协方差或6个标准差,分数)
    find_shape_model_3d (Image,  ShapeModel3DID,0.7, 0.85, 0, ['num_matches','max_overlap','border_model'], [3,0.75,'true'], Pose, CovPose, Score)
    count_seconds (Seconds2)
    计算匹配时间
    Time := Seconds2 - Seconds1
    Times := [Times,Time]
    *通过使用匹配的姿势将三维形状模型投影到图像中,将找到的匹配项可视化
    for J := 0 to |Score| - 1 by 1
        *显示轮廓
        PoseTmp := Pose[J * 7:J * 7 + 6]
        *将三维形状模型的边投影到图像坐标中。
        project_shape_model_3d (ModelContours, ShapeModel3DID, CamParam, PoseTmp, 'true', rad(30))
        dev_set_color ('yellow')
        dev_display (ModelContours)
        * 显示3D模型的坐标系
        dev_set_colored (3)
        disp_3d_coord_system (WindowHandle, CamParam, PoseTmp, 0.015)
    endfor
    for K := 0 to |Score| - 1 by 1
        * 显示找到的位姿的参数
        PoseTmp := Pose[K * 7:K * 7 + 6]
        *自定义函数,显示位姿信息
        display_match_pose (ShapeModel3DID, PoseTmp, WindowHandle)
        {
        *查找模型参数(参考点坐标),
         get_shape_model_3d_params (ShapeModel3DID, 'reference_point', ReferencePoint)
         *查找相机参数
       get_shape_model_3d_params (ShapeModel3DID, 'cam_param', CamParam)
* 
* Project the reference point
* 将三维姿态转换为齐次变换矩阵。
pose_to_hom_mat3d (Pose, HomMat3D)
*对点应用任意仿射3D变换
affine_trans_point_3d (HomMat3D, ReferencePoint[0], ReferencePoint[1], ReferencePoint[2], X, Y, Z)
*将3D点投影到(亚)像素图像坐标中。
project_3d_point (X, Y, Z, CamParam, Row, Column)
* 显示参考点坐标
Message := 'Pose:'
Message[1] := '   X: ' + (1000 * Pose[0])$'4.1f' + ' mm'
Message[2] := '   Y: ' + (1000 * Pose[1])$'4.1f' + ' mm'
Message[3] := '   Z: ' + (1000 * Pose[2])$'4.1f' + ' mm'
Message[4] := '   Alpha: ' + Pose[3]$'4.1f' + '°'
Message[5] := '   Beta: ' + Pose[4]$'4.1f' + '°'
Message[6] := '   Gamma: ' + Pose[5]$'4.1f' + '°'
disp_message (WindowHandle, Message, 'image', Row, Column - 30, 'black', ['#ffffffcc','false'])
return () }
    endfor
    *在左上角显示匹配用时
    disp_message (WindowHandle, |Score| + ' Match(es) found in ' + Time$'4.2f' + ' s', 'window', 12, 12, 'dark green', ['white','false'])
    if (I < NumImages)
        disp_continue_message (WindowHandle, 'black', ['white','false'])
        stop ()
    endif
endfor
* 
disp_end_of_program_message (WindowHandle, 'black', ['white','false'])

Three, summary

The following summarizes the above-mentioned shape-based 3D matching method, which mainly includes the following steps:
1. Read/create 3D model read_object_model_3d/create_shape_model_3d;
2. Perform 3D matching on the two-dimensional image, calculate the score, and find_shape_model_3d
3 will match the result Visualization, project_shape_model_3d, project_3d_point
Generally speaking, this 3D matching method is still relatively easy to use. It can also recognize the occlusion between objects. The difficulty lies in tuning. The principle of this method is to search and judge the target in the image based on the pose information of the 3D model, and return a matching value. There is no more detailed code on the Internet. It should be more difficult. There are many based on point clouds. According to the data, the current industry's projects on 3D recognition are not very common, and there are few researchers. I hope that there will be improvements in the future.
If you have opinions and ideas, you can communicate together and pay attention to like and comment.

Guess you like

Origin blog.csdn.net/baidu_35536188/article/details/109504810