工控网首页
>

应用设计

>

机器视觉运动控制一体机应用例程(四)提取目标轮廓

机器视觉运动控制一体机应用例程(四)提取目标轮廓

在实际的机器视觉应用项目中,常常需要提取产品的轮廓信息进行进一步的加工处理。在本次的课程中,我们将使用ZDevelop软件来演示提取目标轮廓的功能。

image.png

一检测原理及应用场景

(一)检测原理

提取轮廓也是基于边缘轮廓的算法。它是在输入的单通道图像中,获取梯度值大于设置的梯度阈值、连接的轮廓长度大于最小轮廓长度的所有轮廓点并输出轮廓点对应的位置坐标数据。

(二)应用场景

1.提取产品的轮廓特征进行加工,如鞋底点胶,根据特定形状裁切布艺等。

2.提取产品的外轮廓作为检测区域对产品进行外观检测。

二软件演示

(一)流程图

image.png

(二)实例演示

1.打开ZDevelop软件:新建项目→新建HMI文件→新建main.bas文件,用于编写界面响应函数→新建global_variable.bas文件用于定义和初始化全局变量并开启HMI自动运行任务→新建camera.bas文件用于实现相机采集功能→新建draw.bas文件用于更新绘制图形刷新界面→文件添加到项目。

image.png

2.设计HMI启动界面。

image.png

3.在global_variable.bas文件中定义并初始化全局变量,定义完成后运行Hmi.hmi文件。

'''''全局变量大部分使用数组结构'''''

''注:basic编程中很多函数会以TABLE(系统的数据结构)做为参数

''table                    说明                 table      说明

''11~12             鼠标操作时获取的坐标        15~18 提取轮廓ROI图像坐标数据        

''25~28             提取轮廓ROI控件坐标数据    40    轮廓点数量

''50~50+轮廓数量*2  指定轮廓的轮廓点坐标          

'***********定义程序任务相关变量**********************

'主任务状态

'0 - 未初始化

'1 - 停止

'2 - 运行中

'3 - 正在停止

GLOBAL DIM main_task_state

main_task_state = 1

'运行任务开关

GLOBAL DIM run_switch

run_switch = 0

'采集任务开关

'0 - 停止采集

'1 - 请求采集

GLOBAL DIM grab_switch

grab_switch = 0

'定位检测主任务id - 10

GLOBAL DIM main_task_id

main_task_id = 10

'相机连续采集线程id - 7

GLOBAL DIM grab_task_id

grab_task_id = 7

'***********结束定义程序任务相关变量******************

'***********定义相机采集相关变量**********************

'相机种类,此处使用海康相机-"mvision"

GLOBAL DIM CAMERA_TYPE(100)

'CAMERA_TYPE = "mindvision;basler;mvision;huaray;zmotion"

CAMERA_TYPE = "mvision"

'相机个数

GLOBAL cam_num

cam_num = 0

'相机模式,-1 连续采集,0-软件触发采集

GLOBAL cam_mode

cam_mode = 0

'***********结束定义相机采集相关变量******************

'定义使用ROI标志,1-使用ROI,0-使用全图像区域

GLOBAL DIM d_roi_arc_flag 

d_roi_arc_flag = 0

'定义鼠标按下标志位,1-已按下,0-未按下

GLOBAL DIM is_set_roi_m_down

is_set_roi_m_down = 0

GLOBAL DIM d_detect_time '定义消耗的时间变量

d_detect_time = 0

'定义程序执行过程中采集的图像变量、二值化图像变量、显示图像变量、提取到的轮廓列表

GLOBAL ZVOBJECT grabImg,binImg,colorImg,contlist

'定义最小轮廓长度

GLOBAL DIM minLength

minLength=1700    '默认提取轮廓最小长度为1700像素

'定义提取到轮廓的数量

GLOBAL DIM count

count=0

'定义保存参数标志

GLOBAL DIM d_is_saved

'定义提取轮廓的ROI区域

