Halcon实例分析——check_blister.hdev

前言

例程运行结果如下

实例路径如下 

注释翻译如下:

*这个例子主要演示了医药行业的应用,主要是检测自动填充胶囊是否正确。第一张图片主要是作为参考模型,用于定位胶囊的位置。使用blob分析法去判断整个胶囊的状态。

 


一、代码详细分析

dev_close_window ()
dev_update_off ()
read_image (ImageOrig, 'blister/blister_reference')
dev_open_window_fit_image (ImageOrig, 0, 0, -1, -1, WindowHandle)
set_display_font (WindowHandle, 14, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)

参考前几篇文章文章,这里有个新的算子

dev_open_window_fit_image — Open a new graphics window that preserves the aspect ratio of the given image.

翻译如下:打开一个保持图片纵横比例不变的窗口

dev_open_window_fit_image(Image : : Row, Column, WidthLimit, HeightLimit : WindowHandle)

第一个参数是输入图片

第二参数是左上角的行坐标

第三个参数是左上角的列坐标

第四个参数宽度

第五个参数是高度

第六个参数是窗口句柄

 需要注意,官方描述如果width和height为空或者是负值,那么默认值就分别使用[500,800]和[400,600]

根据官方文档的描述是这样的

描述
This procedure opens a new graphics window with a given minimum and maximum extent such that it preserves the aspect ratio of the given image.

The position of the new graphics window is given by the parameters Row and Column, which define the position of the upper left corner of the graphics window.

The size of the new graphics window is determined such that the limits given in WidthLimit and HeightLimit are fulfilled and that the aspect ratio of the given image is preserved.

我大致翻译如下:

这个算子是用来打开一个不改变图片纵横比例的窗口,窗口的位置有Row和Column决定左上角的坐标,窗口的大小由WidthLimit和HeightLimit决定。

 access_channel (ImageOrig, Image1, 1)

我们加载的图片是三通道彩色图片,我之前也说过,对于检测来说,大部分时候都需要将彩色图片进行转化,进而对不同通道的图片进行处理。

这个算子主要是来访问多通道图片的某一个通道使用的。

后面的参数1就是第一个通道,大家可以设置成2或者3或者4看一下,4应该会报错,因为图片是三通道的

threshold (Image1, Region, 90, 255)
shape_trans (Region, Blister, 'convex')

提取整个产品,屏蔽背景干扰,需要注意的是之前都是转换成举行,这里是转换成多边形。因为药片的四个角是有倒角的,为了更精确的提取,可以使用多边形提取。

orientation_region (Blister, Phi)
area_center (Blister, Area1, Row, Column)
vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D)
affine_trans_image (ImageOrig, Image2, HomMat2D, 'constant', 'false')

这四段代码主要的目的是把所有的图片都放在一个基准上,无论图片什么角度,都转成0度

第一行代码获取当前角度

第二行代码获取坐标

第三行代码转换坐标矩阵

第四行代码转动当前图片

这四行代码使用的顺序组合基本都是这样 ,这和模板匹配异曲同工。

在一些场景中,如果没有什么特征点,使用这种方式比较好。

for I := 0 to 4 by 1
    Row := 88 + I * 70
    for J := 0 to 2 by 1
        Column := 163 + J * 150
        gen_rectangle2 (Rectangle, Row, Column, 0, 64, 30)
        concat_obj (Chambers, Rectangle, Chambers)
    endfor
endfor

这里使用一个for循环,来创建很多个长方形,圈出胶囊 位置,并且在创建的过程中把所有的区域放到新的数组里面

 ObjectsConcat = [Objects1,Objects2]

从官方文档可以得知concat_obj的功能,上面的公式很形象的为我们展示了算子功能

这里因为只是示例,所以矩形的坐标事先都是知道的,可以直接生成。在实际检测项目中,我们一般都是需要去画这些ROI,然后保存到本地,等检测产品的时候,直接调用本地ROI就可以了。

affine_trans_region (Blister, Blister, HomMat2D, 'nearest_neighbor')

之前只是把图片移动到固定的角度上,这里是把提取的区域移动到和图片一样的角度上

difference (Blister, Chambers, Pattern)

这里使用之前提取的整个矩形如下图,和上面我们生成的小矩形做差,得出新的一个矩形,但是后面又没有用到这个Pattern ,所以这一段在这个实例中,确实我没有发现有什么意义

第一次阈值得到的矩形

 生成的15个小矩形

 做差得出下图模板矩形,但是后面我没有发现用到这个模板矩形

 union1 (Chambers, ChambersUnion)

之前生成的15个小矩形每个是单独的个体,使用union1可以连接成一个整体,后面使用这个整体去提取胶囊部分,所以我个人认为这个才是模板ROI

 orientation_region (Blister, PhiRef)
PhiRef := rad(180) + PhiRef
area_center (Blister, Area2, RowRef, ColumnRef)

除了第二段代码我觉的有意义,第一行和第三行确实重复了上面的操作

orientation_region (Blister, Phi)
area_center (Blister, Area1, Row, Column)
vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D)
affine_trans_image (ImageOrig, Image2, HomMat2D, 'constant', 'false')

