勇哥的视觉实验: 模板匹配(1)使用基于描述符的模板匹配在图片序列中寻找不同姿式的饼干盒子

说明:

模板匹配是halcon的强项,opencv自带的模板匹配算子跟halcon这个比起来差好几层楼那么多。
在视觉引导定位时,模板匹配是少不了的东西。
所有的新手在遇到阈值搞不定的应用时,都会想到模板匹配,可见其概念和易用性已经深入人心。
但实际上halcon的模板匹配的知识点还是很多的,并非仅仅是我们常见的形态模板匹配。
勇哥这个系列贴子用来补全halcon模板匹配的相关系列知识。


使用基于描述符的模板匹配在图片序列中寻找不同姿式的饼干盒子


这个例子展示了如何使用基于描述符的匹配特性找到一个不同方向饼干盒子。

首先,根据参考图像计算模型和参考姿态,然后在显示不同方向的饼干盒子的图像序列中搜索模型。

使用得到的姿势,我们还可以检查盒子是否倒置。


代码说明:


(一)

关于算子vector_to_pose

在贴子《HALCON高级篇:3d相机标定(一)基础理论中我们讨论过相机外参可以用下面三种方法来确定:

1. 利用从某一个标定图像获取的位姿,其中标定图像中标定板被直接放置在测量平面上。在这种情况下,你就可以用算子get_calib_data来获得其位姿。

2. 通过一个标定板被直接放置在测量平面的额外图像,将相机内参的确定从相机外参的确定分离出来。应用find_calib_object去提取标定标志点和位姿。

3. 自己去确定3D世界点和它们在图像映射的对应关系,然后调用vector_to_pose。


vector_to_pose需要知道至少不再一条直线上3个点的3D世界坐标,然后,你必须确定这些3d点映射后相对应的图像坐标,然后vector_to_pose就能计算出外参。

如下面代码所示:

RowsRoi := [224,224,406,406]
ColumnsRoi := [115,540,540,115]
WorldX := [-189,189,189,-189] / 1000.0
WorldY := [-80,-80,80,80] / 1000.0
* reference pose of the object to the camera is computed
vector_to_pose (WorldX, WorldY, [], RowsRoi, ColumnsRoi, CamParam, 'iterative', 'error', Pose, Quality)

(二)

未完待续……



演示代码:

* This example shows how to find a cookie box aligned in different
* directions with the descriptor based matching feature. First, a
* model and a reference pose are computed from the reference
* image, then the model is searched in a sequence of images
* showing the cookie box in different orientations. Using the
* resulting pose we can also check whether the box is placed
* upside down or not.
* 
* 
ReCreateDescrModel := false
* 
dev_update_off ()
dev_close_window ()
read_image (Image, 'packaging/cookie_box_01')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (4)
dev_set_color ('blue')
* 
gen_cam_par_area_scan_division (0.0155565, -109.42, 1.28008e-005, 1.28e-005, 322.78, 240.31, 640, 480, CamParam)
* 
* 
RowsRoi := [224,224,406,406]
ColumnsRoi := [115,540,540,115]
WorldX := [-189,189,189,-189] / 1000.0
WorldY := [-80,-80,80,80] / 1000.0
* reference pose of the object to the camera is computed
vector_to_pose (WorldX, WorldY, [], RowsRoi, ColumnsRoi, CamParam, 'iterative', 'error', Pose, Quality)
image_points_to_world_plane (CamParam, Pose, RowsRoi, ColumnsRoi, 'm', XOuterBox, YOuterBox)
* generate ROI for model training
gen_rectangle1 (Rectangle, 224, 115, 406, 540)
reduce_domain (Image, Rectangle, ImageReduced)
* 
* If desired re-create the descriptor-based model. Note that this may take
* several minutes dependent on the hardware.
dev_display (Image)
if (ReCreateDescrModel)
    dev_display (Rectangle)
    disp_message (WindowHandle, 'Creating the descriptor-based model ... \n(may take a minute)', 'window', 10, 10, 'black', 'true')
    count_seconds (SecondsCreation1)
    create_calib_descriptor_model (ImageReduced, CamParam, Pose, 'harris_binomial', [], [], ['depth','number_ferns','patch_size','min_scale','max_scale'], [11,30,17,0.4,1.2], 42, ModelID)
    count_seconds (SecondsCreation2)
    TimeCreation := SecondsCreation2 - SecondsCreation1
    write_descriptor_model (ModelID, 'cookie_box_model.dsm')
