Halcon的Blob分析

一、Blob分析流程及常用算子

1.基本步骤

Blob分析的基本步骤,这是一种理想状态,也是最基本的套路,获取图像->分割图像(区分前景像素和背景像素)->特征提取(比如面积、重心、旋转角度等)。

halcon代码实现如下:
read_image(Image,‘particle’)
threshold(Image, BrightPixels,120,255)//阈值分割算子
connection(BrightPixels,Particles)//断开联通区域
area_center(Particles,Area,Row,Column)

实际上,提取Blob之前和分析Blob之后也存在重要的步骤。比如,提取Blob之前一般要对图像进行预处理,比如图像的变换和校正、平滑与去噪、以及增强处理;分析Blob之后需要将Blob进行选取,或者将Blob重心的像素值向物理坐标系坐标值的转化。因此,Blob实现方法需要具体情况具体分析。就拿阈值分割提取Blob而言,是用固定阈值还是动态阈值,这都是根据图片情况进行具体分析的。

2.完整的Blob分析步骤

在实际应用中,Blob 的分割会很复杂,需要处理更多步骤。 其原因有多种,比如杂乱或不均匀的照明、图像中有很多杂斑(很难提取目标位)。 此外,对Blob进行后处理以获取客户需要的直观显示数据,例如将特征转换为真实世界单位或结果可视化。

整个过程为:获取图像->应用ROI->定位ROI->矫正图像->图像预处理->动态获取分割参数->分割图像->处理区域->特征提取->将像素坐标转换到世界坐标->结果显示或者输出。

* ball.hdev: Inspection of Ball Bonding
* 
dev_update_window ('off')
dev_close_window ()
dev_open_window (0, 0, 728, 512, 'black', WindowID)
read_image (Bond, 'die/die_03')
dev_display (Bond)
set_display_font (WindowID, 14, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()

*灰度处理 二值化
threshold (Bond, Bright, 100, 255)
*形态学处理,一般用于定位,形状转换,rectangle2带方向的矩形
shape_trans (Bright, Die, 'rectangle2')
dev_set_color ('green')
dev_set_line_width (3)
dev_set_draw ('margin')
dev_display (Die)
disp_continue_message (WindowID, 'black', 'true')
stop ()
*区域锁定
reduce_domain (Bond, Die, DieGrey)

*再次二值化
threshold (DieGrey, Wires, 0, 50)
*用给定的形状特征填充区域:面积为1~100的区域
fill_up_shape (Wires, WiresFilled, 'area', 1, 100)
dev_display (Bond)
dev_set_draw ('fill')
dev_set_color ('red')
dev_display (WiresFilled)
disp_continue_message (WindowID, 'black', 'true')
stop ()

*形态学处理:此处为开运算/(也可以用腐蚀),减少像素,circle–对圆形作用最大
*形态学 腐蚀
*erosion_circle (WiresFilled, RegionErosion, 15.5)
*形态学 膨胀
*dilation_circle (RegionErosion, RegionDilation, 15.5)
*形态学 开运算(效果同上 先腐蚀后膨胀)
opening_circle (WiresFilled, Balls, 15.5)
dev_set_color ('green')
dev_display (Balls)
disp_continue_message (WindowID, 'black', 'true')
stop ()
*将二值化分开的区域划分为不同的连通区域,断成不同的区域,方便后面作特征值提取处理
connection (Balls, SingleBalls)

*特征值提取
*根据圆度提取区域
* select_shape (SingleBalls, IntermediateBalls, 'circularity', 'and', 0.85, 1.0)
*根据面积提取区域
select_shape (SingleBalls, IntermediateBalls, 'area', 'and', 800, 1200)
*按照坐标进行排序
sort_region (IntermediateBalls, FinalBalls, 'first_point', 'true', 'column')
dev_display (Bond)
dev_set_colored (12)
dev_display (FinalBalls)
disp_continue_message (WindowID, 'black', 'true')
stop ()

*计算最小外接圆半径
smallest_circle (FinalBalls, Row, Column, Radius)
NumBalls := |Radius|
Diameter := 2 * Radius
meanDiameter := mean(Diameter)
minDiameter := min(Diameter)
dev_display (Bond)
disp_circle (WindowID, Row, Column, Radius)
dev_set_color ('white')
disp_message (WindowID, 'D: ' + Diameter$'.4', 'image', Row - 2 * Radius, Column, 'white', 'false')
dev_update_window ('on')

 

3.常见特征提取

1)、区域特征:
a:面积area;
b:力矩Moments;
c:平行于主轴的最小矩形smallest_rectangle1;
d:任意方向的最小矩形smallest_rectangle2;
e:最小圆形smallest_circle;
f:凸包面积convexity;
g:contlength区域边界长度;
h:圆形roundness;
j:圆度circularity;
k:紧密度compactness;
l:矩形度rectangularity;
2)、灰度特征
a:简单灰度值特征:区域的平均灰度值;
b:区域的最小和最大灰度值;