上面已经有代码获取Blister的坐标和角度了,所以这个例程确实几段代码有点多余,重复使用没有问题,只是冗余而已

到这里,准备工作基本完成,下面的代码就是真是的检测部分执行的代码。我么在做缺陷检测的时候,上面这些代码其实就是我们在设置界面完成的工作,提起ROI,设置检测参数。

当正式检测的时候,我们就执行下面的代码了。

首先一个for循环,基本很多例子都会有for循环,目的是为了模拟相机连续采集图片

    read_image (Image, 'blister/blister_' + Index$'02')
    threshold (Image, Region, 90, 255)
    connection (Region, ConnectedRegions)
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 5000, 9999999)
    shape_trans (SelectedRegions, RegionTrans, 'convex')

    orientation_region (RegionTrans, Phi)
    area_center (RegionTrans, Area3, Row, Column)
    vector_angle_to_rigid (Row, Column, Phi, RowRef, ColumnRef, PhiRef, HomMat2D)
    affine_trans_image (Image, ImageAffineTrans, HomMat2D, 'constant', 'false')

这里和之前的代码一样,首先提取产品,然后获取坐标和角度,使用之前生成的矩阵把图片统一移动到一个标准点上。

    reduce_domain (ImageAffineTrans, ChambersUnion, ImageReduced)
    decompose3 (ImageReduced, ImageR, ImageG, ImageB)

使用之前的模板剪切图片

得到如下图示,所以我之前说模板应该是15个小矩形 

 

 decompose3 (ImageReduced, ImageR, ImageG, ImageB)

把三通道图片转换成RGB单独的三个通道

R通道图片 

G通道图片

 B通道图片

 具体使用哪个通道的图片,需要我们查看具体检测的缺陷在哪个通道能最容易体现,就是用哪个通道的图片

 var_threshold (ImageB, Region, 7, 7, 0.2, 2, 'dark')

阈值提取,这个算子我有个专栏专门讲解的,和其他阈值算子做了比较,大家可以看那个专栏的解读,篇幅较长,这里就不说了

    connection (Region, ConnectedRegions0)
    closing_rectangle1 (ConnectedRegions0, ConnectedRegions, 3, 3)
    fill_up (ConnectedRegions, RegionFillUp)
    select_shape (RegionFillUp, SelectedRegions, 'area', 'and', 1000, 99999)
    opening_circle (SelectedRegions, RegionOpening, 4.5)
    connection (RegionOpening, ConnectedRegions)
    select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1000, 99999)
    shape_trans (SelectedRegions, Pills, 'convex')

这里的一系列算子都是之前说过的,主要目的就是从下图中提取我们需要的胶囊外轮廓

 处理后,提取的清晰轮廓,这样后面我们做运算的时候会没有干扰,

 

  count_obj (Chambers, Number)
    gen_empty_obj (WrongPill)
    gen_empty_obj (MissingPill)
    for I := 1 to Number by 1
        select_obj (Chambers, Chamber, I)
        intersection (Chamber, Pills, Pill)
        area_center (Pill, Area, Row1, Column1)
        if (Area > 0)
            min_max_gray (Pill, ImageB, 0, Min, Max, Range)
            if (Area < 3800 or Min < 60)
                concat_obj (WrongPill, Pill, WrongPill)
            endif
        else
            concat_obj (MissingPill, Chamber, MissingPill)
        endif
    endfor

 这里最主要的算子就是intersection,找交集,然后紧跟一个if判断,

  select_obj (Chambers, Chamber, I)

 

注意这里是不是整体去做交集,而是15个胶囊一个一个去做交集运算,Chambers是集合,从集合中一个一个的取出Chamber去和上面提取的Pills做交集

Chambers如下

 

Chamber

Pills

 做交集如下

 我们先不看判断代码,首先我们设想一下,上面做交集的结果

1.如果没有胶囊,那么交集的结果肯定为空,也就是面积为0

2.如果胶囊不完整,那么交集的结果是面积肯定会很小。

3.如果胶囊完整,那么交集后,就是胶囊的轮廓,面积很大。

带着上面的假设我们再看下面的判断

    if (Area > 0)
            min_max_gray (Pill, ImageB, 0, Min, Max, Range)
            if (Area < 3800 or Min < 60)
                concat_obj (WrongPill, Pill, WrongPill)
            endif
        else
            concat_obj (MissingPill, Chamber, MissingPill)
        endif

 第一给if判断就是判断面积,符合我们假设的第一条

if语句内部判断的就是胶囊不完整的情况

这里例程添加了一个判断灰度值的算子,从例程中可以看出,当交集后的结果面积小于3800或者最小灰度值小于60时,那么胶囊就是不完整。

当然这是我考虑,后来全部看完后,我发现,使用灰度值判断的是混料

混料的的时候,虽然胶囊完整,但是灰度值不一样


总结

例程只是例程,给我们提供思路和帮助我们理解算子的,所以不要深度解读他的合理性和严谨性,看例程不是做项目,一个视觉检测项目,我们需要很多个例程提供的算子共同才能解决

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无锡伶俐科技

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值