|  此前,我们依次讲解了软硬件介绍及计数实例、相机的基本使用、基于形状匹配的视觉定位、BLOB有无检测、测量尺寸、机器视觉方案中使用到的标定功能、ZDevelop软件实现识别条形码和二维码,以及测量点/直线/圆的功能。   本期课程我们和大家一起分享机器视觉中使用到的简单的外观检测功能---检测划痕。   视频教程:《VPLC系列机器视觉运动控制一体机快速入门(九)》            一、原理   外观检测是机器视觉技术中一个重要的检测功能,它可以检测产品表面的脏污、瑕疵、缺陷、毛边、划痕等不良因素。在包装行业和生产制造业被广泛应用。            1.划痕检测的原理是什么?   由于划痕是随机出现且不具有固定形态的特征,因此无法使用匹配等定位功能检测判断划痕。这时就需要用到形态学处理提取划痕特征,再配合BOLB检测判断划痕有无。   划痕检测是使用形态学方法(如顶帽算法)将灰度图像转换成二值化图像后,提取划痕的图像特征,再使用BLOB检测对划痕的特征进行有无检测。            2.什么是顶帽算法?   顶帽算法是将原始的图像(逐像素)减去开运算的图像,得到开运算中消除的小面积的局部亮像素区域的一种形态学处理方法。   开运算是先进行腐蚀,再进行膨胀的一种形态学处理方法。开运算可以去除一些孤立的、细小的亮区域,平滑有毛刺的边缘线,同时原区域的面积不会发生明显变化。对于灰度值高于产品灰度值的(亮)划痕可用顶帽算法检测出来。            3.什么是黑帽算法?   黑帽算法是将闭运算图像(逐像素)减去原始的图像,得到闭运算中消除的小面积的局部暗像素区域的一种形态学处理方法。   闭运算是先进行膨胀,再进行腐蚀的一种形态学处理方法。闭运算可以去除一些孤立的、细小的暗区域,同时原区域的面积不会发生明显变化。闭运算还可以填充小面积的亮区域的空洞,使分离的亮边缘相连接。对于灰度值低于产品灰度值的(暗)划痕可用黑帽算法检测出来。            二、划痕检测特点   1.依赖形态学处理   需要将检测图像转换成二值化图像,并使用形态学处理图像突出检测特征。   2.无固定形状特征   划痕都是随机出现的无特定形状的特征,因此无法通过匹配进行检测。   3.基于BLOB检测   提取出划痕特征后需要使用BLOB检测出连通的划痕区域。   4.需要一定对比度   划痕和待检测产品需要满足一定的对比度,才能使用形态学处理方法提取对应特征。            1.打开ZDevelop软件:新建项目→新建HMI文件→新建main.bas文件,用于编写界面响应函数→新建global_variable.bas文件用于存放全局变量并开启HMI自动运行任务→新建InitParam.bas文件用于初始化测量参数→新建camera.bas文件用于实现相机采集功能→新建draw.bas文件用于更新绘制图形刷新界面→文件添加到项目。            2.设计HMI界面。            3.在global_variable.bas文件中定义全局变量,定义完成后运行Hmi.hmi文件。
   '''''全局变量大部分使用数组结构'''''   ''注:basic编程中很多函数会以TABLE(系统的数据结构)做为参数   ''在这里table均是做为中间变量
   ''table 21-22,鼠标按键,控件坐标系   ''table 31-35,旋转矩ROI参数,cx、cy、width、height、angle,控件坐标系   ''table 41-45,旋转矩形控件坐标转换后对应的图像坐标,图像坐标系
   ''table 51-56,圆环ROI参数,cx、cy、圆环中线半径r、圆环半宽ann_R、起始角度stAngle、角度范围entAngle,控件坐标系   ''table 61-66,圆环控件坐标转换后对应的图像坐标,图像坐标系
   '主任务状态   '0 - 未初始化   '1 - 停止   '2 - 运行中   '3 - 正在停止   GLOBAL DIM main_task_state   main_task_state = 1
   '采集开关   '0 - 停止采集   '1 - 请求采集   GLOBAL DIM grab_switch   grab_switch = 0
   '相机个数   GLOBAL cam_num   cam_num = 0
   '相机种类,"zmotion;mvision;basler;mindvision;huaray"   GLOBAL DIM CAMERA_TYPE(16)   CAMERA_TYPE = "mvision"
   ' 定义主任务id - 10   GLOBAL DIM main_task_id   main_task_id = 10
   '定义连续采集任务id - 9   GLOBAL DIM grab_task_id   grab_task_id = 9
   '定义全局图像变量   GLOBAL ZVOBJECT grabImg '采集图像   GLOBAL ZVOBJECT binImg '二值化图像   GLOBAL ZVOBJECT disImg '显示图像
   '定义常用颜色变量   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_def_num '定义划痕数量结果   GLOBAL DIM d_def_state '定义状态结果
   '定义划痕数据结果存储数组变量   GLOBAL DIM value(10000),id
   '旋转矩形ROI参数:cx、cy、width、height、angle   GLOBAL DIM d_roi_rect2(5)
   '检测参数:划痕类型、检测方向、检测尺寸、对比度、最小面积、最大面积   GLOBAL DIM d_detect_param(6)
   '***********定义读取本地文件功能相关变量**************   ''注意,该功能只在使用仿真器时有效   '定义是否使用本地图片标志   GLOBAL DIM d_use_imgfile   d_use_imgfile=1
   '定义本地图片索引   GLOBAL DIM d_index   d_index=0
   '定义读取图片的路径   GLOBAL DIM File_Name(100)
   '***********结束定义读取本地文件功能相关变量**********
   '运行HMI文件   RUN "Hmi.hmi",1
   4.在InitParam.bas文件中初始化测量参数。
   end
   GLOBAL SUB init_detect_param()'初始化测量参数
      d_def_num = 0 '划痕结果初始化为0      d_def_state = 0 '状态结果初始化为0      TABLE(1)=1      '初始化roi参数      d_roi_rect2(0) = 160.0 'roi中心x      d_roi_rect2(1) = 120.0 'roi中心y      d_roi_rect2(2) = 80.0 'roi宽      d_roi_rect2(3) = 60.0 'roi高      d_roi_rect2(4) = 0.0 'roi角度      TABLE(31) = d_roi_rect2(0) '将roi变量赋值给起始地址为31的table数组      TABLE(32) = d_roi_rect2(1)      TABLE(33) = d_roi_rect2(2)      TABLE(34) = d_roi_rect2(3)      TABLE(35) = d_roi_rect2(4)
      '初始化检测参数:划痕类型、检测方向、检测尺寸、对比度、最小面积、最大面积      d_detect_param(0) = 0 '初始化划痕类型为暗      d_detect_param(1) = 2 '初始化检测方向为X轴和Y轴      d_detect_param(2) = 4 '初始化检测尺寸为4      d_detect_param(3) = 20 '初始化对比度为20      d_detect_param(4) = 2000 '初始化最小面积为2000个像素      d_detect_param(5) = 7000 '初始化最大面积为7000个像素
      '将划痕结果变量赋值为0      for i=0 to 100          value(i)=0      next
   END SUB
   5.关联HMI界面值显示控件变量。            6.在main.bas文件中添加HMI界面初始化函数并在Hmi系统设置中关联初始化函数。
   'HMI界面初始化函数      GLOBAL SUB hmi_init()
      grab_switch = 0 '初始化采集开关为停止采集      main_task_state = 1 '初始化主任务状态为停止状态
      '初始化时依据图像分辨率设置区域的裁剪尺寸,此处图像分辨率为1280x960      ZV_RESETCLIPSIZE(1280, 960)      '设置锁存通道0的大小,以适应图片元件控件大小      ZV_LATCHSETSIZE(0, HMI_CONTROLSIZEX(10, 7), HMI_CONTROLSIZEY(10, 7))
      ZV_SETSYSINT("LineWidth",5) '设置绘制画笔宽度为5个像素
      init_detect_param() '初始化测量参数
      ZV_LATCHCLEAR(0) '清空锁存通道0      ZV_LATCHCLEAR(1) '清空锁存通道1   END SUB            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_SEL(0) '选择扫描到的第一个相机进行操作      CAM_SETEXPOSURE(5000) '设置相机曝光时间为5000us      CAM_SETMODE(0) '设置软件触发模式      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="\9\"+TOSTR(d_index,1,0)+".bmp" '.../flash/9/目录下的图片所在的路径名称              ZV_IMGREAD(grabImg,File_Name,1)              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
   8.在draw.bas文件中添加检测ROI更新绘制函数,并在自定义元件属性窗口中关联刷新函数和绘制函数。
   end
      '和绘制(即选择ROI)有关的界面的刷新绘制函数放在这个bas文件里      DIM is_redraw '绘图标志,0表示未进行绘制,1表示正在进行绘制      is_redraw = 0
      DIM hit_pos '定义调整操作标志
   '根据鼠标操作更新ROI位置区域函数   GLOBAL SUB update_roi()
      if mouse_scan(21) = 1 then '扫描鼠标按下操作          '只有按下时可以改变击中位置,获取鼠标点击位置对应的击中区域编号          hit_pos = ZV_HMIADJRECT2(table(21), table(22), 31, -1)          is_redraw = 1 '绘图标志置1      endif
      if mouse_scan(21) = -1 then '扫描鼠标松开操作          '根据区域编号调整roi区域位置          ZV_HMIADJRECT2(table(21), table(22), 31, hit_pos)          is_redraw = 1 '绘图标志置1      endif
      if (MOUSE_state(21)) then '鼠标按下时          '根据区域编号调整roi区域位置          ZV_HMIADJRECT2(table(21), table(22), 31, hit_pos)          is_redraw = 1 '绘图标志置1      endif
      if (1 = is_redraw) then '如果绘制标志=1          is_redraw = 0 '绘图标志置0          '控件roi坐标转图像roi坐标,控件坐标存放在起始地址为111的数组,图像坐标存放在起始地址为50的数组          ZV_POSTOIMG(0, 1, 31, 41)          d_roi_rect2(0) = TABLE(41)'将图像坐标的数据赋值给ROI变量          d_roi_rect2(1) = TABLE(42)          d_roi_rect2(2) = ZV_LENTOIMG(0, TABLE(33))          d_roi_rect2(3) = ZV_LENTOIMG(0, TABLE(34))          d_roi_rect2(4) = TABLE(35)          SET_REDRAW '重新绘制全部区域      endif
   END SUB
   'ROI区域更新后实时绘制ROI区域   GLOBAL SUB draw_roi()
      SET_COLOR(C_BLUE) '设置画笔颜色为蓝色      ZV_HMIRECT2(31, 300) '将旋转矩形roi分解为HMI支持的绘图图元并添加控制参数,便于HMI绘图显示      DRAWLINE(TABLE(300), TABLE(301), TABLE(302), TABLE(303)) '绘制外矩形      DRAWLINE(TABLE(302), TABLE(303), TABLE(304), TABLE(305))      DRAWLINE(TABLE(304), TABLE(305), TABLE(306), TABLE(307))      DRAWLINE(TABLE(306), TABLE(307), TABLE(300), TABLE(301))   END SUB            9.在main.bas文件中添加HMI界面按下【上一页】按钮时响应的函数并关联动作函数名。            'HMI界面按下上一页按钮时响应的函数   GLOBAL SUB last_()
      id=id-1 'id变量自减1      if id<0 then '如果id变量<0          id =0 'id=0      endif
   END SUB            10.在main.bas文件中添加HMI界面按下【下一页】按钮时响应的函数并关联动作函数名。            'HMI界面按下下一页按钮时响应的函数   GLOBAL SUB next_()   id=id+1 'id变量自加1   END SUB            11.在main.bas文件中添加HMI界面按下【测试】按钮时响应的函数并关联动作函数名。            'HMI界面按下测试按钮时响应的函数   GLOBAL SUB btn_test()   for i=0 to 100 '检测前先将结果数据清零   value(i)=0   next   '定义二值化白色区域、二值化区域、二值化黑色区域、连通区域、检测结果、划痕输出图像、输出结果矩阵、结果列表   GLOBAL ZVOBJECT regionWhite, regionMask, regionBlack,re_connecte,rst,outImg,mat,relist   '根据ROI数据生成检测区域ROI   ZV_REGENRECT2(regionMask, d_roi_rect2(0), d_roi_rect2(1), d_roi_rect2(2), d_roi_rect2(3), d_roi_rect2(4))   '表面外观缺陷检测算子,传参分别是:输入图像、检测区域、输出检测结果、检测划痕类型、检测轴、检测尺寸、对比度阈值、最小面积、最大面积   ZV_DEFDETECTSUR_(grabImg,regionMask,rst,d_detect_param(0),d_detect_param(1),d_detect_param(2),d_detect_param(3),d_detect_param(4),d_detect_param(5))   '获取缺陷结果算子,传参分别是:检测结果、输出缺陷图像、数据结果矩阵、结果列表、输出图像类型、输出结果排序类型   ZV_DEFGETSURRST_(rst,outImg,mat,relist,2,0)'获取缺陷结果   ZV_LATCH(outImg,1)'将缺陷结果图像显示到锁存通道1中   ZV_MATINFO(mat,50)'获取结果矩阵的信息并存放到起始地址为50的变量中   d_def_num=table(50)'将矩阵行数即划痕数量赋值给结果变量   if (TABLE(50)=0) then '如果检测到的划痕数量=0,则结果状态=1   d_def_state=1   else d_def_state=0   endif   ?TABLE(50),TABLE(51)'打印提示矩阵的行数和列数信息   for i = 0 to TABLE(50)-1 '循环给数据结果变量赋值   '获取第i行矩阵数据结果,包括面积 周长,坐标x,坐标y   ZV_MATGETROW(mat, i, 4, 100+i*4)   value(i*4+0)=TABLE(100+i*4+0)'将table数据赋值给对应变量   value(i*4+1)=TABLE(100+i*4+1)   value(i*4+2)=TABLE(100+i*4+2)   value(i*4+3)=TABLE(100+i*4+3)   next   END SUB            12.在main.bas文件中添加【运行】按钮响应的函数并关联动作函数。            HMI界面按下运行按钮时响应的函数   GLOBAL SUB btn_run()   if(2 = main_task_state) then '如果主任务处于运行中状态       ?"已经开启连续运行任务,请勿重复操作!" '打印提示   return   endif      if (1 = main_task_state) then '如果主任务处于停止状态          if (0 = PROC_STATUS(main_task_id)) then'如果程序中任务未开启              main_task_state = 2 '将主任务状态设置为运行中状态              RUNTASK main_task_id, main_task'开启主任务           endif       endif   END SUB   '主任务执行的函数   main_task:      while(1)          '如果主任务状态处于正在停止状态即停止按钮按下时          if (3 = main_task_state) then              main_task_state = 1'将主任务状态设置为停止状态              exit while '退出循环          endif              '否则循环执行采集和检测函数              btn_grab()              btn_test()      wend   END            13.在main.bas文件中添加【停止】按钮响应的函数并关联动作函数。            HMI界面按下停止按钮时响应的函数   GLOBAL SUB btn_stop()   if (2 = main_task_state) then '如果主任务状态处于2即任务运行中时   main_task_state = 3 '将主任务状态置为3,退出循环   endif   END SUB                        本次,正运动技术VPLC系列机器视觉运动控制一体机快速入门(九)——外观检测功能---检测划痕,就分享到这里。   更多精彩内容请关注“正运动小助手”公众号,需要ZDevelop开发环境与例程代码,请咨询正运动技术销售工程师:400 089 8936。   本文由正运动技术原创,欢迎大家转载,共同学习,一起提高中国智能制造水平。文章版权归正运动技术所有,如有转载请注明文章来源。   正运动技术专注于运动控制技术研究和通用运动控制软硬件产品的研发,是国家级高新技术企业。正运动技术汇集了来自华为、中兴等公司的优秀人才,在坚持自主创新的同时,积极联合各大高校协同运动控制基础技术的研究,是国内工控领域发展最快的企业之一,也是国内少有、完整掌握运动控制核心技术和实时工控软件平台技术的企业。主要业务有:运动控制卡_运动控制器_EtherCAT运动控制卡_EtherCAT控制器_运动控制系统_视觉控制器__运动控制PLC_运动控制_机器人控制器_视觉定位_XPCIe/XPCI系列运动控制卡等等。 
 |