4.开运算和闭运算(形态学)

图像分割时,会用到开运算和闭运算,采用不同的分割策略,效果会不一样,这里仅先介绍下概念。
1)、开运算 先腐蚀后膨胀;
2)、闭运算 先膨胀后腐蚀;
3)、腐蚀;
4)、膨胀。
开运算和闭运算要用到的算子如下:
1)、开运算 opening(ConnectedRegions, ConnectedRegions, RegionOpening1)
2)、闭运算 closing(RegionOpening1, RegionOpening1, RegionClosing1)
3)、腐蚀 erosion1(RegionClosing1, RegionClosing1, RegionErosion1, 1)
4)、膨胀 dilation1(RegionErosion1, RegionErosion1, RegionDilation1, 1)
5)、圆形结构开运算 opening_circle(ConnectedRegions, RegionOpening, 3.5)
6)、圆形结构闭运算 closing_circle(RegionOpening, RegionClosing, 3.5)
7)、圆形结构腐蚀 erosion_circle(RegionClosing, RegionErosion, 3.5)
8)、圆形结构膨胀 dilation_circle(RegionErosion, RegionDilation, 3.5)

5.功能特征的取值:

求Region指定特征值:region_features(Regions : : Features : Value)

根据特征值选择区域:select_shape(Regions : SelectedRegions : Features, Operation, Min, Max : )

特征 备注
area Area of the object 对象的面积  
row Row index of the center 中心点的行坐标  
column Column index of the center 中心点的列坐标  
width Width of the region 区域的宽度  
height Height of the region 区域的高度  
row1 Row index of upper left corner 左上角行坐标  
column1 Column index of upper left corner 左上角列坐标  
row2 Row index of lower right corner 右下角行坐标  
column2 Column index of lower right corner 右下角列坐标  
circularity Circularity 圆度 0~1
compactness Compactness 紧密度 0~1
contlength Total length of contour 轮廓线总长  
convexity Convexity 凸性  
rectangularity Rectangularity 矩形度 0~1
ra Main radius of the equivalent ellipse 等效椭圆长轴半径长度  
rb Secondary radius of the equivalent ellipse 等效椭圆短轴半径长度  
phi Orientation of the equivalent ellipse 等效椭圆方向  
anisometry Anisometry 椭圆参数,Ra/Rb长轴与短轴的比值  
bulkiness Bulkiness 椭圆参数,蓬松度π*Ra*Rb/A  
struct_factor Structur Factor 椭圆参数,Anisometry*Bulkiness-1  
outer_radius Radius of smallest surrounding circle 最小外接圆半径  
inner_radius Radius of largest inner circle 最大内接圆半径  
inner_width Width of the largest axis-parallel rectangle that fits into the region 最大内接矩形宽度  
inner_height Height of the largest axis-parallel rectangle that fits into the region 最大内接矩形高度  
dist_mean Mean distance from the region border to the center 区域边界到中心的平均距离  
dist_deviation Deviation of the distance from the region border from the center 区域边界到中心距离的偏差  
roundness Roundness 圆度,与circularity计算方法不同  
num_sides Number of polygon sides 多边形边数  
connect_num Number of connection components 连通数  
holes_num Number of holes 区域内洞数  
area_holes Area of the holes of the object 所有洞的面积  
max_diameter Maximum diameter of the region 最大直径  
orientation Orientation of the region 区域方向  
euler_number Euler number 欧拉数,即连通数和洞数的差  
rect2_phi Orientation of the smallest surrounding rectangle 最小外接矩形的方向  
rect2_len1 Half the length of the smallest surrounding rectangle 最小外接矩形长度的一半 smallest_rectangle2
rect2_len2 Half the width of the smallest surrounding rectangle 最小外接矩形宽度的一半  
moments_m11 Geometric moments of the region 几何矩  
moments_m20 Geometric moments of the region 几何矩  
moments_m02 Geometric moments of the region 几何矩  
moments_ia Geometric moments of the region 几何矩  
moments_ib Geometric moments of the region 几何矩  
moments_m11_invar Geometric moments of the region 几何矩  
moments_m20_invar Geometric moments of the region 几何矩  
moments_m02_invar Geometric moments of the region 几何矩  
moments_phi1 Geometric moments of the region 几何矩  
moments_phi2 Geometric moments of the region 几何矩  
moments_m21 Geometric moments of the region 几何矩  
moments_m12 Geometric moments of the region 几何矩  
moments_m03 Geometric moments of the region 几何矩  
moments_m30 Geometric moments of the region 几何矩  
moments_m21_invar Geometric moments of the region 几何矩  
moments_m12_invar Geometric moments of the region 几何矩  
moments_m03_invar Geometric moments of the region 几何矩  
moments_m30_invar Geometric moments of the region 几何矩  
moments_i1 Geometric moments of the region 几何矩  
moments_i2 Geometric moments of the region 几何矩  
moments_i3 Geometric moments of the region 几何矩  
moments_i4 Geometric moments of the region 几何矩  
moments_psi1 Geometric moments of the region 几何矩  
moments_psi2 Geometric moments of the region 几何矩  
moments_psi3 Geometric moments of the region 几何矩  
moments_psi4 Geometric moments of the region 几何矩