GLOBAL DIM d_learn_roi(4)

d_learn_roi(0)=180

d_learn_roi(1)=110

d_learn_roi(2)=380

d_learn_roi(3)=310

TABLE(25) = d_learn_roi(0) '将矩形ROI数据存放到起始地址为25的table数组中

TABLE(26) = d_learn_roi(1)

TABLE(27) = d_learn_roi(2)

TABLE(28) = d_learn_roi(3)

'常用颜色变量

GLOBAL C_RED, C_GREEN, C_BLUE, C_YELLOW

C_RED   = RGB(255,  0,  0)

C_GREEN = RGB(  0,255,  0)

C_BLUE  = RGB(  0,  0,255)

C_YELLOW= RGB(255,255,  0)

'***********定义读取本地文件功能相关变量**************

''注意,该功能只在使用仿真器时有效

'定义是否使用本地图片标志

GLOBAL DIM d_use_imgfile

d_use_imgfile=1

'定义本地图片索引

GLOBAL DIM d_index

'定义读取图片的路径

GLOBAL DIM File_Name(100)   

'***********结束定义读取本地文件功能相关变量**********

'初始化全局变量完成后开启HMI文件

RUN"Hmi1.hmi",1

4.关联HMI启动界面值控件变量。

image.png

5.在main.bas文件中添加HMI界面初始化函数并在Hmi系统设置中关联初始化函数。

end

'注:

'凡是要使用Region有关的算子在系统初始化时都要调用ZV_RESETCLIPSIZE(width, height)这个算子设置下图像尺寸,以满足相机分辨率,因为默认的是640*480尺寸

'HMI界面初始化函数

GLOBAL SUB hmi_init()

    grab_switch = 0              '停止采集

    main_task_state = 1          '主任务停止运行

    if(VR(7)=1)then             '如果已保存参数

         btn_LoadParam()

    endif

    ZV_RESETCLIPSIZE(1280, 960)'初始化时依据图像分辨率设置区域的裁剪尺寸,此处图像分辨率为1280x960

    ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(10, 1), HMI_CONTROLSIZEY(10, 1)) '设置锁存的大小

    ZV_SETSYSDBL("CamGetTimeout", 1000) '设置采集超时

    ZV_LATCHCLEAR(0)           '清空锁存通道0

  

END SUB

'加载保存参数子程序

GLOBAL SUB btn_LoadParam()

    '加载保存的参数

    minLength=VR(0)

    d_roi_arc_flag=VR(1)

    d_learn_roi(0)=VR(2)

    d_learn_roi(1)=VR(3)

    d_learn_roi(2)=VR(4)

    d_learn_roi(3)=VR(5)

    d_use_imgfile =VR(6)

    TABLE(25)    = VR(9)

        TABLE(26)    = VR(10)

        TABLE(27)    = VR(11)

        TABLE(28)    = VR(12)

END SUB

image.png

6.在draw.bas文件中添加检测ROI更新绘制函数,并在自定义元件属性窗口中关联刷新函数和绘制函数。

end

'和绘制(即选择ROI)有关的界面的刷新绘制函数放在这个bas文件里

  DIM is_redraw

  is_redraw = 0

  

  DIM hit_pos,sr_mpos_x ,sr_mpos_y 

    

'根据鼠标操作更新训练颜色样本的有效区域

