halcon中是怎么实现半导体/Led中的GoldenDie的检测方法的 基于局部可变形模板匹配 variation_model模型
原文作者:aircraft
原文地址:https://www.cnblogs.com/DOMLX/p/18739196
这篇简单介绍一下halcon中的print_check_single_chars.hdev 实例 Perform a typical print quality inspection using variation models for each character也就是打印字母质量的瑕疵检测。
这个实例中运用到的variation_model模型来检测就是半导体/Led中的GoldenDie(构阵带?)的检测方法,通过建立标准晶圆(Die)图形模板,然后实际生产中每颗晶圆(Die)就与标准图形模板比对
得到的差异图形,在对差异图形进行分析(面积,灰度等等)来判断每颗晶圆(Die)的NG、OK。如果你将本篇实例掌握理解了,那么就可以把这个检测方法应用到半导体/Led晶圆检测当中去了。
一.主要算子详解
最重要的算子只有几个
1.create_variation_model( : : Width, Height, Type, Mode : ModelID)
2.train_variation_model(Images : : ModelID : )
3.prepare_variation_model( : : ModelID, AbsThreshold, VarThreshold : )
4.clear_train_data_variation_model( : : ModelID : )
5.compare_variation_model(Image : Region : ModelID : )
6.clear_variation_model( : : ModelID : )
总结起来顺序就是:创建模型,训练模型,给模型设置参数,释放训练参数,输入图像比较模型得到结果,清除释放模型资源。接下来一个个了解一下模型参数。
1.create_variation_model( : : Width, Height, Type, Mode : ModelID)详解:
参数详解
1. Width & Height
- 作用:定义变异模型的参考区域尺寸(即字符在训练图像中对齐后的目标尺寸)。
- 关键点:
- 必须与训练图像裁剪后的尺寸一致。例如,若字符在基准图像中被裁剪为
100×50
像素,则Width=100
,Height=50
。 - 直接影响模型对齐精度:若实际字符尺寸与
Width/Height
不匹配,会导致仿射变换误差。
- 必须与训练图像裁剪后的尺寸一致。例如,若字符在基准图像中被裁剪为
2. Type
- 数据类型选项:
'byte'
(默认值): 8-bit无符号整数,适用于亮度值范围在[0,255]
的图像。'uint2'
: 16-bit无符号整数,支持更高动态范围(如HDR图像)。'float'
: 浮点数,用于需要高精度计算的场景。
- 选择依据:
- 若图像经过归一化(如
[0,1]
),需选择'float'
。 - 若使用
prepare_variation_model
时设置了VarThreshold
,建议用'uint2'
以避免数值溢出。
- 若图像经过归一化(如
3. Mode
有三个参数可选:
模式 说明 适用场景 'standard' 默认模式,基于像素值的方差计算变异模型。 常规场景(字符对比度高、噪声较少) 'robust' 使用鲁棒统计(如中位数)替代方差,减少异常值影响。 训练图像含噪声或离群点 'direct' 跳过方差计算,直接使用原始像素值训练模型。 需要最大保留原始像素信息
关键区别
'standard' vs 'robust':
- 'standard':对像素值的分布敏感,易受高对比度噪声干扰。
- 'robust':通过中位数等稳健统计量,对噪声更鲁棒(适合工业检测场景)。
'direct':
- 不进行任何统计预处理,直接将像素值作为特征输入模型。
- 可能导致模型过拟合原始图像噪声,但保留更多细节。
这里我们一般使用前面两个参数,均值或者中值,均值的计算都是每个图像同位置的灰度数据集来统计的,如果你能确保你传入的训练图像非常优秀都是标准的那么选均值就很好,如果你传入的图像不够完美有好的和次好的存在,那么就可以选中值。这时候中值的参数会给你的程序带来更好的抗噪。
2.train_variation_model(Images : : ModelID : )详解:
参数详解
1. Images
- 类型:
Region
或Image
- 作用:提供对齐后的训练图像(已通过仿射变换调整到参考区域尺寸)。
- 关键要求:
- 尺寸匹配:图像尺寸必须与
create_variation_model
中定义的Width
和Height
一致。 - 内容要求:图像需包含字符区域的变形样本(如旋转、缩放、平移后的实例)。
- 尺寸匹配:图像尺寸必须与
2. ModelID
- 类型:整数
- 作用:指定要训练的变异模型唯一标识符。
- 依赖:必须提前通过
create_variation_model
创建。
关键细节
1. 数据增强机制
- 网格采样:默认将图像划分为多个区域,每个区域的统计特征作为训练样本。
- 阈值筛选:通过
prepare_variation_model
排除噪声和非字符区域。
2. 模型更新策略
- 增量训练:每次调用
train_variation_model
会累积新的样本到模型中,无需从头训练。 - 参数存储:变异模型的参数(如像素分布直方图)保存在
ModelID
对应的内存中。
总结
- 核心作用:通过输入的训练图像更新变异模型,使其学习字符在不同变形下的外观变化。
- 依赖关系:需配合
create_variation_model
和prepare_variation_model
使用。 - 优化方向:合理设置网格参数和阈值,增加训练图像的多样性以提高模型鲁棒性。
3.prepare_variation_model( : : ModelID, AbsThreshold, VarThreshold : )详解:
参数含义:
AbsThreshold
(20):- 作用:筛选图像块时,像素值的绝对偏差阈值。
- 逻辑:仅保留像素值在
[局部均值 - AbsThreshold, 局部均值 + VarThreshold]
范围内的区域。 - 示例:若某像素的局部均值为
100
,则仅保留80 ≤ 像素值 ≤ 120
的区域(假设VarThreshold=20
)。
VarThreshold
(3):- 作用:筛选图像块时,像素值的方差阈值。
- 逻辑:丢弃方差超过
VarThreshold
的图像区域(避免噪声干扰)。 - 示例:若某区域的像素方差为
5
,则保留该区域;若方差为6
,则丢弃。
函数功能:
- 训练数据准备:
从当前图像中提取符合阈值的图像块(Tile),用于训练变异模型。 - 目的:通过阈值筛选,消除噪声和非字符区域,使模型专注于字符本身的变形特征。
本实例中为什么选择 20
和 3
?
这是经验值,需根据字符对比度和背景噪声水平调整:
- 字符对比度高(如黑色字符在白色背景上):
- 可适当增大
AbsThreshold
(如30),保留更宽的像素范围。
- 可适当增大
- 字符边缘细腻(如细线字体):
- 需减小
VarThreshold
(如1),保留更多局部方差小的区域以捕捉细节。
- 需减小
补充说明:
- 数据增强:此步骤通过阈值筛选,间接实现了对字符区域的“自适应采样”。
- 与网格采样的区别:不同于
prepare_variation_model
的其他参数版本(如网格划分),此参数组合直接通过像素统计特征筛选训练样本。
4.clear_train_data_variation_model( : : ModelID : )详解:
核心作用
- 清空训练数据:
删除与指定变异模型(ModelID
)关联的所有训练样本和中间计算结果。 - 释放内存:
回收模型占用的内存空间,避免长期训练导致内存泄漏。 - 重置训练状态:
将模型恢复到初始状态(未训练状态),允许重新开始训练。
5.compare_variation_model(Image : Region : ModelID : )详解:
参数详解
1. Image
- 类型:
Image
- 作用: 输入的待比较图像,需与训练变异模型时使用的图像尺寸和通道一致(如灰度图或彩色图)。
- 关键要求:
- 必须经过与训练阶段相同的仿射变换和对齐操作。
- 像素值范围需与模型创建时指定的
Type
('byte'/'uint2'/'float'
)匹配。
2. Region
- 类型:
Region
- 作用: 定义在
Image
中要比较的目标区域。该区域的尺寸必须与变异模型的参考区域(Width×Height
)严格一致。 - 生成方式:
- 通过
affine_trans_region
将检测到的字符区域变换到参考区域坐标系。 - 示例代码:
vector_angle_to_rigid(..., HomMat2D)
affine_trans_region(RegionDetected, RegionAligned, HomMat2D)
- 通过
3. ModelID
- 类型:
integer
- 作用: 指定要使用的变异模型唯一标识符(需通过
create_variation_model
创建)。
算子: compare_ext_variation_model(Image : Region : ModelID, Mode : )
该算子是算子compare_variation_model的拓展,其参数 MODE可以控制输出暗或亮缺陷或者都输出。
variation_model模型里还有很多其他算子,当你发现当前的算子参数不够完成你要的项目的时候,可以再去看看其他扩展的算子。
工作原理
模型匹配:
- 将输入图像的
Region
与变异模型进行特征比对,提取统计特征(如局部均值、方差、纹理能量)。
- 将输入图像的
差异计算:
- 计算像素值和区域特征的绝对偏差,并生成偏差图
Deviation
。 - 根据统计特征的匹配程度,输出相似度分数
Similarity
。
- 计算像素值和区域特征的绝对偏差,并生成偏差图
置信度评估:
- 基于相似度分数生成二值掩模
Confidence
,标识高置信度区域。
- 基于相似度分数生成二值掩模
6.clear_variation_model( : : ModelID : )详解:
核心作用
- 清除训练数据:
删除与指定变异模型(ModelID
)关联的所有训练样本和中间计算结果。 - 释放内存:
回收模型占用的内存空间,避免长期训练导致内存泄漏。 - 重置训练状态:
将模型恢复到初始状态(未训练状态),允许重新开始训练。
print_check_single_chars.hdev 详解:
这个实例主要就是检测打印字母的质量,首先是将打印出来的字母一个个拆分创建模板,然后传入很多训练的图像也是将其中的字母拆分区域传入,训练完毕后你就得到了多个字母区域训练完成可以后续用来比较模板,然后就是传入待检测的图片,同样将待检测的字母分割好一个个对应传入模板比较,得到差异区域,在根据这个差异区域的灰度,面积等参数来确定这个字母质量为OK/NG。
我将实例代码分成七个段落
1.窗体和图像的一些预处理操作
*-----------------------------------------------------------------------
* 1. 初始化与图像预处理
*-----------------------------------------------------------------------
dev_update_off() // 关闭实时更新显示
read_image (Image, 'pen/pen-01') // 读取基准图像
get_image_size (Image, Width, Height)
dev_close_window() // 关闭现有窗口
dev_open_window (0, 0, Width, Height, 'black', WindowHandle) // 创建新窗口
set_display_font (WindowHandle, 16, 'mono', 'true', 'false') // 设置显示字体为16号等宽黑体
dev_set_color ('red') // 设置红色显示
dev_display (Image) // 显示原始图像
2.字符区域分割与预处理
*-----------------------------------------------------------------------
* 2. 字符区域分割与预处理
*-----------------------------------------------------------------------
threshold (Image, Region, 100, 255) // 阈值分割(灰度>100为前景)
fill_up (Region, RegionFillUp) // 填充孔洞
difference (RegionFillUp, Region, RegionDifference) // 取反得到背景区域
shape_trans (RegionDifference, RegionTrans, 'convex') // 转换为凸包区域
dilation_circle (RegionTrans, RegionDilation, 8.5) // 扩展区域以包含边缘噪声
reduce_domain (Image, RegionDilation, ImageReduced)
threshold (ImageReduced, Region, 0, 180) // 二值化处理
connection (Region, ConnectedRegions) // 连通区域分析
sort_region (ConnectedRegions, SortedRegions, 'character', 'true', 'row') // 按字符顺序排序
dilation_circle (SortedRegions, RegionDilation, 1.5) // 轻微膨胀以稳定区域
smallest_rectangle1 (RegionDilation, Row1, Column1, Row2, Column2) // 计算最小包围矩形
count_obj (RegionDilation, Number) // 统计字符数量 Heights := Row2 - Row1 + 5 // 区域高度(含缓冲)
Widths := Column2 - Column1 + 5 // 区域宽度(含缓冲) gen_empty_obj (ShapeModels) // 初始化形状模型容器
gen_empty_obj (VariationModelROIs) // 初始化变异模型ROI容器
ShapeModelIDs := [] // 存储形状模型ID列表
VariationModelIDs := [] // 存储变异模型ID列表
RowsRef := [] // 存储基准行坐标
ColumnsRef := [] // 存储基准列坐标 for I := 1 to Number by 1
select_obj (RegionDilation, ObjectSelected, I) // 选择第I个字符区域
Height := Heights[I - 1] // 获取字符高度
Width := Widths[I - 1] // 获取字符宽度
move_region (ObjectSelected, RegionMoved, -Row1[I - 1], -Column1[I - 1]) // 平移至左上角
crop_part (Image, ImagePart, Row1[I - 1], Column1[I - 1], Widths[I - 1], Heights[I - 1]) // 裁剪字符区域
reduce_domain (ImagePart, RegionMoved, ImageReduced) // 减少图像域
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 1, [15,15,10]) // 检测形状模型
gen_contours_skeleton_xld (ModelRegions, ModelContour, 1, 'filter') // 生成轮廓
area_center (RegionMoved, Area, RowRef, ColumnRef) // 计算质心位置(用于对齐)
create_shape_model (ImageReduced, 5, rad(-10), rad(20), 'auto', 'none', 'use_polarity', 20, 10, ShapeModelID) // 创建形状模型
create_variation_model (Width, Height, 'byte', 'standard', VariationModelID) // 创建变异模型
concat_obj (ShapeModels, ModelContour, ShapeModels) // 合并模型轮廓
concat_obj (VariationModelROIs, RegionMoved, VariationModelROIs) // 合并ROI区域
RowsRef := [RowsRef,RowRef] // 更新行坐标引用
ColumnsRef := [ColumnsRef,ColumnRef] // 更新列坐标引用
ShapeModelIDs := [ShapeModelIDs,ShapeModelID] // 存储形状模型ID
VariationModelIDs := [VariationModelIDs,VariationModelID] // 存储变异模型ID
endfor
这边主要是将一个个字母区域提取出来制作成一个个单独的模板。
3. 形状模型可视化
*-----------------------------------------------------------------------
* 3. 形状模型可视化
*-----------------------------------------------------------------------
gen_empty_obj (Models)
for I := 1 to Number by 1
select_obj (ShapeModels, ModelSelected, I) // 选择第I个模型
hom_mat2d_identity (HomMat2DIdentity) // 初始化仿射变换矩阵为单位矩阵
hom_mat2d_translate (HomMat2DIdentity, Row1[I - 1], Column1[I - 1], HomMat2D) // 平移至原始位置
affine_trans_contour_xld (ModelSelected, ModelTrans, HomMat2D) // 应用仿射变换
concat_obj (Models, ModelTrans, Models) // 合并可视化模型
endfor dev_display (Image)
dev_set_colored (6) // 设置浅灰色
dev_set_draw ('margin') // 绘制边框
dev_set_line_width (3) // 边框宽度3像素
dev_display (Models) // 显示所有形状模型
dev_set_color ('yellow') // 设置黄色
disp_message (WindowHandle, 'Shape models', 'image', 12, 20, 'yellow', 'false') // 显示标题
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false') // 显示副标题
disp_continue_message (WindowHandle, 'black', 'true') // 继续显示黑色背景
stop () // 暂停等待用户确认
这边主要是将一个个字母区域通过反射变换到匹配所在的位置,让他能够与字母图对应轮廓显示查看。
4. 变异模型训练
*-----------------------------------------------------------------------
* 4. 变异模型训练
*-----------------------------------------------------------------------
for J := 1 to 15 by 1
read_image (Image, 'pen/pen-' + J$'02d') // 读取训练图像(共15张)
find_shape_models (Image, ShapeModelIDs, rad(-10), rad(20), 0.5, [1,1,1,1,1], 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Score, Model) // 检测字符位置
for K := 0 to |Score| - 1 by 1
vector_angle_to_rigid (Row[K], Column[K], Angle[K], RowsRef[Model[K]], ColumnsRef[Model[K]], 0, HomMat2D) // 计算位姿矩阵
affine_trans_image_size (Image, ImageTrans, HomMat2D, 'constant', Widths[Model[K]], Heights[Model[K]]) // 图像对齐到基准尺寸
select_obj (VariationModelROIs, ROI, Model[K] + 1) // 选择对应ROI区域
reduce_domain (ImageTrans, ROI, ImageTransReduced) // 减少图像域
train_variation_model (ImageTransReduced, VariationModelIDs[Model[K]]) // 训练变异模型
endfor
endfor
这边主要是将传入的训练图形中的字母一个个匹配定位到后,将区域反射变换过去然后将字母裁剪出来传入训练。
5. 变异模型可视化验证
*-----------------------------------------------------------------------
* 5. 变异模型可视化验证
*-----------------------------------------------------------------------
get_image_size (Image, Width, Height)
gen_empty_obj (MeanImages)
gen_empty_obj (VarImages)
gen_empty_obj (ROIs) for I := 1 to Number by 1
get_variation_model (MeanImage, VarImage, VariationModelIDs[I - 1]) // 获取均值/方差图像
*AbsThreshold = 20:绝对阈值,用于筛选图像块中的像素值。只有像素值在[Mean - AbsThreshold, Mean + VarThreshold]范围内的像素才会被保留。
*VarThreshold = 3:方差阈值,控制像素值的允许变化范围,基于局部区域的方差。
prepare_variation_model (VariationModelIDs[I - 1], 20, 3) // select_obj (VariationModelROIs, ROI, I) // 选择第I个ROI区域
move_region (ROI, ROIMoved, Row1[I - 1], Column1[I - 1]) // 移动至基准位置
reduce_domain (MeanImage, ROI, MeanImageReduced) // 减少域范围
reduce_domain (VarImage, ROI, VarImageReduced) // 减少域范围
concat_obj (MeanImages, MeanImageReduced, MeanImages) // 合并均值图像
concat_obj (VarImages, VarImageReduced, VarImages) // 合并方差图像
concat_obj (ROIs, ROIMoved, ROIs) // 合并ROI区域
clear_train_data_variation_model (VariationModelIDs[I - 1]) // 清空训练数据
endfor tile_images_offset (MeanImages, MeanImage, Row1, Column1, gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), Width, Height) // 并排显示均值图像
tile_images_offset (VarImages, VarImage, Row1, Column1, gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), Width, Height) // 并排显示方差图像 get_domain (Image, Domain) // 获取图像有效域
dev_set_color ('black') // 设置黑色背景
dev_set_draw ('fill') // 填充显示
dev_display (Domain) // 显示图像域
dev_display (MeanImage) // 显示均值图像
dev_set_colored (6) // 设置浅灰色边框
dev_set_draw ('margin') // 绘制边框
dev_set_line_width (1) // 边框宽度1像素
dev_display (ROIs) // 显示ROI区域
dev_set_color ('yellow') // 设置黄色文字
disp_message (WindowHandle, 'Reference images', 'image', 20, 20, 'yellow', 'false') // 显示标题
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false') // 显示副标题
disp_continue_message (WindowHandle, 'black', 'true') // 继续显示黑色背景
stop () dev_set_color ('black')
dev_set_draw ('fill')
dev_display (Domain)
dev_display (VarImage)
dev_set_colored (6)
dev_set_draw ('margin')
dev_set_line_width (1)
dev_display (ROIs)
dev_set_color ('yellow')
disp_message (WindowHandle, 'Variation images', 'image', 20, 20, 'yellow', 'false')
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
这边就是整合每个模型里的均值图和方差图拼接出来显示给我们看一下过程。
6. 打印错误检测与分类
*-----------------------------------------------------------------------
* 6. 打印错误检测与分类
*-----------------------------------------------------------------------
for J := 1 to 30 by 1
read_image (Image, 'pen/pen-' + J$'02d') // 读取测试图像
gen_empty_obj (RegionsErrorTrans) // 初始化错误区域容器
find_shape_models (Image, ShapeModelIDs, rad(-10), rad(20), 0.5, [1,1,1,1,1], 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Score, Model) // 检测字符位置
NumberFound := |Score| // 获取检测结果数量
for K := 0 to NumberFound - 1 by 1
vector_angle_to_rigid (Row[K], Column[K], Angle[K], RowsRef[Model[K]], ColumnsRef[Model[K]], 0, HomMat2D) // 计算位姿矩阵
affine_trans_image_size (Image, ImageTrans, HomMat2D, 'constant', Widths[Model[K]], Heights[Model[K]]) // 图像对齐到基准尺寸
select_obj (VariationModelROIs, ROI, Model[K] + 1) // 选择对应ROI区域
reduce_domain (ImageTrans, ROI, ImageTransReduced) // 减少图像域
compare_variation_model (ImageTransReduced, RegionDiff, VariationModelIDs[Model[K]]) // 比较当前图像与变异模型
connection (RegionDiff, ConnectedRegions) // 连通区域分析
select_shape (ConnectedRegions, RegionsError, 'area', 'and', 20, 1000000) // 筛选面积>20且<1e6的区域作为错误
count_obj (RegionsError, NumError) // 统计错误区域数量
if (NumError > 0)
vector_angle_to_rigid (RowsRef[Model[K]], ColumnsRef[Model[K]], 0, Row[K], Column[K], Angle[K], HomMat2D) // 计算反向位姿
affine_trans_region (RegionsError, RegionErrorTrans, HomMat2D, 'nearest_neighbor') // 变换错误区域至原始坐标系
concat_obj (RegionsErrorTrans, RegionErrorTrans, RegionsErrorTrans) // 合并错误区域
endif
endfor
dev_clear_window () // 清空显示窗口
dev_display (Image) // 显示原始图像
dev_set_color ('red') // 设置红色警告框
dev_display (RegionsErrorTrans) // 显示检测结果
count_obj (RegionsErrorTrans, NumError) // 统计错误数量
if (NumError == 0 and NumberFound == Number)
disp_message (WindowHandle, 'Clip OK', 'image', 20, 20, 'green', 'false') // 显示绿色OK
else
disp_message (WindowHandle, 'Clip not OK', 'image', 20, 20, 'red', 'false') // 显示红色NG
endif
if (J < 30)
disp_continue_message (WindowHandle, 'black', 'true') // 显示继续提示
stop () // 单步调试暂停
endif
endfor
这边就是将一个个待检测图片传入进去,然后进行一个个的模板区域比对整合结果,在差异参数允许范围内的话就OK,反之NG,然后把差异区域显示出来查看。
7. 资源清理
*-----------------------------------------------------------------------
* 7. 资源清理
*-----------------------------------------------------------------------
for I := 1 to Number by 1
clear_shape_model (ShapeModelIDs[I - 1]) // 清除形状模型
clear_variation_model (VariationModelIDs[I - 1]) // 清除变异模型
endfor
到这整个实例程序就运行完毕了,思想就是分割各个模板区域,然后创建出各个区域的可变模型来进行一一比对,得到差异图形区域。说白了就是拿个标准图,其他图跟标准图贴起来比对,得到灰度差异图或者局部形状差异图。
那么字母可以这样分割区域检测,半导体/Led的晶圆的各个灰度,颜色或者形状区域是不是也可以这样做呢?这就是GoldenDie(构阵带?应该这样念把)检测。(注:大部分led的公司的晶圆并不标准,用这个调参都会把你调死,最好配合分区域检测方法使用。半导体的高质量Die倒是可以用,不过在半导体中高端设备检测他们又会使用其他更好的检测方法)
附print_check_single_chars.hdev实例总代码:
*-----------------------------------------------------------------------
* 1. 初始化与图像预处理
*-----------------------------------------------------------------------
dev_update_off() // 关闭实时更新显示
read_image (Image, 'pen/pen-01') // 读取基准图像
get_image_size (Image, Width, Height)
dev_close_window() // 关闭现有窗口
dev_open_window (0, 0, Width, Height, 'black', WindowHandle) // 创建新窗口
set_display_font (WindowHandle, 16, 'mono', 'true', 'false') // 设置显示字体为16号等宽黑体
dev_set_color ('red') // 设置红色显示
dev_display (Image) // 显示原始图像 *-----------------------------------------------------------------------
* 2. 字符区域分割与预处理
*-----------------------------------------------------------------------
threshold (Image, Region, 100, 255) // 阈值分割(灰度>100为前景)
fill_up (Region, RegionFillUp) // 填充孔洞
difference (RegionFillUp, Region, RegionDifference) // 取反得到背景区域
shape_trans (RegionDifference, RegionTrans, 'convex') // 转换为凸包区域
dilation_circle (RegionTrans, RegionDilation, 8.5) // 扩展区域以包含边缘噪声
reduce_domain (Image, RegionDilation, ImageReduced)
threshold (ImageReduced, Region, 0, 180) // 二值化处理
connection (Region, ConnectedRegions) // 连通区域分析
sort_region (ConnectedRegions, SortedRegions, 'character', 'true', 'row') // 按字符顺序排序
dilation_circle (SortedRegions, RegionDilation, 1.5) // 轻微膨胀以稳定区域
smallest_rectangle1 (RegionDilation, Row1, Column1, Row2, Column2) // 计算最小包围矩形
count_obj (RegionDilation, Number) // 统计字符数量 Heights := Row2 - Row1 + 5 // 区域高度(含缓冲)
Widths := Column2 - Column1 + 5 // 区域宽度(含缓冲) gen_empty_obj (ShapeModels) // 初始化形状模型容器
gen_empty_obj (VariationModelROIs) // 初始化变异模型ROI容器
ShapeModelIDs := [] // 存储形状模型ID列表
VariationModelIDs := [] // 存储变异模型ID列表
RowsRef := [] // 存储基准行坐标
ColumnsRef := [] // 存储基准列坐标 for I := 1 to Number by 1
select_obj (RegionDilation, ObjectSelected, I) // 选择第I个字符区域
Height := Heights[I - 1] // 获取字符高度
Width := Widths[I - 1] // 获取字符宽度
move_region (ObjectSelected, RegionMoved, -Row1[I - 1], -Column1[I - 1]) // 平移至左上角
crop_part (Image, ImagePart, Row1[I - 1], Column1[I - 1], Widths[I - 1], Heights[I - 1]) // 裁剪字符区域
reduce_domain (ImagePart, RegionMoved, ImageReduced) // 减少图像域
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 1, [15,15,10]) // 检测形状模型
gen_contours_skeleton_xld (ModelRegions, ModelContour, 1, 'filter') // 生成轮廓
area_center (RegionMoved, Area, RowRef, ColumnRef) // 计算质心位置(用于对齐)
create_shape_model (ImageReduced, 5, rad(-10), rad(20), 'auto', 'none', 'use_polarity', 20, 10, ShapeModelID) // 创建形状模型
create_variation_model (Width, Height, 'byte', 'standard', VariationModelID) // 创建变异模型
concat_obj (ShapeModels, ModelContour, ShapeModels) // 合并模型轮廓
concat_obj (VariationModelROIs, RegionMoved, VariationModelROIs) // 合并ROI区域
RowsRef := [RowsRef,RowRef] // 更新行坐标引用
ColumnsRef := [ColumnsRef,ColumnRef] // 更新列坐标引用
ShapeModelIDs := [ShapeModelIDs,ShapeModelID] // 存储形状模型ID
VariationModelIDs := [VariationModelIDs,VariationModelID] // 存储变异模型ID
endfor *-----------------------------------------------------------------------
* 3. 形状模型可视化
*-----------------------------------------------------------------------
gen_empty_obj (Models)
for I := 1 to Number by 1
select_obj (ShapeModels, ModelSelected, I) // 选择第I个模型
hom_mat2d_identity (HomMat2DIdentity) // 初始化仿射变换矩阵为单位矩阵
hom_mat2d_translate (HomMat2DIdentity, Row1[I - 1], Column1[I - 1], HomMat2D) // 平移至原始位置
affine_trans_contour_xld (ModelSelected, ModelTrans, HomMat2D) // 应用仿射变换
concat_obj (Models, ModelTrans, Models) // 合并可视化模型
endfor dev_display (Image)
dev_set_colored (6) // 设置浅灰色
dev_set_draw ('margin') // 绘制边框
dev_set_line_width (3) // 边框宽度3像素
dev_display (Models) // 显示所有形状模型
dev_set_color ('yellow') // 设置黄色
disp_message (WindowHandle, 'Shape models', 'image', 12, 20, 'yellow', 'false') // 显示标题
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false') // 显示副标题
disp_continue_message (WindowHandle, 'black', 'true') // 继续显示黑色背景
stop () // 暂停等待用户确认 *-----------------------------------------------------------------------
* 4. 变异模型训练
*-----------------------------------------------------------------------
for J := 1 to 15 by 1
read_image (Image, 'pen/pen-' + J$'02d') // 读取训练图像(共15张)
find_shape_models (Image, ShapeModelIDs, rad(-10), rad(20), 0.5, [1,1,1,1,1], 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Score, Model) // 检测字符位置
for K := 0 to |Score| - 1 by 1
vector_angle_to_rigid (Row[K], Column[K], Angle[K], RowsRef[Model[K]], ColumnsRef[Model[K]], 0, HomMat2D) // 计算位姿矩阵
affine_trans_image_size (Image, ImageTrans, HomMat2D, 'constant', Widths[Model[K]], Heights[Model[K]]) // 图像对齐到基准尺寸
select_obj (VariationModelROIs, ROI, Model[K] + 1) // 选择对应ROI区域
reduce_domain (ImageTrans, ROI, ImageTransReduced) // 减少图像域
train_variation_model (ImageTransReduced, VariationModelIDs[Model[K]]) // 训练变异模型
endfor
endfor *-----------------------------------------------------------------------
* 5. 变异模型可视化验证
*-----------------------------------------------------------------------
get_image_size (Image, Width, Height)
gen_empty_obj (MeanImages)
gen_empty_obj (VarImages)
gen_empty_obj (ROIs) for I := 1 to Number by 1
get_variation_model (MeanImage, VarImage, VariationModelIDs[I - 1]) // 获取均值/方差图像
*AbsThreshold = 20:绝对阈值,用于筛选图像块中的像素值。只有像素值在[Mean - AbsThreshold, Mean + VarThreshold]范围内的像素才会被保留。
*VarThreshold = 3:方差阈值,控制像素值的允许变化范围,基于局部区域的方差。
prepare_variation_model (VariationModelIDs[I - 1], 20, 3) // select_obj (VariationModelROIs, ROI, I) // 选择第I个ROI区域
move_region (ROI, ROIMoved, Row1[I - 1], Column1[I - 1]) // 移动至基准位置
reduce_domain (MeanImage, ROI, MeanImageReduced) // 减少域范围
reduce_domain (VarImage, ROI, VarImageReduced) // 减少域范围
concat_obj (MeanImages, MeanImageReduced, MeanImages) // 合并均值图像
concat_obj (VarImages, VarImageReduced, VarImages) // 合并方差图像
concat_obj (ROIs, ROIMoved, ROIs) // 合并ROI区域
clear_train_data_variation_model (VariationModelIDs[I - 1]) // 清空训练数据
endfor tile_images_offset (MeanImages, MeanImage, Row1, Column1, gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), Width, Height) // 并排显示均值图像
tile_images_offset (VarImages, VarImage, Row1, Column1, gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), gen_tuple_const(Number,-1), Width, Height) // 并排显示方差图像 get_domain (Image, Domain) // 获取图像有效域
dev_set_color ('black') // 设置黑色背景
dev_set_draw ('fill') // 填充显示
dev_display (Domain) // 显示图像域
dev_display (MeanImage) // 显示均值图像
dev_set_colored (6) // 设置浅灰色边框
dev_set_draw ('margin') // 绘制边框
dev_set_line_width (1) // 边框宽度1像素
dev_display (ROIs) // 显示ROI区域
dev_set_color ('yellow') // 设置黄色文字
disp_message (WindowHandle, 'Reference images', 'image', 20, 20, 'yellow', 'false') // 显示标题
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false') // 显示副标题
disp_continue_message (WindowHandle, 'black', 'true') // 继续显示黑色背景
stop () dev_set_color ('black')
dev_set_draw ('fill')
dev_display (Domain)
dev_display (VarImage)
dev_set_colored (6)
dev_set_draw ('margin')
dev_set_line_width (1)
dev_display (ROIs)
dev_set_color ('yellow')
disp_message (WindowHandle, 'Variation images', 'image', 20, 20, 'yellow', 'false')
disp_message (WindowHandle, '(moved to original pos.)', 'image', 45, 20, 'yellow', 'false')
disp_continue_message (WindowHandle, 'black', 'true')
stop () *-----------------------------------------------------------------------
* 6. 打印错误检测与分类
*-----------------------------------------------------------------------
for J := 1 to 30 by 1
read_image (Image, 'pen/pen-' + J$'02d') // 读取测试图像
gen_empty_obj (RegionsErrorTrans) // 初始化错误区域容器
find_shape_models (Image, ShapeModelIDs, rad(-10), rad(20), 0.5, [1,1,1,1,1], 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Score, Model) // 检测字符位置
NumberFound := |Score| // 获取检测结果数量
for K := 0 to NumberFound - 1 by 1
vector_angle_to_rigid (Row[K], Column[K], Angle[K], RowsRef[Model[K]], ColumnsRef[Model[K]], 0, HomMat2D) // 计算位姿矩阵
affine_trans_image_size (Image, ImageTrans, HomMat2D, 'constant', Widths[Model[K]], Heights[Model[K]]) // 图像对齐到基准尺寸
select_obj (VariationModelROIs, ROI, Model[K] + 1) // 选择对应ROI区域
reduce_domain (ImageTrans, ROI, ImageTransReduced) // 减少图像域
compare_variation_model (ImageTransReduced, RegionDiff, VariationModelIDs[Model[K]]) // 比较当前图像与变异模型
connection (RegionDiff, ConnectedRegions) // 连通区域分析
select_shape (ConnectedRegions, RegionsError, 'area', 'and', 20, 1000000) // 筛选面积>20且<1e6的区域作为错误
count_obj (RegionsError, NumError) // 统计错误区域数量
if (NumError > 0)
vector_angle_to_rigid (RowsRef[Model[K]], ColumnsRef[Model[K]], 0, Row[K], Column[K], Angle[K], HomMat2D) // 计算反向位姿
affine_trans_region (RegionsError, RegionErrorTrans, HomMat2D, 'nearest_neighbor') // 变换错误区域至原始坐标系
concat_obj (RegionsErrorTrans, RegionErrorTrans, RegionsErrorTrans) // 合并错误区域
endif
endfor
dev_clear_window () // 清空显示窗口
dev_display (Image) // 显示原始图像
dev_set_color ('red') // 设置红色警告框
dev_display (RegionsErrorTrans) // 显示检测结果
count_obj (RegionsErrorTrans, NumError) // 统计错误数量
if (NumError == 0 and NumberFound == Number)
disp_message (WindowHandle, 'Clip OK', 'image', 20, 20, 'green', 'false') // 显示绿色OK
else
disp_message (WindowHandle, 'Clip not OK', 'image', 20, 20, 'red', 'false') // 显示红色NG
endif
if (J < 30)
disp_continue_message (WindowHandle, 'black', 'true') // 显示继续提示
stop () // 单步调试暂停
endif
endfor *-----------------------------------------------------------------------
* 7. 资源清理
*-----------------------------------------------------------------------
for I := 1 to Number by 1
clear_shape_model (ShapeModelIDs[I - 1]) // 清除形状模型
clear_variation_model (VariationModelIDs[I - 1]) // 清除变异模型
endfor
halcon中是怎么实现半导体/Led中的GoldenDie的检测方法的 基于局部可变形模板匹配 variation_model模型的更多相关文章
- Halcon编程-基于形状特征的模板匹配
halcon软件最高效的一个方面在于模板匹配,号称可以快速进行柔性模板匹配,能够非常方便的用于缺陷检测.目标定位.下面以一个简单的例子说明基于形状特征的模板匹配. 为了在右图中,定位图中的三 ...
- 基于.net的分布式系统限流组件 C# DataGridView绑定List对象时,利用BindingList来实现增删查改 .net中ThreadPool与Task的认识总结 C# 排序技术研究与对比 基于.net的通用内存缓存模型组件 Scala学习笔记:重要语法特性
基于.net的分布式系统限流组件 在互联网应用中,流量洪峰是常有的事情.在应对流量洪峰时,通用的处理模式一般有排队.限流,这样可以非常直接有效的保护系统,防止系统被打爆.另外,通过限流技术手段,可 ...
- halcon三种模板匹配方法
halcon有三种模板匹配方法:即Component-Based.Gray-Value-Based.Shaped_based,分别是基于组件(或成分.元素)的匹配,基于灰度值的匹配和基于形状的匹配,此 ...
- halcon——缺陷检测常用方法总结(模板匹配(定位)+差分)
引言 机器视觉中缺陷检测分为一下几种: blob分析+特征 模板匹配(定位)+差分 光度立体:halcon--缺陷检测常用方法总结(光度立体) - 唯有自己强大 - 博客园 (cnblogs.com) ...
- Android应用项目中BaseAdapter、SimpleAdapter和ArrayAdapter中的三种适配器
一.写在前面: 本次我们来讲解一下Android应用中三个适配器:BaseAdapter.SimpleAdapter和ArrayAdapter.其中常见的是BaseAdapter,也是个人推荐使用的适 ...
- EXCEL中对1个单元格中多个数字求和
如A1=3779.3759.3769.3781.3750,A2对A1中4个数字求和怎么求!请高手赐教! 方法一:在B1中输入公式=SUM(MID(A1,{1,6,11,16,21},4)*1) 方法二 ...
- 借助JavaScript中的Dom属性改变Html中Table边框的颜色
借助JavaScript中的Dom属性改变Html中Table边框的颜色 -------------------- <html> <head> <title>我是页 ...
- 借助JavaScript中的时间函数改变Html中Table边框的颜色
借助JavaScript中的时间函数改变Html中Table边框的颜色 <html> <head> <meta http-equiv="Content-Type ...
- Java中是否可以调用一个类中的main方法?
前几天面试的时候,被问到在Java中是否可以调用一个类中的main方法?回来测试了下,答案是可以!代码如下: main1中调用main2的主方法 package org.fiu.test; impor ...
- linux 中部署ant编译的包中缺少问题
今天遇到在window上部署ant编译的包,能运行正常,但部署在linux中出现跳不进jsp中,出现404问题,后来经过排查在jsp中<%@taglib prefix="c" ...
随机推荐
- PCB设计AD规则设置(按照嘉立创设置)
本文转载自https://blog.csdn.net/subtitle_/article/details/121648972 官方参考https://www.jlc.com/portal/vtechn ...
- vue前端代码npm install报错的解决方法
npm install,报错: npm WARN tarball tarball data for has-bigints@https://registry.npmmirror.com/has-big ...
- 重磅宣布|强强联合,腾讯云携手Veeam提供云上数据存储服务
近日获悉,腾讯云对象存储COS正式通过Veeam备份软件标准化测试,携手为用户提供云上数据存储服务. Veeam对COS的支持是通过SOBR( Scale out backup repository) ...
- ng-alain: st 简化表格
https://github.com/ng-alain/delon/blob/master/packages/abc/st/index.zh-CN.md st 并不是在创造另一个表格组件,而是在 nz ...
- 【前端】【H5 API】实现文件读取操作
H5 API 实现文件读取操作 该接口通过FileReader对象来读取本地存储的文件,然后使用File对象来指定读取的文件或数据 File对象 可以是来自用户在一个元素上(如<input> ...
- Qt开发经验小技巧101-110
如果需要在尺寸改变的时候不重绘窗体,则设置属性即可 this->setAttribute(Qt::WA_StaticContents, true); 这样可以避免可以避免对已经显示区域的重新绘制 ...
- Net6之Jwt认证+Bearer认证 2.0
以前接触过,写过博客,第二次再写有了新的体会.第一次博客:https://www.cnblogs.com/zhang-3/p/16184067.html 过程: 生成token令牌(钥匙) 添加bea ...
- 开源轻量级 IM 框架 MobileIMSDK 的微信小程序端已发布!
一.基本介绍 MobileIMSDK - 微信小程序端是一套基于微信原生 WebSocket 的即时通讯库: 1)超轻量级.无任何第 3 方库依赖(开箱即用): 2)纯 JS 编写.ES6 语法.高度 ...
- 内华达大地测量实验室gnss数据半自动化下载
内华达大地测量实验室GNSS数据半自动化下载 前言 目的:继上篇GNSS时序形变位移数据下载,介绍了内华达网站GNSS位移数据如何手动交互进行下载.后面发现若自己需要下载很多站点的数据,我要通过手动一 ...
- 获取不同型号手机小程序导航栏的高度(uniapp)
uni.getSystemInfo({ success: function(e) { Vue.prototype.StatusBar = e.statusBarHeight; let custom = ...