HALCON示例程序check_fish_stick_dimension.hdev生鱼棒尺寸测量;基于形态学的像素级精度尺寸测量

HALCON示例程序check_fish_stick_dimension.hdev基于形态学的像素级精度尺寸测量

示例程序源码(加注释)

  • 关闭实时显示更新
    dev_update_off ()

  • 关闭窗口
    dev_close_window ()

  • 读入图片
    read_image (Image, ‘food/fish_sticks_raw_01’)

  • 根据给定长宽比开辟窗口并显示图像
    dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)

  • 设置字体显示格式
    set_display_font (WindowHandle, 16, ‘mono’, ‘true’, ‘false’)

  • 区域以边缘形式进行显示
    dev_set_draw (‘margin’)

  • 获取系统关于“空白区域储存的设置”并进行设置,上一篇介绍过了
    get_system (‘store_empty_region’, StoreEmptyRegion)
    set_system (‘store_empty_region’, ‘true’)

  • 变量的声明与赋值
    cm_per_pix := 0.0373
    TargetLength := 9.0
    ToleranceHigh := 0.8
    ToleranceLow := 0.2

  • 定义图片数量
    NumImages := 10

  • 循环检测
    for I := 1 to NumImages by 1

    • 读入图片
      read_image (Image, ‘food/fish_sticks_raw_’ + I$’.2’)

    • 分割生鱼棒,将测量区域提取出来

    • 阈值分割选取灰度值在50-255的像素
      threshold (Image, Region, 50, 255)

    • 分割连通域
      connection (Region, ConnectedRegions)

    • 填充孔洞,使选取的生鱼棒完整
      fill_up (ConnectedRegions, RegionFillUp)

    • 筛选面积在1000-99999的区域,消除杂点干扰
      select_shape (RegionFillUp, SelectedRegions, ‘area’, ‘and’, 1000, 99999)

    • 选择不与图像边框相交的区域,不检测与图像边缘相交的生鱼棒,因为它不完整

    • 使用形态学运算来计算区域的边界,这里就是将图片边界提取出来
      boundary (Image, RegionBorder, ‘inner’)

    • 求图像边界与提取出生鱼棒区域的交集,如果有交集那么证明有生鱼棒位于图像边界,不进行检测。
      intersection (SelectedRegions, RegionBorder, RegionIntersection)

    • 求解上一步求出的交集的面积与坐标
      area_center (RegionIntersection, Area, Row1, Column1)

    • find(Area,0)这个算子意思是在Area数组里边寻找0这个元素,并且返回索引号;这里又在后边加

    • 了个 1,交集区域为空所以 Area:=[0,0,0,0],find(Area,0):=[0,1,2,3],

    • ValidRegionIndices := [1,2,3,4];如果find在Area数组内没有找到0,则返回-1
      ValidRegionIndices := find(Area,0) + 1

    • 如果ValidRegionIndices第一个元素不等0;ValidRegionIndices := []为空
      if (ValidRegionIndices[0] == 0)
      ValidRegionIndices := []
      endif

    • halcon自定义函数,目的在数组(第一个参数)寻找大于数值(第二个参数)的值,并返回索引号。
      select_tuple_larger (Area, 0.0, RegionAtBorderIndices)

    select_tuple_larger函数内部代码:
    ** sgn()返回数值的符号,(-1,0,1) **这里就是数组里边的值与输入值相减,根据符号判断1为正,之后用find返回数组数值为1的索引号
    tuple_find (sgn(Tuple - Value), 1, Indices)
    if (Indices[0] == -1)
    Indices := []
    endif
    return ()

    RegionAtBorderIndices := RegionAtBorderIndices + 1

    • select_obj 在元组中选取指定对象

    • 选取要正常测量的区域
      select_obj (SelectedRegions, ValidSticks, ValidRegionIndices)

    • 选取位于边界的区域
      select_obj (SelectedRegions, StickAtBorder, RegionAtBorderIndices)

    • 测量生鱼棒的尺寸

    • 求取生鱼棒的可旋转最小外接矩形
      smallest_rectangle2 (ValidSticks, Row, Column, Phi, Length1, Length2)

    • 求取生鱼棒的实际长度,用像素个数乘以像素尺寸
      FishLength1 := Length1 * 2 * cm_per_pix

    • 选取尺寸大于最小要求尺寸的生鱼棒
      select_tuple_larger (FishLength1, TargetLength - ToleranceLow, IndicesGood)

    • 选取尺寸大于最大要求尺寸的生鱼棒
      select_tuple_larger (FishLength1, TargetLength + ToleranceHigh, IndicesBad1)

    • tuple_remove从元组中删除元素,将尺寸大于最大要求尺寸的生鱼棒剔除
      tuple_remove (IndicesGood, IndicesBad1, IndicesGood)

    • 选取小于最小要求尺寸的生鱼棒
      select_tuple_larger (-FishLength1, -(TargetLength - ToleranceLow), IndicesBad2)

    • 将大于最大要求尺寸与小于最小要求尺寸的坏的生鱼棒的索引号合并到一个坏的生鱼棒的数组
      IndicesBad := [IndicesBad1,IndicesBad2]

    • subset()选择元组元组的一个或多个单个元素,相当于将好坏的坐标选取出来
      RowGood := subset(Row,IndicesGood)
      ColumnGood := subset(Column,IndicesGood)
      RowBad := subset(Row,IndicesBad)
      ColumnBad := subset(Column,IndicesBad)
      FishLength1Good := subset(FishLength1,IndicesGood)
      FishLength1Bad := subset(FishLength1,IndicesBad)

    • 绘制外接矩形框
      if (|IndicesGood| > 0)
      gen_rectangle2 (GoodSticks, RowGood, ColumnGood, subset(Phi,IndicesGood), subset(Length1,IndicesGood), subset(Length2,IndicesGood))
      else
      gen_empty_obj (GoodSticks)
      endif
      if (|IndicesBad| > 0)
      gen_rectangle2 (BadSticks, RowBad, ColumnBad, subset(Phi,IndicesBad), subset(Length1,IndicesBad), subset(Length2,IndicesBad))
      else
      gen_empty_obj (BadSticks)
      endif

    • 显示结果
      dev_display (Image)
      dev_set_color (‘white’)
      dev_set_line_width (1)
      dev_display (ValidSticks)
      dev_set_line_width (3)
      dev_set_color (‘yellow’)
      dev_display (StickAtBorder)
      dev_set_color (‘green’)
      dev_display (GoodSticks)
      dev_set_color (‘red’)
      dev_display (BadSticks)

    • ′.1f′这个是代表浮点数显示小数点后一位String:=′Targetlength:′+TargetLength'.1f'这个是代表浮点数显示小数点后一位 String := 'Target length: ' + TargetLength.1fString:=Targetlength:+TargetLength‘.1f’ + ’ cm’
      String[1] := ‘Tolerance: -’ + ToleranceLow′.1f′+′/+′+ToleranceHigh'.1f' + '/+' + ToleranceHigh.1f+/++ToleranceHigh’.1f’
      disp_message (WindowHandle, String, ‘window’, 12, 12, ‘black’, ‘true’)

    for J := 0 to |IndicesGood| - 1 by 1
    disp_message (WindowHandle, ‘OK’, ‘image’, 80, ColumnGood[J] - 10, ‘green’, ‘false’)
    disp_message (WindowHandle, FishLength1Good[J]′.1f′+′cm′,′image′,RowGood[J],ColumnGood[J]−28,′white′,′false′)endforforJ:=0to∣IndicesBad∣−1by1dispmessage(WindowHandle,′NotOK′,′image′,80,ColumnBad[J]−30,′red′,′false′)dispmessage(WindowHandle,FishLength1Bad[J]'.1f' + 'cm', 'image', RowGood[J], ColumnGood[J] - 28, 'white', 'false') endfor for J := 0 to |IndicesBad| - 1 by 1 disp_message (WindowHandle, 'Not OK', 'image', 80, ColumnBad[J] - 30, 'red', 'false') disp_message (WindowHandle, FishLength1Bad[J].1f+cm,image,RowGood[J],ColumnGood[J]28,white,false)endforforJ:=0toIndicesBad1by1dispmessage(WindowHandle,NotOK,image,80,ColumnBad[J]30,red,false)dispmessage(WindowHandle,FishLength1Bad[J]’.1f’ + ‘cm’, ‘image’, RowBad[J], ColumnBad[J] - 28, ‘white’, ‘false’)
    endfor
    if (I != NumImages)
    disp_continue_message (WindowHandle, ‘black’, ‘true’)
    stop ()
    endif
    endfor

  • 恢复系统设置
    set_system (‘store_empty_region’, StoreEmptyRegion)

处理思路

普通的形态学进行区域的分割与测量,这个例子给我最大的收获就是如何找到与图像边界重叠的区域,还有关于halcon下数组相关的操作,比如sgn、find、select_obj、subset等。

后记

大家有什么问题可以向我提问哈,我看到了第一时间回复,希望在学习的路上多多结交良师益友。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值