GLOBAL SUB update_roi()

    if d_roi_arc_flag = 1 then   '如果选择ROI类型为矩形

         if mouse_scan(11) = 1 then    '扫描鼠标按下操作

              is_set_roi_m_down = 1       '鼠标按下标志置1

              sr_mpos_x = table(11)      '将当前鼠标按下位置的坐标赋值给变量

              sr_mpos_y = table(12)

              '只有按下时可以改变击中位置,获取鼠标点击位置对应的击中区域编号

              hit_pos = ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 25, -1) 

              is_redraw = 1              '绘图标志置1

          endif

      

          if mouse_scan(11) = -1 then    '扫描鼠标松开操作

              is_set_roi_m_down = 0       '鼠标按下标志置0

              sr_mpos_x = table(11)       '将当前鼠标松开位置的坐标赋值给变量

              sr_mpos_y = table(12)

              '根据区域编号调整定位器区域位置

              ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 25, hit_pos)

              is_redraw = 1               '绘图标志置1

          endif

        '如果鼠标按下时

        if (is_set_roi_m_down and MOUSE_state(11)) then

            sr_mpos_x = table(11)       '将当前鼠标按下位置的坐标赋值给变量

            sr_mpos_y = table(12)

            '根据区域编号调整定位器区域位置

            ZV_HMIADJRECT(sr_mpos_x, sr_mpos_y, 25, hit_pos)

            is_redraw = 1               '绘图标志置1

        endif 

        

        if (1 = is_redraw) then       '如果绘制标志=1

            is_redraw = 0              '将绘制标志置0

            '控件roi坐标转图像roi坐标,控件坐标存放在起始地址为25的数组,图像坐标存放在起始地址为15的数组

            ZV_POSTOIMG(0, 2, 25, 15)

            '将图像坐标的数据赋值给ROI变量中

            d_learn_roi(0) = TABLE(15)

            d_learn_roi(1) = TABLE(16)

            d_learn_roi(2) = TABLE(17)

            d_learn_roi(3) = TABLE(18)

            SET_REDRAW  '重新绘制全部区域

        endif

    else 

        SET_REDRAW  

    endif

  

END SUB

'根据更新的鼠标位置坐标绘制训练颜色样本区域

GLOBAL SUB draw_roi()

    if d_roi_arc_flag = 1 then '如果ROI类型为矩形

      

        SET_COLOR(C_BLUE)    '设置绘制时画笔的颜色为蓝色

        '根据控件坐标数据绘制矩形

        DRAWRECT(TABLE(25), TABLE(26), TABLE(27), TABLE(28))

        

        local cx,cy   '定义局部变量

        cx = (TABLE(25) + TABLE(27)) / 2 '计算矩形的中心坐标x、y

        cy = (TABLE(26) + TABLE(28)) / 2

      

        DRAWLINE(cx-5, cy, cx+5, cy)  '绘制中心十字线

        DRAWLINE(cx, cy-5, cx, cy+5)

    endif

    

END SUB

image.png

7.在camera.bas文件中添加HMI界面中采集相关按钮响应的函数并关联动作函数。

end

'主界面按下扫描相机按钮时响应的函数

GLOBAL SUB cam_scan_all()

    if(d_use_imgfile=1)then 

        ?"请先按下使用本地图片按钮关闭该功能"

        return 

    endif 

  

    ZV_SETSYSINT("LogLevel", 7)     '设置控制器信息

    ZV_SETSYSSTR("DataDir","")

      

    CAM_SCAN(CAMERA_TYPE)           '扫描相机,CAMERA_TYPE="mvision"

    cam_num = CAM_COUNT()           '获取扫描到的相机数量

    if (0 = cam_num) then           '如果相机数量=0,打印提示信息

        ? "未找到相机"    

        return                       '退出子函数,不往下执行

    endif

    ?"cam_num = " cam_num            '如果扫描到相机,打印相机数量

    cam_mode = 0                     '设置软触发采集

    

    CAM_SEL(0)                       '选择扫描到的第一个相机进行操作

    CAM_SETEXPOSURE(5000)           '设置相机曝光时间为5000us      

    CAM_SETMODE(cam_mode)            '设置软件触发模式

    CAM_START(0)                     '开启相机  

  

END SUB

'主界面按下单次采集按钮执行的函数