二、Blob分析案例

1.豆子分割统计(形态学案例)

* 采集图像操作
dev_update_off ()
read_image (Image, 'pellets')
dev_close_window ()
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowID)
dev_set_part (0, 0, Height - 1, Width - 1)
set_display_font (WindowID, 16, 'mono', 'true', 'false')
dev_set_colored (6)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_display (Image)
disp_message (WindowID, 'Detect each single pellet', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID, 'black', 'true')
stop ()

 

* 从背景分割颗粒的区域
* 二进制阈值分割 对dark(暗色) light(亮色)
binary_threshold (Image, LightRegion, 'max_separability', 'light', UsedThreshold)
opening_circle (LightRegion, Region, 2.5)
dev_display (Region)
disp_message (WindowID, 'First, segment the pellets', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID, 'black', 'true')
stop ()

 

* 第一次分割出颗粒区域,只是分割处理而已不能进行统计
connection (Region, ConnectedRegionsWrong)
dev_display (Image)
dev_display (ConnectedRegionsWrong)
disp_message (WindowID, 'Simple connection fails', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID, 'black', 'true')
stop ()

* 通过腐蚀的方式来分割出每个区域
erosion_circle (Region, RegionErosion, 7.5)
*自定义形状腐蚀
* shape_trans (RegionErosion, RegionTrans, 'convex')
* gen_rectangle1 (Rectangle, 1, 1, 20, 20)
* gen_circle (Circle, 10, 10, 10)
* erosion1 (Region, Circle, RegionErosion1, 1)
dev_display (Image)
dev_display (RegionErosion)
disp_message (WindowID, 'Erosion of the pellet regions', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID, 'black', 'true')
stop ()

* 在次分割连通区域
connection (RegionErosion, ConnectedRegions)
dev_display (Image)
dev_display (ConnectedRegions)
disp_message (WindowID, 'Perform connection now', 'window', 12, 12, 'black', 'true')
disp_continue_message (WindowID, 'black', 'true')
stop ()

* 通过应用膨胀使其恢复到原始颗粒大小
dilation_circle (ConnectedRegions, RegionDilation, 7.5)
area_center (RegionDilation, Area, Row, Column)

* 统计颗粒数量
count_obj (RegionDilation, Number)
dev_display (Image)
dev_display (RegionDilation)
disp_message (WindowID, Number + ' pellets detected', 'window', 12, 12, 'black', 'true')
dev_set_color ('cyan')
disp_cross (WindowID, Row, Column, 16, rad(60))

 

2.车牌的字符分割(数字与字母)

***** 读取图片
dev_close_window ()
read_image (Image, '../chepai18.jpg')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)

 

***** 处理图片-定位车牌
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, Region, 80, 100)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 8870.97, 10000)

 

***** 处理图片- 转正图片
shape_trans (SelectedRegions, RegionTrans, 'rectangle2')
** 求出中心位置
area_center (RegionTrans, Area, Row, Column)
** 获取当前矩形的倾斜度
orientation_region (RegionTrans, Phi)
** 构建一个旋转的仿射变换矩阵
vector_angle_to_rigid (Row, Column, Phi, Row, Column, rad(0), HomMat2D)
hom_mat2d_slant (HomMat2D, rad(15), 'x', Column, Row, HomMat2DSlant)
affine_trans_region (RegionTrans, RegionAffineTrans, HomMat2DSlant, 'nearest_neighbor')
affine_trans_image (Image, ImageAffineTrans, HomMat2DSlant, 'constant', 'false')
reduce_domain (ImageAffineTrans, RegionAffineTrans, ImageReduced)

 