else
    * If desired read the descriptor-based model from disk
    disp_message (WindowHandle, 'Reading the descriptor-based model file from disk ...\n ... will take a few seconds!', 'window', 10, 10, 'black', 'true')
    dev_set_check ('~give_error')
    dev_error_var (ErrorVar, 1)
    read_descriptor_model ('cookie_box_model.dsm', ModelID)
    Error := ErrorVar
    dev_set_check ('give_error')
    if (Error != H_MSG_TRUE)
        * Create the descriptor-based model if it's not available on disk
        dev_display (Image)
        dev_display (Rectangle)
        disp_message (WindowHandle, 'Reading the descriptor-based model file from disk  ... \n... failed!', 'window', 10, 10, 'black', 'true')
        disp_message (WindowHandle, 'Creating the descriptor-based model (may take a minute)', 'window', 48, 10, 'black', 'true')
        * 
        count_seconds (SecondsCreation1)
        create_calib_descriptor_model (ImageReduced, CamParam, Pose, 'harris_binomial', [], [], ['depth','number_ferns','patch_size','min_scale','max_scale'], [11,30,17,0.4,1.2], 42, ModelID)
        count_seconds (SecondsCreation2)
        TimeCreation := SecondsCreation2 - SecondsCreation1
        * Ignore writing errors as they are not critical for this example
        dev_set_check ('~give_error')
        write_descriptor_model (ModelID, 'cookie_box_model.dsm')
        dev_set_check ('give_error')
        ReCreateDescrModel := true
    endif
endif
* 
* 
if (ReCreateDescrModel)
    dev_display (Image)
    disp_message (WindowHandle, 'One model created in ' + TimeCreation$'.03f' + ' seconds.', 'window', 10, 10, 'black', 'true')
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endif
* 
* 
* Main loop:
* search model in image sequence
for Index := 1 to 10 by 1
    OutputString := []
    read_image (Image, 'packaging/cookie_box_' + Index$'.02')
    dev_display (Image)
    * 
    * find model (using default parameters)
    count_seconds (Seconds1)
    find_calib_descriptor_model (Image, ModelID, [], [], [], [], 0.25, 1, CamParam, 'num_points', Pose, Score)
    count_seconds (Seconds2)
    Time := Seconds2 - Seconds1
    * 
    * display results
    if (|Score| > 0)
        get_descriptor_model_points (ModelID, 'search', 0, Row, Col)
        dev_set_colored (12)
        dev_set_line_width (1)
        gen_cross_contour_xld (Cross1, Row, Col, 6, 0.785398)
        dev_display (Cross1)
        dev_set_color ('lime green')
        dev_set_line_width (3)
        disp_3d_coord_system (WindowHandle, CamParam, Pose, 0.07)
        * 
        pose_to_hom_mat3d (Pose, HomMat3D)
        affine_trans_point_3d (HomMat3D, XOuterBox, YOuterBox, [0,0,0,0], XTrans, YTrans, ZTrans)
        project_3d_point (XTrans, YTrans, ZTrans, CamParam, RowTrans, ColTrans)
        * 
        * 
        gen_contour_polygon_xld (Contour, RowTrans, ColTrans)
        close_contours_xld (Contour, Contour)
        dev_display (Contour)
        * 
        * determine direction of box
        if ((Pose[5] > 45 and Pose[5] < 135) or (Pose[5] > 225 and Pose[5] < 315))
            OutputString := 'Box label found in ' + (Time * 1000)$'.4' + ' ms (on the side)'
        elseif (Pose[5] > 135 and Pose[5] < 225)
            OutputString := 'Box label found in ' + (Time * 1000)$'.4' + ' ms (upside down)'
        else
            OutputString := 'Box label found in ' + (Time * 1000)$'.4' + ' ms'
        endif
    endif
    if (|Score| == 0)
        OutputString := 'No label found'
    endif
    disp_message (WindowHandle, OutputString, 'window', 10, 10, 'black', 'true')
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endfor
dev_display (Image)
disp_message (WindowHandle, 'Program finished.\nPress \'Run\' to clear all descriptor models.', 'window', 10, 10, 'black', 'true')
stop ()
dev_update_on ()




image.png


image.png


--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!



隐藏资源

您需要注册登录后才能查看此内容!
本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864