GLOBAL SUB btn_grab()

    '如果d_use_imgfile=1时使用读取本地图片功能,使用控制器时请将此部分代码注释掉

    if (d_use_imgfile=1) then 

        if(d_index=3) then 

             d_index=0

        endif

        File_Name="\提取轮廓\"+TOSTR(d_index,1,0)+".bmp"   '.../flash/提取轮廓/目录下的图片所在的路径名称

        ZV_IMGREAD(grabImg,File_Name,0)

        ZV_LATCH(grabImg, 0) 

        d_index=d_index+1

    return   

    endif

    ''读取本地图片功能结束

  

  '如果相机数量为0,提示先扫描相机,并退出子函数不往下执行

    if cam_num = 0   then 

         ?"请先扫描相机!"

    return 

    endif

  

    CAM_SETPARAM("TriggerSoftware", 0)  '发送触发指令

    CAM_GET(grabImg, 0)                 '获取一帧图像存放到grabImg变量中

    ZV_LATCH(grabImg, 0)                '将图像显示到锁存通道0中

  

END SUB

'主界面按下连续采集按钮响应的函数

GLOBAL SUB btn_cgrab()

    if grab_switch =1 then                 '如果已经处于连续执行状态,打印提示信息并退出函数

         ?"正在连续运行中,请勿重复操作!"

         return 

    endif

    

    if( d_use_imgfile =0) then '如果使用相机采集功能         

        if cam_num = 0   then    '判断如果相机数量=0,打印提示信息并退出函数        

         ?"请先扫描相机!"

         return 

        endif

    endif

    

    grab_switch = 1            '采集任务开关置1

    if (1 = grab_switch) then

        if (0 = PROC_STATUS(grab_task_id)) then

            RUNTASK  grab_task_id, grab_task  '开启连续采集任务

        endif

    endif

  

END SUB

'采集任务实现函数

grab_task:

    while(1)

        if (0 = grab_switch) then  '如果采集任务开关=0即停止采集按钮按下时

            exit while             '退出循环

        endif

          

    'grab_switch=1时重复执行以下操作

    btn_grab()'单次采集按钮响应的函数

    wend

END

'主界面按下停止采集按钮响应的函数

GLOBAL SUB btn_stopCgrab()

    if grab_switch =0 then  '如果已经处于停止采集状态,打印提示信息并退出函数

        ?"未开启连续采集!"

    return 

    endif

  

    grab_switch = 0          '将采集任务开关置0

END SUB

image.png

8.在main.bas文件中添加HMI界面按下【保存】按钮时响应的函数并关联动作函数名。

'HMI界面按下保存按钮时响应的函数

GLOBAL SUB btn_SaveParam()

    VR(0)=minLength

    VR(1)=d_roi_arc_flag

    VR(2)=d_learn_roi(0)

    VR(3)=d_learn_roi(1)

    VR(4)=d_learn_roi(2)

    VR(5)=d_learn_roi(3)

    VR(6)=d_use_imgfile

    VR(9)=TABLE(25)

    VR(10)= TABLE(26)

    VR(11)=TABLE(27)

    VR(12)=TABLE(28)

    d_is_saved=1

    VR(7)=d_is_saved

    ?"已成功保存参数"

END SUB

image.png

9.在main.bas文件中添加HMI界面按下【测试】按钮响应的函数并关联动作函数。

'定义HMI界面按下测试按钮时响应的函数

GLOBAL SUB btn_test()

    TICKS=0

    ZVOBJECT regionMask,contour,genList,fragment

    '生成ROI区域

    if d_roi_arc_flag = 1 then '如果选择的ROI类型是矩形

         '根据ROI数据生成旋转矩形区域

         ZV_REGENRECT(regionMask,d_learn_roi(0),d_learn_roi(1),d_learn_roi(2)-d_learn_roi(0)+1,d_learn_roi(3)-d_learn_roi(1)+1)   '生成矩形测量区域

    else

        '生成全图像区域

        ZV_REGENFULLIMG(grabImg,regionMask)

    endif

    ZV_CLEAR(contlist)

    ZV_CONTGENSUBPIX(grabImg, regionMask,contlist,120,220,minLength) '从有效区域中提取最小轮廓长度为minLength的边缘轮廓,并将提取的结果存于 list 列表中

    ZV_GRAYTORGB(grabImg,colorImg)'将灰度图转换到RGB图像,用于绘制检测结果图像

    count = ZV_LISTCOUNT(contlist)   '获取列表中的数量

    for i=0 to count-1

        ZV_LISTGET(contlist,contour,i)   '获取列表中序号为i的元素

        ZV_CONTCOUNT(contour,40) '获取轮廓点的数量

        ZV_CONTOUR(colorImg,contour,zv_color(0,255,0))

      