*************** 开始识别之车牌图片预处理
rgb1_to_gray (ImageReduced, GrayImage1)
threshold (GrayImage1, Region1, 128, 255)
erosion_rectangle1 (Region1, RegionErosion, 3, 3)
opening_rectangle1 (RegionErosion, RegionOpening, 1, 3)
connection (RegionOpening, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 200, 500)
sort_region (SelectedRegions1, SortedRegions, 'character', 'true', 'column')

 

3.车牌字符分割带中文(中文、数字、字母)

***** 读取图片
dev_close_window ()
read_image (Image, '素材/chepai18.jpg')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
dev_display (Image)
***** 处理图片-定位车牌
rgb1_to_gray (Image, GrayImage)
threshold (GrayImage, Region, 80, 100)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 8870.97, 10000)
***** 处理图片- 转正图片
shape_trans (SelectedRegions, RegionTrans, 'rectangle2')
area_center (RegionTrans, Area, Row, Column)
orientation_region (RegionTrans, Phi)
vector_angle_to_rigid (Row, Column, Phi, Row, Column, rad(0), HomMat2D)
hom_mat2d_slant (HomMat2D, rad(15), 'x', Column, Row, HomMat2DSlant)
affine_trans_region (RegionTrans, RegionAffineTrans, HomMat2DSlant, 'nearest_neighbor')
affine_trans_image (Image, ImageAffineTrans, HomMat2DSlant, 'constant', 'false')
reduce_domain (ImageAffineTrans, RegionAffineTrans, ImageReduced)
*************** 开始识别之车牌图片预处理,带中文字符分割
rgb1_to_gray (ImageReduced, GrayImage1)
threshold (GrayImage1, Regions, 176, 242)
closing_circle (Regions, RegionClosing, 3.5)
opening_circle (Regions, RegionOpening, 1.7)
connection (RegionOpening, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 20, 600)
sort_region (SelectedRegions1, SortedRegions, 'character', 'true', 'column')
*************** 组装苏字区域
select_obj (SortedRegions, ObjectSelected1, 1)
select_obj (SortedRegions, ObjectSelected2, 2)
select_obj (SortedRegions, ObjectSelected3, 3)
union2 (ObjectSelected1, ObjectSelected2, RegionUnion)
union2 (RegionUnion, ObjectSelected3, RegionUnion1)
select_obj (SortedRegions, ObjectSelected4, 4)
select_obj (SortedRegions, ObjectSelected5, 5)
select_obj (SortedRegions, ObjectSelected6, 6)
select_obj (SortedRegions, ObjectSelected7, 7)
select_obj (SortedRegions, ObjectSelected8, 8)
select_obj (SortedRegions, ObjectSelected9, 9)
***************** 把所有区域组成一个对象
gen_empty_obj (NumberObject)
concat_obj (NumberObject, RegionUnion1, NumberObject)
concat_obj (NumberObject, ObjectSelected4, NumberObject)
concat_obj (NumberObject, ObjectSelected5, NumberObject)
concat_obj (NumberObject, ObjectSelected6, NumberObject)
concat_obj (NumberObject, ObjectSelected7, NumberObject)
concat_obj (NumberObject, ObjectSelected8, NumberObject)
concat_obj (NumberObject, ObjectSelected9, NumberObject)
**************** 创建训练文件
TrainFile:='./Charactor.trf'
Words:=['苏','E','C','6','2','N','8']
** 完成图像与字符训练对应关系
write_ocr_trainf (NumberObject, GrayImage1, Words, TrainFile)
** 读取训练文件
read_ocr_trainf_names (TrainFile, CharacterNames, CharacterCount)
** 创建一个分类识别器
create_ocr_class_mlp (8, 10, 'constant', 'default', CharacterNames, 80, 'none', 10, 42, OCRHandle)
** 训练分类识别器
trainf_ocr_class_mlp (OCRHandle, TrainFile, 200, 1, 0.01, Error, ErrorLog)
** 保存分类识别文件
write_ocr_class_mlp (OCRHandle, './Charactor.omc')
*********************** 基于训练omc文件开始识别带中文车牌**************
read_ocr_class_mlp ('./Charactor.omc', OCRHandle1)
do_ocr_multi_class_mlp (NumberObject, GrayImage1, OCRHandle1, Class, Confidence)
dev_clear_window ()
dev_display (Image)
dev_set_color ('red')
set_display_font (WindowHandle, 30, 'mono', 'true', 'false')
for Index := 0 to |Class|-1 by 1
    set_tposition (WindowHandle,30, 120+36*Index)
    write_string (WindowHandle, Class[Index])
