HALCON check_blister.hdev药品胶囊检测
示例程序源码(加注释)
-
显示、读入图片、设置显示字体等,之前的帖子已经介绍过了
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) -
第一步,我们创建一个图案,以便在后续的水泡图像中轻松切出腔室。
-
access_channel - 访问多通道图像中的指定的一个通道。这里选取Image1的第一个通道
access_channel (ImageOrig, Image1, 1) -
进行阈值分割,选取灰度值在90-255的区域
threshold (Image1, Region, 90, 255) -
使用shape_trans对区域Region处理,提取Region的外框,convex功能是外框
shape_trans (Region, Blister, ‘convex’) -
orientation_region计算区域的方向,这个算子是基于elliptic_axis 算子来的,elliptic_axis 是求取等效的椭圆,所以用算子orientation_region相当于把区域Blister转化为一个等效椭圆,计算这个椭圆的长轴在图像中的角度。
orientation_region (Blister, Phi) -
求取区域Blister的面积与中心坐标。
area_center (Blister, Area1, Row, Column) -
vector_angle_to_rigid - 根据初始坐标(前3个参数)与仿射变换后的坐标与角度(4-6,三个参数)角度生成一个旋转与平移的仿射变换矩阵HomMat2D。这里初始坐标与结束坐标都没有变化只是角度旋转到了0度。
vector_angle_to_rigid (Row, Column, Phi, Row, Column, 0, HomMat2D) -
affine_trans_image - 对图像进行任意的2D仿射变换。ImageOrig:要进行仿射变换的图像;Image2:仿射变换之后的图像;HomMat2D:2D仿射变换矩阵;constant:进行仿射变换的方式,这个代表使用均值滤波器来防止混叠效应的发生。false:仿射变换后的图片超出现有图片大小的区域不被剪切掉;若为true则相反。
affine_trans_image (ImageOrig, Image2, HomMat2D, ‘constant’, ‘false’) -
生成一个空的对象Chambers
gen_empty_obj (Chambers)for I := 0 to 4 by 1Row := 88 + I * 70for J := 0 to 2 by 1Column := 163 + J * 150* * 生成一个可旋转的矩形;* 前两个参数是区域中心坐标,第三个参数是矩形角度,后两个参数是矩形的宽高。gen_rectangle2 (Rectangle, Row, Column, 0, 64, 30)* * concat_obj - 把两个对象融合在一起。* 注意,这个和union不一样,union是把两个对象整合成一个对象,整合后对象的元素个数为1;* 而使用concat_obj 是把几个对象联合成一个对象,这个对象中的元素个数之和不变。concat_obj (Chambers, Rectangle, Chambers)endforendfor
-
使用变换矩阵HomMat2D对Blister区域使用nearest_neighbor方法进行仿射变换。
affine_trans_region (Blister, Blister, HomMat2D, ‘nearest_neighbor’) -
求取区域Blister与区域Chambers的差集
difference (Blister, Chambers, Pattern) -
将区域Chambers(有多个元素)联合成一个区域(一个元素)
union1 (Chambers, ChambersUnion) -
求取区域Blister的角度
orientation_region (Blister, PhiRef) -
将角度PhiRef加180度
PhiRef := rad(180) + PhiRef -
求取区域Blister的面积与中心坐标
area_center (Blister, Area2, RowRef, ColumnRef) -
循环检测每一张图片
-
定义变量Count 赋值6
Count := 6 -
for循环
for Index := 1 to Count by 1-
读入图片
read_image (Image, ‘blister/blister_’ + Index$‘02’) -
对图片Image进行阈值分割,提取像素灰度值在90-255的区域
threshold (Image, Region, 90, 255) -
分割连通域
connection (Region, ConnectedRegions) -
使用select_shape 对区域ConnectedRegions进行筛选,筛选出面积值介于5000-999999的区域
select_shape (ConnectedRegions, SelectedRegions, ‘area’, ‘and’, 5000, 9999999) -
求取区域SelectedRegions的外形
shape_trans (SelectedRegions, RegionTrans, ‘convex’) -
求取区域RegionTrans的角度
orientation_region (RegionTrans, Phi) -
求取区域RegionTrans的面积与中心坐标
area_center (RegionTrans, Area3, Row, Column) -
生成仿射变换矩阵HomMat2D
vector_angle_to_rigid (Row, Column, Phi, RowRef, ColumnRef, PhiRef, HomMat2D) -
使用HomMat2D矩阵对Image进行仿射变换
affine_trans_image (Image, ImageAffinTrans, HomMat2D, ‘constant’, ‘false’) -
使用区域剪切图片,缩小图像处理定义域
reduce_domain (ImageAffinTrans, ChambersUnion, ImageReduced) -
将图片ImageReduced分成R/G/B三通道图像
decompose3 (ImageReduced, ImageR, ImageG, ImageB) -
var_threshold - 通过局部均值和标准差分析对图像进行阈值处理。
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’) -
对区域Chambers进行计数
count_obj (Chambers, Number) -
生成一个空的对象
gen_empty_obj (WrongPill) -
生成一个空的对象
gen_empty_obj (MissingPill) -
for循环
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 - 在对象数组中选取指定对象,之前例子已经讲过了
-
下面的就是显示了
dev_clear_window ()
dev_display (ImageAffinTrans)
dev_set_color (‘forest green’)
count_obj (Pills, NumberP)
count_obj (WrongPill, NumberWP)
count_obj (MissingPill, NumberMP)
dev_display (Pills)
if (NumberMP > 0 or NumberWP > 0)
disp_message (WindowHandle, ‘Not OK’, ‘window’, 10, 10 + 600, ‘red’, ‘true’)
else
disp_message (WindowHandle, ‘OK’, ‘window’, 10, 10 + 600, ‘forest green’, ‘true’)
endif
disp_message (WindowHandle, '# correct pills: ’ + (NumberP - NumberWP), ‘window’, 10, 10, ‘black’, ‘true’)
disp_message (WindowHandle, '# wrong pills : ’ + NumberWP, ‘window’, 10 + 25, 10, ‘black’, ‘true’)
if (NumberWP > 0)
disp_message (WindowHandle, NumberWP, ‘window’, 10 + 25, 10 + 180, ‘red’, ‘true’)
endif
disp_message (WindowHandle, '# missing pills: ’ + NumberMP, ‘window’, 10 + 50, 10, ‘black’, ‘true’)
if (NumberMP > 0)
disp_message (WindowHandle, NumberMP, ‘window’, 10 + 50, 10 + 180, ‘red’, ‘true’)
endif
dev_set_color (‘red’)
dev_display (WrongPill)
dev_display (MissingPill)
if (Index < Count)
disp_continue_message (WindowHandle, ‘black’, ‘true’)
endif
stop ()
endfor
-
处理思路
在这个例子是药品行业胶囊的检测,是比较经典的例子,我们下一篇文章介绍另一个胶囊检测例子。这个胶囊检测首先用到了仿射变换,把每个胶囊的单元提取出来,然后使用最简单的blob分析对缺陷进行提取。
后记
大家有什么问题可以向我提问哈,我看到了第一时间回复,希望在学习的路上多多结交良师益友。