'       '获取轮廓点数据方法1,获取所有轮廓点数据

'       for j=0 to TABLE(40)-1

'            ZV_CONTGETPT(contour,j,50) '指定轮廓中第i个点的坐标放到 TABLE (50)中 

'        next

  

         '获取轮廓点数据方法2,将轮廓分割成基元

          ZV_CLEAR(genList)

          ZV_CONTSEGMENT(contour,genList,0,1,1) '将轮廓分割成直线基元

          DIM num

          num=ZV_LISTCOUNT(genList)

          for j=0 to num-1

              ZV_LISTGET(genList,fragment,j)   '获取列表中序号为j的元素

              ZV_CONTGETPARAM(fragment,64,50)'获取轮廓基元类型和直线基元参数,包括基元类型,直线起始坐标x、y终点坐标x,y

              ZV_LINE(colorImg,TABLE(51),TABLE(52),TABLE(53),TABLE(54),C_BLUE)'绘制轮廓分割后提取的效果

          next

    

    next

    ZV_LATCH(colorImg,0)

    d_detect_time=abs(TICKS)

END SUB

image.png

10.在main.bas文件中添加HMI界面按下【运行】按钮响应的函数并关联动作函数。

'主界面点击运行按钮时响应的函数

GLOBAL SUB btn_run()

    if(run_switch = 1) then  '如果已经开启连续运行

        ?"已开启连续运行,请勿重复操作!" '提示信息并退出子函数,不往下执行

        return 

    endif

    

    run_switch = 1      '主任务开关置1

    if (1 = run_switch) then   '如果主任务开关=1

        if (0 = PROC_STATUS(main_task_id)) then '如果main_task_id任务未开启

            RUNTASK  main_task_id, main_task    '开启main_task任务

        endif

    endif

END SUB

'主任务执行的内容

main_task:

    while(1)

        if (0 = run_switch) then '如果主任务开关=0即停止运行按钮按下时

            exit while           '退出循环

        endif

      

        '否则重复执行以下操作

        '执行单次采集响应函数获取一帧图像

        btn_grab() 

        '执行提取轮廓子程序          

        btn_test()

    wend

  

END

image.png

11.在main.bas文件中添加HMI启动界面按下【停止】按钮响应的函数并关联动作函数。

'主界面点击停止按钮时响应的函数

GLOBAL SUB btn_stop()

    if(run_switch = 0) then  '如果主任务开关=0

         ?"未开启连续运行!"     '提示未开启循环任务,并退出子函数不往下执行

         return 

     endif

  

     run_switch = 0            '主任务开关置0,退出循环

END SUB

image.png

(三)仿真演示效果图

image.png

image.png

image.png

本次,正运动技术机器视觉运动控制一体机应用例程(四)——提取目标轮廓,就分享到这里。

更多精彩内容请关注“正运动小助手”公众号,需要相关开发环境与例程代码,请咨询正运动技术销售工程师:400-089-8936。

本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。

审核编辑(
王静
)
投诉建议

提交

查看更多评论
其他资讯

查看更多

正运动全国产EtherCAT运动控制器ZMC432H用户手册

正运动全国产EtherCAT运动控制器ZMC432H

正运动技术运动控制器如何快速实现单轴/多轴同步跟随功能?

正运动ECI1408运动控制卡用户手册

正运动机器视觉运动控制一体机VPLC710