QQ登录

只需一步,快速开始

3.3 halcon实现上位机检测胶囊的有无与缺陷

[ 复制链接 ]
当前帖子实现一个在医药行业的视觉应用,实现功能是检测被自动填充的胶囊。是否有被填充,被填充的胶囊是否正确。


思路首先是获取 胶囊区域在摆正时的中心坐标和角度,
同时得到在这种情况 下所有胶囊区域 集合及背景骨架,可以理解为预先定位。
采用blob提取和几何变换相结合方法定位选择一个位置,
让后续采集的图像 都 在这个固定的位置提取药品目标区域 ,从而 进行检测 ,周而复始地进行检测工作。


让胶囊区域 和前面 预先确定的固定位置复合,是通过旋转加平移实现,
在这个位置提取前面 保存的胶囊区域 集合,
这样就可以让每张图像 通过 定位提取得到所有的对应区域。
最后对这些区域 进行处理和遍历,判断 它们的面积和灰度特点等。
进而得到结果。
这是一个思路。也可以采用其他 的blob分析 思路 ,
如用原图和背景骨架做差,得到目标区域 ,再配合几何变换,同样可以定位到目标区域 。
blob分析 定位方法很灵活,核心 思想就是想办法利用自己熟悉的算子逼近与定位ROI。