endfor

4.统计每个骰子的点数(距离变换+分水岭)

dev_close_window ()
dev_open_window (0, 0, 500, 500, 'black', WindowHandle)
set_display_font (WindowHandle, 30, 'mono', 'true', 'false')
list_files ('素材/dice/', ['files','follow_links'], ImageFiles)
tuple_regexp_select (ImageFiles, ['\\.(tif|tiff|gif|bmp|jpg|jpeg|jp2|png|pcx|pgm|ppm|pbm|xwd|ima|hobj)$','ignore_case'], ImageFiles)
ResultIndex:=1
for Index := 0 to |ImageFiles| - 1 by 1
    read_image (Image, ImageFiles[Index])
    get_image_size (Image, Width, Height)
    threshold (Image, Regions, 180, 255)

    *区域填充(把区域中孔洞进行填充)
    fill_up (Regions, RegionFillUp)

    *区域砍断
    connection (RegionFillUp, ConnectedRegions)
    *距离变换(水平垂直距离)越靠近边缘越暗
    distance_transform (ConnectedRegions, DistanceImage, 'octagonal', 'true', 1000, 1000)
    ** convert_image_type算子转化为BYTE类型时真实值小于零的值直接置0,而大于0的值则保持不变。
    convert_image_type (DistanceImage, ImageConverted, 'byte')

    *图像灰度反转
    invert_image (ImageConverted, ImageInvert)
    *灰度值缩放(扩大暗色区域)
    scale_image_max (ImageInvert, ImageScaleMax)
    *分水岭分割
    watersheds_threshold (ImageScaleMax, Basins, 10)
    intersection (Basins, ConnectedRegions, RegionIntersection)

    select_shape (RegionIntersection, SelectedRegions, 'area', 'and', 30000, 100000)
    count_obj (SelectedRegions, Number)
    dev_display (Image)
    for Index1 := 1 to Number by 1
        select_obj (SelectedRegions, ObjectSelected, Index1)
        reduce_domain (Image, ObjectSelected, ImageReduced)
        threshold (ImageReduced, Regions1, 0, 150)
        fill_up (Regions1, RegionFillUp1)
        connection (RegionFillUp1, ConnectedRegions1)
        select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 200, 20000)
        count_obj (SelectedRegions1, Number1)
        area_center (ObjectSelected, Area, Row, Column)
        disp_message (WindowHandle, Number1, 'image', Row, Column, 'green', 'false')
         
    endfor
    stop()
endfor

距离变换算法

计算区域每个点到区域边缘的距离变换,并将距离信息赋值到图像中。

distance_transform(Region : DistanceImage : Metric, Foreground, Width, Height : )

Region:输入参数,目标区域。

DistanceImage:输出参数,距离图像。

Metric:输入参数,用于测量距离的方法。默认 ‘city-block’

‘chamfer-3-4’,沿每个点到边缘的平行和垂直移动的权重为3,对角线移动的权重为4的方向计算最近距离。

‘chamfer-3-4-unnormalized’,同上,抑制归一化,可以减少运算量。

‘chessboard’,沿每个点到边缘的垂直、平行和对角的方向计算最近距离。

‘city-block’,沿每个点到边缘的垂直和平行的方向计算最近距离。

‘euclidean’,沿每个点到边缘的欧几里得距离。

‘octagonal’,沿每个点到边缘的垂直、平行和对角线(权值更高)的方向计算最近距离。

Foreground:输入参数,计算方式设置。默认 ‘true’ 【‘false’在区域外所有的点到区域的边缘, ‘true’计算区域内所有的点到区域边缘的距离】

Width:输入参数,输入的计算距离的范围宽度。1 ≤ Width

Height:输入参数,输入的计算距离的范围高度。1 ≤ Height

这里的Width,Height一般情况是等于图片的分辨率大小,但是范围值也可以设定为:要计算的区域包含在设定的分辨率内。

watersheds_threshold

分水岭,就是在峡谷最低哇处开口注水,然后地形地貌高耸的地方就会形成大坝,或者说是一条条脊。

 

posted @ 2024-07-22 16:09  ZHIZRL  阅读(473)  评论(0编辑  收藏  举报