下面是代码的实现与注释
2019-03-22_000749.jpg

  1. dev_close_window ()
  2. dev_update_off ()
  3. read_image (ImageOrig, 'blister/blister_reference')
  4. dev_open_window_fit_image (ImageOrig, 0, 0, -1, -1, WindowHandle)
  5. set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
  6. dev_set_draw ('margin')
  7. dev_set_line_width (3)
  8. *
  9. *获取多通道图像ImageOrig的第一通道图像。
  10. access_channel (ImageOrig, Image1, 1)
  11. threshold (Image1, Region, 90, 255)
  12. *将二值化的区域 进行凸性转换,也就是将区域外围凹陷处填平,使区域更加规范,结果保存到Blister。
  13. shape_trans (Region, Blister, 'convex')
  14. *获取区域角度,单位角度,以水平向右为基准,逆时针方向 为正。
  15. orientation_region (Blister, Phi)
  16. *获取区域的面积 与中心坐标
  17. area_center (Blister, Area1, Row, Column)
  18. *从一个点和角度进行偏向 变换,这里目的是为了将图片进行旋转成水平位置。
  19. *第一个Row, Column, Phi为变换前点的坐标与角度,Row, Column, 0为变换后的点坐标与角度。0表示最后 区域 旋转成水平。
  20. *这个角度是以水平向右为基准,区域主轴和这个基准的夹角,逆时针为正。
  21. *这个算子也就是生成一个可以执行旋转平移的矩阵,以句柄 形式保存在变量HomMat2D。
  22. vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D)
  23. *用前面生成的旋转矩阵对图像进行旋转平移,ImageOrig为输入图, Image2为输出图
  24. * HomMat2D为旋转矩阵句柄, 'constant',为双线性插值方法,其灰度值 是由最邻近的四个像素 决定 。
  25. *'false'表示 是否自动调节输出图像的大小,false表示不自动 调节。
  26. affine_trans_image (ImageOrig, Image2, HomMat2D, 'constant', 'false')
  27. *生成一个空的图形对象
  28. gen_empty_obj (Chambers)
  29. *依次遍历每个颗粒,并画出来,同时叠加 到数组中,目的是和前面 的Blister求差,得到胶囊的骨架区域。
  30. for I := 0 to 4 by 1
  31.     Row := 88 + I * 70
  32.     for J := 0 to 2 by 1
  33.         Column := 163 + J * 150
  34.         gen_rectangle2 (Rectangle, Row, Column, 0, 64, 30)
  35.         concat_obj (Chambers, Rectangle, Chambers)
  36.     endfor
  37. endfor
  38. dev_display(Image2)
  39. dev_display(Chambers)
  40. stop()
  41. *进行区域反射变换,Blister, Blister, HomMat2D,分别有输入,输出图像和施加矩阵
  42. *'nearest_neighbor'为邻近插值方法,速度快但精度不高,目的是将胶囊板区域摆正,和Chamber求差。
  43. affine_trans_region (Blister, Blister, HomMat2D, 'nearest_neighbor')
  44. *求差算子,从区域Blister减去 Chambers区域,结果保存在Pattern。
  45. difference (Blister, Chambers, Pattern)
  46. *将Chambers的全部区域合并成一个
  47. union1 (Chambers, ChambersUnion)
  48. orientation_region (Blister, PhiRef)
  49. *将负值角度变换为对应的正角度。
  50. PhiRef := rad(180) + PhiRef
  51. area_center (Blister, Area2, RowRef, ColumnRef)
  52. * 开始循环读取6张图片,检测胶囊。
  53. Count := 6
  54. for Index := 1 to Count by 1
  55.     read_image (Image, 'blister/blister_' + Index


  56. 02')
  57.     *进行图像二值化处理,选取灰度值在90, 255的像素
  58.     threshold (Image, Region, 90, 255)
  59.     *将区域进行分割成为不相连的多个区域;
  60.     connection (Region, ConnectedRegions)
  61.     *选择面积在5000, 9999999的全部区域。
  62.     select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 5000, 9999999)
  63.     shape_trans (SelectedRegions, RegionTrans, 'convex')
  64.     *
  65.     * 将当前图像施加加平移,与前面的参考位置重合。
  66.     orientation_region (RegionTrans, Phi)
  67.     area_center (RegionTrans, Area3, Row, Column)
  68.     vector_angle_to_rigid (Row, Column, Phi, RowRef, ColumnRef, PhiRef, HomMat2D)
  69.     affine_trans_image (Image, ImageAffineTrans, HomMat2D, 'constant', 'false')
  70.     *
  71.     * 提取图像的药物区域
  72.     reduce_domain (ImageAffineTrans, ChambersUnion, ImageReduced)
  73.     *将三通道图像ImageReduced,进行拆分;
  74.     decompose3 (ImageReduced, ImageR, ImageG, ImageB)
  75.     *对图像 进行局部阈值分割,通过一个掩模的滑动求取局部均值和标准差来确定阈值。
  76.     *其实就是通过掩膜滑动每次计算对应图的均值 和标准差,把局部灰度相关较大的区域分割开
  77.     *也就是亮暗区域。ImageB, Region分别为输入图像与输出区域。7,7为掩模宽高,
  78.     *0.2为标准差因子,2为像素灰度值与与均值间的最小绝对 差值,dark为阈值类型,表示选择
  79.     *暗的还是亮的。此函数可以用于光照不是很均匀的图像。
  80.     var_threshold (ImageB, Region, 7, 7, 0.2, 2, 'dark')
  81.     connection (Region, ConnectedRegions0)
  82.     *采用结构元素宽高为3的矩形 结构进行闭运算。
  83.     closing_rectangle1 (ConnectedRegions0, ConnectedRegions, 3, 3)
  84.     fill_up (ConnectedRegions, RegionFillUp)
  85.     select_shape (RegionFillUp, SelectedRegions, 'area', 'and', 1000, 99999)
  86.     *采用结构元素半径为4.5的圆进行开运算。
  87.     opening_circle (SelectedRegions, RegionOpening, 4.5)
  88.     connection (RegionOpening, ConnectedRegions)
  89.     select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1000, 99999)
  90.     shape_trans (SelectedRegions, Pills, 'convex')
  91.     *
  92.     * 分类结果与显示统计
  93.     *计算药粒的个数
  94.     count_obj (Chambers, Number)
  95.     gen_empty_obj (WrongPill)
  96.     gen_empty_obj (MissingPill)
  97.     for I := 1 to Number by 1
  98.         select_obj (Chambers, Chamber, I)
  99.         *循环检测每个胶囊腔体位置内是否有胶囊
  100.         intersection (Chamber, Pills, Pill)
  101.         area_center (Pill, Area, Row1, Column1)
  102.         *面积大于0表示有,否则为无。
  103.         if (Area > 0)
  104.             *求图像指定区域的最大最小灰度值,Pill, ImageB为输入区域与图像。
  105.             *第三参数表示低于(高于)最大(最小)绝对值的百分比。0表示 无直方图代入计算。
  106.             *Min, Max, Range为输出值,表示最小最大灰度值,及它们的差值。
  107.             min_max_gray (Pill, ImageB, 0, Min, Max, Range)
  108.             if (Area < 3800 or Min < 60)
  109.                 *满足此条件记为有缺陷胶囊
  110.                 concat_obj (WrongPill, Pill, WrongPill)
  111.             endif
  112.         else
  113.             concat_obj (MissingPill, Chamber, MissingPill)
  114.         endif
  115.     endfor
  116.     *
  117.     dev_clear_window ()
  118.     dev_display (ImageAffineTrans)
  119.     dev_set_color ('forest green')
  120.     count_obj (Pills, NumberP)
  121.     count_obj (WrongPill, NumberWP)
  122.     count_obj (MissingPill, NumberMP)
  123.     dev_display (Pills)
  124.     if (NumberMP > 0 or NumberWP > 0)
  125.         disp_message (WindowHandle, 'Not OK', 'window', 12, 12 + 600, 'red', 'true')
  126.     else
  127.         disp_message (WindowHandle, 'OK', 'window', 12, 12 + 600, 'forest green', 'true')
  128.     endif
  129.     *
  130.     Message := '# Correct pills: ' + (NumberP - NumberWP)
  131.     Message[1] := '# Wrong pills  :  ' + NumberWP
  132.     Message[2] := '# Missing pills:  ' + NumberMP
  133.     *
  134.     Colors := gen_tuple_const(3,'black')
  135.     if (NumberWP > 0)
  136.         Colors[1] := 'red'
  137.     endif
  138.     if (NumberMP > 0)
  139.         Colors[2] := 'red'
  140.     endif
  141.     disp_message (WindowHandle, Message, 'window', 12, 12, Colors, 'true')
  142.     dev_set_color ('red')
  143.     dev_display (WrongPill)
  144.     dev_display (MissingPill)
  145.     if (Index < Count)
  146.         disp_continue_message (WindowHandle, 'black', 'true')
  147.     endif
  148.     stop ()
  149. endfor
复制代码




回复

使用道具 举报

快速回复 返回列表 客服中心 搜索