Halcon使用
Halcon
HALCON 是一款非常强大的工业视觉软件,广泛用于自动化检测和机器视觉领域。它由德国公司 MVTec Software GmbH 开发,在制造业、医疗影像、机器人等行业应用很多。
HALCON 是一个机器视觉算法库 + 开发环境,主要用来让计算机“看懂图像”。它提供了大量现成的视觉处理工具,比如:
- 图像增强(去噪、对比度调整)
- 边缘检测
- 目标识别
- 测量尺寸
- 缺陷检测
读取图片
* 读取图片
* Image 输出参数
* 'printer...' 输入图,相对路径
read_image (Image, 'printer_chip/printer_chip_01')
* 绝对路径
read_image (Image1, 'D:/图片/emoji/微信图片_2025-11-27_092846_383.jpg')
* 变量赋值
a:=10
阈值分割(类似blob)
*1 读取卡针图片
read_image (Image2, 'clip')
*2 阈值分割 ≈ Blob工具
* 参数1 输入图片
* 参数2 输出区域
* 参数3,参数4 提取的阈值范围
threshold (Image2, Region, 10, 80)
*3 连通区域
* 参数1 传入区域
* 参数2 分割后区域
connection (Region, ConnectedRegions)
*4 筛选
* 参数1 筛选区域
* 参数2 筛选后的区域
* 参数3 筛选属性 ara 面积
* 参数4 与预算
* 参数5,6 最小最大面积
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 5000, 99999)
* 选择区域
gen_rectangle1 (ROI_0, 16.1173, 57.9092, 206.662, 292.683)
常见数据类型、运算符
*halcon的常见数据类型:图形变量、控制变量
*图形变量:图片类型(Image),区域(Region)轮廓类型
*控制变量: 基本数据类型(整型、浮点型、字符串类型)、句柄、元组类型
*1 获取窗口的句柄
* 获取window句柄到 WindowHandle 变量
dev_get_window (WindowHandle)
*2 基本数据类型
* := 赋值
a:=226 // int
b:=22.6 // number
c:='226' // string
d:=true // tru == 1
*3 元组类型(tuple)
arr:=[] // 空数组
arr1:=[1,2,3] // 数字数组
arr2:=['你好',2,3.14] // 多类型数组
test:=arr2[2] // 取值
arr3:=[0:10] // 0~10
arr4:=[0:10:100] // 从0开始,每次递增10,到100
arr5:=[0:-10:-100] // 从0开始,每次递减10,到-100
* |数组名| 获取数组长度
length:=|arr5| // 数组长度
*4 元组tuple常用的一些函数
tuple_abs (-10, Abs) // 绝对值
tuple_add (10, 10, Sum) // 求和
tuple_ceil (1.1, Ceil) // 向上取整
tuple_floor (1.9, Floor) // 向下取整
tuple_concat (Sum, Sum, Concat) // 拼接
tuple_concat (arr4, arr5, Concat1) // 元组拼接
tuple_remove (Concat1, 5, Reduced) // 删除元组指定索引
* 注意:如果为字符串 '1' 也会判断为是数字
tuple_is_number (arr2, IsNumber) // 判断数组中是否为数字类型
*5 运算符
a1:=10
a1:=a1+30
a1:= a1-30
a1:=a1*10
a1:=a1/9
a1:=a1%9
流程控制语句
*1流程控制
dev_clear_window () // 清空窗体
a2:=90
a3:=190
if (a2!=a3) // == 相等, #不等 !=不等
*展示文本:展示字符,在窗口上展示,左上展示, 黑色的字体
*[属性名],[属性值] 预留参数
*shadow_color 盒子阴影
dev_disp_text ('hello', 'window', 0, 100, 'black', ['box_color','shadow_color'], ['green','red'])
endif
stop ()
dev_clear_window()
socre:=50
if(socre<=100 and socre>=90) //and 并且
*参数1 窗体的句柄
*2 内容
*3 展示窗体上
*4/5 坐标
*6 颜色
*7/8 预留参数
disp_text (WindowHandle, '非常优秀', 'window', 12, 12, 'black', [], [])
elseif(socre< 90and socre>=80)
disp_text (WindowHandle, '优秀', 'window', 12, 12, 'black', [], [])
else
disp_text (WindowHandle, '及格', 'window', 12, 12, 'black', [], [])
endif
stop () // 停止运行
*2 switch 条件判断
week:=1
switch (week)
case 1:
dev_disp_text ('周一', 'window', 200, 300, 'black', ['box_color','shadow_color'], ['green','red'])
break
case 2:
dev_disp_text ('周二', 'window', 200, 300, 'black', ['box_color','shadow_color'], ['green','red'])
break
default:
dev_clear_window ()
break
endswitch
循环语句
*1 for循环
* 从1到5 每次叠加1 所有for结束之后index是6
dev_clear_window()
for Index := 1 to 5 by 1
aa:=Index
endfor
stop ()
bb:=Index+1
* 求1~100的和
sum1:=0
for Index := 1 to 100 by 1
sum1:= sum1 + Index
endfor
stop ()
s1:=90
if (s1>80 or s1<60) // or 或者意思 俩个满足一个即可
dev_disp_text ('适得府君书', 'window', 0, 100, 'black', ['box_color','shadow_color'], ['green','red'])
endif
stop ()
if (s1>80 xor s1<60) // 俩个只能满足一个
dev_disp_text ('sssss', 'window', 100, 100, 'black', ['box_color','shadow_color'], ['green','red'])
endif
stop ()
for Index1 := 1 to 5 by 1
if (Index1%2==0)
break // break 跳出循环 其他循环也不再执行;continue结束本次循环 继续下次循环
endif
endfor
stop ()
*2 while循环
count:=0
while (1)
count:=count+1
dev_disp_text (count, 'window', 100, 10+count*50, 'black', ['box_color','shadow_color'], ['green','red'])
if (count>10)
break
endif
endwhile
读取多张图片
*1 读取单张图片
* read_image (Image, 'D:/桌面/Halcon/day01/img(4)/img/1.jpg')
*2 读取多张图片
list_image_files ('D:/桌面/Halcon/day01/img(4)/img', 'default', [], ImageFiles)
* 循环读取每张图片
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
stop ()
endfor
作业1:阈值分割匹配骰子
list_image_files ('D:/桌面/Halcon/day01/img(4)/img', 'default', [], ImageFiles)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
* 转换为灰度图
rgb1_to_gray(Image, GrayImage)
* 阈值分割
threshold (GrayImage, Region, 20, 120)
* 连通性分割
connection (Region, ConnectedRegions)
* 首次面积筛选
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 190, 420)
* 根据面积筛选输出所有圆的非环性
* dev_display (Image)
* count_obj (SelectedRegions, Number)
* for i := 1 to Number by 1
* select_obj (SelectedRegions, Obj, i)
* 计算 circularity
* circularity (Obj, Circularity)
* 显示中心位置
* area_center (Obj, Area, Row, Column)
* 显示文本(推荐)
* dev_disp_text (Circularity, 'image', Row, Column, 'red', [], [])
* endfor
* 筛选非环性
select_shape (SelectedRegions, Result, 'circularity', 'and', 0.5, 1.0)
* 计算数量
count_obj(Result,Number)
* 类型转换
tuple_string (Number, 'd', str)
* 首先显示原图
dev_display (Image)
* 接着显示最终匹配结果
dev_display (Result)
* 显示数量
dev_disp_text (str, 'window', 'top', 'left', 'black', [], [])
stop ()
endfor
作业2:阈值分割匹配孔洞
* 读取图片
read_image(Image, 'particle.png')
* 阈值分割
threshold (Image, Region, 90, 255)
* 连通性
connection (Region, ConnectedRegions)
* 面积筛选
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 90, 99999)
* 获取region数量
count_obj (SelectedRegions, Number)
* 清除屏幕
dev_clear_window ()
for Index := 1 to Number by 1
* 从多个regions集合中取出一个
select_obj (SelectedRegions, ObjectSelected, Index)
* 获取该region的 面积,行,列坐标
area_center (ObjectSelected, Area, Row, Column)
* 根据面积设置颜色
* 根据面积设置文字
if (Area >= 5000)
dev_set_color ('green')
dev_disp_text ('大区域', 'image', Row, Column, 'black', [], [])
elseif (Area >= 1000)
dev_set_color ('yellow')
dev_disp_text ('中区域', 'image', Row, Column, 'black', [], [])
else
dev_set_color ('blue')
dev_disp_text ('小区域', 'image', Row, Column, 'black', [], [])
endif
endfor
绘制区域
* 绘制ROI区域
* Region of Interest 感兴趣区域
* 使用界面操作配置
* gen_region_runs (ROI_0, [67,68,69,70,71,72,73,74,75,76,77,78,78,79,79,80,80,81,81,82,82,83,83,84,84,85,85,86,86,87,87,88,88,89,89,90,90,91,91,92,92,93,93,94,94,95,95,96,96,97,97,98,98,99,99,100,100,101,101,102,102,103,103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,127,127,128,128,129,129,130,130,131,131,132,132,133,133,134,134,135,135,136,136,137,137,138,138,139,139,140,140,141,141,142,142,143,143,144,144,145,145,146,146,147,147,148,148,149,149,150,150,151,151,152,152,153,153,154,154,155,155,156,156,157,157,158,158,159,159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171,172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180,181,181,182,182,183,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308], [215,210,208,205,205,205,202,200,199,198,198,39,196,36,194,35,192,34,192,31,191,31,191,31,190,30,187,29,187,28,186,27,185,27,185,27,184,24,182,24,182,23,181,23,180,23,180,23,180,22,180,22,178,20,178,20,178,20,178,20,175,20,175,20,174,19,174,18,173,18,173,18,172,18,172,18,171,17,171,17,169,17,169,17,168,17,168,16,167,16,167,15,166,15,166,15,166,15,166,15,165,15,163,15,163,15,163,15,162,15,162,15,162,15,161,15,161,15,161,15,161,15,159,15,159,15,159,15,159,15,157,15,157,15,157,15,157,15,157,15,157,15,157,15,157,15,156,15,155,15,155,15,155,15,155,15,155,15,154,15,154,15,154,15,154,15,154,15,154,15,154,15,154,15,154,15,154,15,153,15,153,15,153,15,153,15,153,15,153,15,153,15,153,15,153,14,153,14,153,14,153,14,151,14,151,14,150,12,150,12,150,11,149,10,149,10,149,10,149,10,149,9,149,9,9,9,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,10,10,11,12,12,14,14,15,15,17,17,18,18,20,21,22,22,23,23,24,27,28,28,28,28,30,32,32,33,34,35,36,36,39,39,40,41,42,43,45,45,47,48,51,51,53,53,53,55,57,59,60,60,60,61,64,65,66,66,68,70,70,72,73,73,75,76,77,80,81,81,82,84,85,87,89,89,92,94,96,99,101,101,103,107,109,111,114,114,120,123,126,135,168,168,168], [234,238,242,247,247,247,250,254,258,258,258,60,262,66,263,67,264,70,265,72,268,72,268,75,269,75,270,76,271,78,272,81,275,81,275,83,276,84,277,87,278,87,280,91,281,91,281,94,282,95,283,99,283,100,286,102,286,102,286,103,287,105,287,106,288,107,288,107,288,107,288,108,288,109,288,109,288,109,288,111,288,111,288,111,288,111,288,112,288,113,288,113,288,113,288,113,288,113,288,114,288,114,288,114,288,114,288,115,288,115,288,115,288,115,288,115,288,117,288,117,288,117,288,118,288,118,288,118,288,118,288,119,288,119,288,119,288,119,288,119,288,119,288,120,288,120,288,120,288,121,288,123,287,124,287,124,287,124,287,124,287,125,287,125,287,127,287,127,287,127,287,127,286,129,286,130,284,131,284,131,284,132,283,132,283,133,283,135,283,136,282,136,282,136,282,137,282,137,282,138,281,138,281,138,281,139,281,139,280,139,278,141,278,142,278,142,278,142,278,143,277,144,277,276,276,276,276,275,274,274,274,274,274,271,271,271,271,270,270,270,269,269,268,268,268,268,268,268,266,266,266,266,265,264,263,263,263,263,263,262,262,262,262,262,260,260,259,258,258,258,258,257,257,254,254,254,254,253,253,253,253,252,251,250,250,250,250,249,248,248,246,245,245,245,245,244,242,242,242,241,240,240,239,239,239,238,237,235,235,235,235,233,233,233,231,230,230,229,229,228,226,226,226,224,223,221,221,221,220,218,216,215,215,212,211,211,209,209,206,205,204,202,200,199,196,191,191,187])
* dev_get_window (WindowHandle)
* 代码绘制
* 绘制圆
* draw_circle (WindowHandle, Row, Column, Radius)
* 显示绘制的圆
* gen_circle (Circle, Row, Column, Radius)
* 绘制矩形
* draw_rectangle1 (WindowHandle, Row1, Column1, Row2, Column2)
* gen_rectangle1 (Rectangle, Row1, Column1, Row2, Column2)
* 绘制仿射矩形
* draw_rectangle2 (WindowHandle, Row3, Column3, Phi, Length1, Length2)
* gen_rectangle2 (Rectangle1, Row3, Column3, Phi, Length1, Length2)
dev_clear_window ()
read_image (Image, 'clip')
threshold (Image, Region, 10, 80)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 3000, 99999)
count_obj (SelectedRegions, Number)
* 使用select_obj后,选中的区域会变成红色
* dev_display(Image)
* for Index := 1 to Number by 1
* 选中
* select_obj (SelectedRegions, ObjectSelected, Index)
* area_center (ObjectSelected, Area, Row, Column)
* gen_circle (Circle, Row, Column, 30)
* endfor
* 设置多个颜色
* 参数 3,6,12 颜色个数,设置选中区域颜色
dev_set_colored (12)
* 显示原始图
dev_display(Image)
dev_display(SelectedRegions)
* 设置绘制模式
dev_set_draw ('margin')
* 设置线段粗细
dev_set_line_width (3)
* 设置总体颜色,将短线线段颜色修改为白色
dev_set_color ('white')
* 和select_obj不同的地方在于数组的 Index 从 0 开始
for Index := 0 to Number-1 by 1
area_center (SelectedRegions, Area, Row, Column)
gen_circle (Circle, Row[Index], Column[Index], 30)
endfor
练习: 阈值分割+绘制区域+箭头方向
* 读取图像
read_image (Image, 'clip')
* 灰度阈值分割(提取灰度在10~80之间的区域)
threshold (Image, Region, 10, 80)
* 连通域分析(把分割后的区域拆分成多个独立目标)
connection (Region, ConnectedRegions)
* 按面积筛选(去除太小的噪声区域)
* 这里只保留面积在3000~99999之间的目标
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 3000, 99999)
* 获取当前显示窗口句柄(用于后续绘图)
dev_get_window (WindowHandle)
* 统计筛选后目标的数量
count_obj(SelectedRegions, Number)
* ================== 显示区域 ==================
* 设置填充颜色为蓝色
dev_set_color('blue')
dev_set_draw('fill')
* 显示所有选中的区域(实心显示)
dev_display(SelectedRegions)
* ================== 设置方向线样式 ==================
* 设置线条颜色为绿色
dev_set_color('green')
* 设置为边框绘制(只画线,不填充)
dev_set_draw('margin')
* ================== 遍历每个目标 ==================
for Index := 1 to Number by 1
* 取出当前第 Index 个区域
select_obj(SelectedRegions, Region, Index)
* 计算区域的面积和中心点坐标
area_center(Region, Area, Row1, Column1)
* 计算区域的主方向(弧度制)
orientation_region(Region, Angle)
* 设置方向线长度
Length := 80
* 根据方向角计算线的终点
* 注意:Row对应y方向(sin),Column对应x方向(cos)
Row2 := Row1 - Length * sin(Angle)
Column2 := Column1 + Length * cos(Angle)
* 绘制方向主线(从中心指向方向)
disp_line(WindowHandle, Row1, Column1, Row2, Column2)
* ================== 绘制箭头 ==================
* 箭头长度
ArrowLength := 20
* 箭头方向(反向,用于形成箭头头部)
ArrowAngle := Angle + rad(180)
* 箭头两侧线(形成“V”字)
RowA := Row2 - ArrowLength * sin(ArrowAngle + 0.5)
ColA := Column2 + ArrowLength * cos(ArrowAngle + 0.5)
RowB := Row2 - ArrowLength * sin(ArrowAngle - 0.5)
ColB := Column2 + ArrowLength * cos(ArrowAngle - 0.5)
* 绘制箭头两边
disp_line(WindowHandle, Row2, Column2, RowA, ColA)
disp_line(WindowHandle, Row2, Column2, RowB, ColB)
endfor
优化: 上述中使用的是disp_line的方式自己绘制箭头,通过学习,发现Halcon自带绘制箭头的算子disp_arrow,具体下方的二值化阈值分割
二值化阈值分割(自动阈值分割)
*----------------------------------
* 自动二值化阈值分割
*----------------------------------
* 1. 读取图片
read_image (Image, 'clip')
* 获取图像尺寸(宽、高)
get_image_size (Image, Width, Height)
* 关闭已有窗口
dev_close_window ()
* 打开一个新的显示窗口(大小与图像一致)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
* 显示原始图像
dev_display (Image)
* 显示“点击继续”提示
disp_continue_message (WindowHandle, 'black', 'true')
* 程序暂停,等待用户操作
stop()
*----------------------------------
* 2. 自动阈值分割
*----------------------------------
* 自动计算最佳阈值进行二值化
* 参数说明:
* 'max_separability' → 最大类间方差法(类似Otsu)
* 'dark' → 提取暗区域(如果改为 'light' 则提取亮区域)
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
* 连通区域分析(将分割结果分成多个独立区域)
connection (Region, ConnectedRegions)
* 根据面积筛选区域
* 只保留面积在 3300 ~ 99999 之间的目标
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 3300, 99999)
* 再次暂停,方便观察结果
disp_continue_message (WindowHandle, 'black', 'true')
stop()
* 清空窗口
dev_clear_window ()
* 显示原图
dev_display (Image)
* 显示筛选后的区域
dev_display (SelectedRegions)
*----------------------------------
* 3. 绘制方向箭头
*----------------------------------
* 设置绘制模式为边框(只画轮廓)
dev_set_draw ('margin')
* 设置线宽
dev_set_line_width (5)
* 设置颜色为绿色
dev_set_color ('green')
* 计算每个区域的面积和中心坐标
area_center (SelectedRegions, Area, Row, Column)
* 设置箭头长度
Length := 80
* 获取区域个数
count_obj (SelectedRegions, Number)
* 获取区域方向角(弧度制)
orientation_region (SelectedRegions, Angle)
*----------------------------------
* 3.1 使用 Index 遍历(已注释)
*----------------------------------
* for Index := 0 to Number-1 by 1
* 计算箭头终点坐标
* Row2 := Row[Index] - Length * sin(Angle[Index])
* Column2 := Column[Index] + Length * cos(Angle[Index])
* 绘制箭头
* disp_arrow (WindowHandle, Row[Index], Column[Index], Row2, Column2, 3)
* endfor
*----------------------------------
* 3.2 不使用 Index(推荐方式)
*----------------------------------
* HALCON支持元组运算,这里直接整体计算
for Index := 1 to Number by 1
* 从中心点出发,根据方向角计算箭头终点
* Row方向用sin,Column方向用cos
disp_arrow (WindowHandle,
Row,
Column,
Row - Length * sin(Angle),
Column + Length * cos(Angle),
3)
endfor
*----------------------------------
* 4. 在中心点画圆
*----------------------------------
* 生成一个与 Row 长度相同、值全为20的元组(作为半径)
tuple_gen_const (|Row|, 20, Newtuple)
* 说明:
* Row 和 Column 是“元组”(多个点)
* 所以半径也必须是元组(长度一致)
* HALCON绘图规则:
* 1)单值方式:参数都是单个值
* 2)元组方式:参数全部为元组(批量绘制)
* 设置颜色为黄色
dev_set_color ('yellow')
* 在每个中心点画一个圆(半径=20)
gen_circle (Circle, Row, Column, Newtuple)
区域运算
*---------------------------
* 区域运算
*---------------------------
* 读取图像(文件名为 claudia)
read_image (Image, 'claudia')
* 生成一个圆形区域 ROI_0
* 参数:行坐标、列坐标、半径
gen_circle (ROI_0, 66.3852, 218.714, 27.5504)
* 生成一个矩形区域 ROI_01
* 参数:左上角行、列,右下角行、列
gen_rectangle1 (ROI_01, 68.6335, 214.219, 111.35, 304.122)
*---------------------------
* 区域集合运算
*---------------------------
* 求两个区域的交集(重叠部分)
intersection (ROI_0, ROI_01, RegionIntersection)
* 求差集:ROI_0 - ROI_01(圆减去矩形)
difference (ROI_0, ROI_01, RegionDifference1)
* 求差集:ROI_01 - ROI_0(矩形减去圆)
difference (ROI_01, ROI_0, RegionDifference2)
* 求补集:ROI_0 在整幅图像中的反区域(非ROI_0区域)
complement (ROI_0, RegionComplement)
* 求并集:两个区域合并
union2 (ROI_0, ROI_01, RegionUnion)
* 清空显示窗口
dev_clear_window ()
*---------------------------
* 图像通道操作
*---------------------------
* 将彩色图像分解为三个通道(通常是R、G、B)
decompose3 (Image, Image1, Image2, Image3)
* 合并两个通道生成一个多通道图像
compose2 (Image1, Image2, MultiChannelImage)
* 合并三个通道生成一个三通道图像
compose3 (Image1, Image2, Image3, MultiChannelImage1)
* 根据索引获取某一个通道(索引从1开始)
* 这里获取第1个通道(通常是R通道)
access_channel (MultiChannelImage1, Image4, 1)
*---------------------------
* 图像分割(阈值法)
*---------------------------
*(方法1:自动阈值,已注释)
* binary_threshold (Image3, Region, 'max_separability', 'light', UsedThreshold)
* connection (Region, ConnectedRegions)
*(方法2:手动阈值分割)
* 对 Image3 进行灰度阈值分割(147~255)
threshold (Image3, Region, 147, 255)
* 对分割结果进行连通区域分析
connection (Region, ConnectedRegions)
* 根据面积筛选目标区域
* 只保留面积在 1100 到 1200 之间的区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1100, 1200)
练习: 车牌识别z
*----------------------------------
* 基于Blob分析提取车牌区域
*----------------------------------
* 1. 读取图像(汽车图片)
read_image (Image, 'audi2')
* 关闭已有窗口
dev_close_window ()
* 打开一个 512x512 的显示窗口
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
* 显示原始图像
dev_display (Image)
* 显示“点击继续”提示
disp_continue_message (WindowHandle, 'black', 'true')
* 暂停程序
stop ()
*----------------------------------
* 2. 自动阈值分割(Blob提取核心步骤)
*----------------------------------
* 使用自动阈值分割
* 参数说明:
* 'smooth_histo' → 先对直方图平滑,再寻找最佳阈值(抗噪更稳定)
* 'dark' → 提取暗区域(车牌通常偏暗或对比明显)
binary_threshold (Image, Region, 'smooth_histo', 'dark', UsedThreshold)
* 连通域分析(把二值图中的区域分离成多个独立Blob)
connection (Region, ConnectedRegions)
* 根据面积筛选候选区域(车牌大致面积范围)
* 这里只保留面积在 1050~1500 的区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1050, 1500)
* 暂停查看分割效果
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*----------------------------------
* 3. 显示筛选后的车牌候选区域
*----------------------------------
* 设置显示颜色为绿色
dev_set_color ('green')
* 显示原图
dev_display (Image)
* 在图像上叠加显示筛选出的区域(候选车牌)
dev_display (SelectedRegions)
* 暂停观察结果
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*----------------------------------
* 4. 计算Blob特征(用于定位车牌)
*----------------------------------
* 获取候选区域数量(可能有多个)
count_obj (SelectedRegions, Number)
* 计算每个区域的面积和中心坐标
area_center (SelectedRegions, Area, Row, Column)
*----------------------------------
* 5. 标记车牌位置(画圆)
*----------------------------------
* 设置绘制模式为轮廓
dev_set_draw ('margin')
* 设置绘制颜色为红色
dev_set_color ('red')
* 设置线宽
dev_set_line_width (3)
* 遍历每个候选区域
for Index := 1 to Number by 1
* 在每个区域中心画一个圆(半径=35)
* 用于标记车牌位置
gen_circle (Circle, Row, Column, 35)
endfor
数据格式化操作
*----------------------------------
* 数据格式化操作(tuple转字符串)
* 使用 $ 运算符进行格式化
*----------------------------------
* 八进制格式(以0开头)
* 123 → 0173
a := 123$'#o'
* 十六进制(小写)
* 123 → 0x7b
b := 123$'#x'
* 十六进制(大写)
* 123 → 0X7B
c := 123$'#X'
*----------------------------------
* 浮点数格式
*----------------------------------
* 默认浮点格式(保留6位小数)
* 123 → 123.000000
d := 123$'#f'
* 指定保留2位小数
* 123 → 123.00
e := 123$'#.2f'
*----------------------------------
* 字符串宽度控制
*----------------------------------
* 总宽度为6,不够前面补空格(右对齐)
* " 123"
f := 123$'6'
* 总宽度为6,左对齐(后面补空格)
* "123 "
g := 123$'-6'
*----------------------------------
* 科学计数法
*----------------------------------
* 使用科学计数法(小写e)
* 123 → 1.230000e+02
h := 123$'#e'
元组和字典
*----------------------------------
* 1. 元组(数组)操作
*----------------------------------
* 定义一个元组(类似数组)
arr := [1,2,3]
* 获取第0个元素(HALCON索引从0开始)
a := arr[0]
* 给第4个位置赋值(索引3)
* 注意:HALCON会自动扩展元组
* 结果:arr = [1,2,3,10]
arr[3] := 10
*----------------------------------
* 删除元素
*----------------------------------
* 删除索引为0的元素
* 结果:Reduced = [2,3,10]
tuple_remove (arr, 0, Reduced)
*----------------------------------
* 插入元素
*----------------------------------
* 定义一个字符串元组
arr1 := ['明天不上课','后天是自习']
* 在索引1位置插入arr1
* 原: [1,2,3,10]
* 新: [1,'明天不上课','后天是自习',2,3,10]
tuple_insert (arr, 1, arr1, Extended)
*----------------------------------
* 2. 字典(Dict)操作
*----------------------------------
* 创建一个字典句柄
create_dict (DictHandle)
*----------------------------------
* 2.1 字典赋值(存数据)
*----------------------------------
* 存储字符串
set_dict_tuple (DictHandle, 'Name', 'Junglezt')
* 存储数字
set_dict_tuple (DictHandle, 'age', 22)
* 存储元组(列表)
set_dict_tuple (DictHandle, 'like', ['beautiful girl','computer skill','fitness'])
* 生成一个矩形区域
gen_rectangle1 (Rectangle, 30, 20, 100, 200)
* 将区域对象存入字典(注意:对象用 set_dict_object)
set_dict_object (Rectangle, DictHandle, 'rect')
*----------------------------------
* 2.2 获取字典数据
*----------------------------------
* 获取字符串
get_dict_tuple (DictHandle, 'Name', Name)
* 获取数字
get_dict_tuple (DictHandle, 'age', age)
* 获取元组
get_dict_tuple (DictHandle, 'like', like)
* 获取区域对象
get_dict_object (MyRect, DictHandle, 'rect')
*stop()
* 清空窗口
dev_clear_window ()
* 显示取出的区域
dev_display (MyRect)
*----------------------------------
* 获取所有键(key)
*----------------------------------
* 返回字典中所有key
get_dict_param (DictHandle, 'keys', [], GenParamValue)
*----------------------------------
* 2.3 删除键
*----------------------------------
* 删除区域对象
remove_dict_key (DictHandle, 'rect')
* 删除元组数据
remove_dict_key (DictHandle, 'like')2
作业1: 匹配路由器孔洞
read_image (Image, 'progres.png')
dev_get_window (WindowHandle)
dev_set_line_width (3)
dev_set_color ('green')
dev_set_draw ('margin')
* 绘制仿射矩形
* 选择区域
draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
* 生成矩形
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
* ROI 获取感兴趣区域
reduce_domain (Image, Rectangle, ImageReduced)
* 裁剪图像
*crop_domain (ImageReduced, ImagePart)
disp_continue_message (WindowHandle, 'black', 'true')
stop()
* 阈值分割
binary_threshold (ImageReduced, Region, 'max_separability', 'dark', UsedThreshold)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 20, 30)
disp_continue_message (WindowHandle, 'black', 'true')
stop()
* 获取数量
count_obj (SelectedRegions, Number)
* 获取半径
smallest_circle (SelectedRegions, Row1, Column1, Radius)
dev_display (Image)
dev_display (SelectedRegions)
dev_disp_text ('数量:' + Number, 'image', 150,200, 'black', [], [])
R := Radius[0]
Text := '半径' + R$'.2f'
dev_disp_text (Text, 'image', 200, 200, 'black', [], [])
作业2: 匹配主板进行定位
read_image (Image, 'die_pads')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (50, 500, Width * 2, Height * 2, 'black', WindowHandle)
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 二值化阈值分割
binary_threshold (Image, Region, 'smooth_histo', 'light', UsedThreshold)
connection (Region, ConnectedRegions)
dev_clear_window ()
dev_display (Image)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 220, 1000)
stop ()
* 获取中心点
area_center (SelectedRegions, Area, Row, Column)
* 获取角度
orientation_region (SelectedRegions, Angle)
* 获取数量
count_obj (SelectedRegions, Number)
* 获取边框
gen_contour_region_xld (SelectedRegions, Contours, 'border')
dev_display (Image)
dev_display (Contours)
stop ()
* 定义箭头长度
dev_set_color ('red')
Length := 30
for Index := 1 to Number by 1
* 使用disp_arrow绘制的箭头在拖动图片时会消失
* 使用gen_arrow_contour_xld 绘制的箭头在拖动图片时不会消失
*disp_arrow (WindowHandle, Row, Column, Row - Length * sin(Angle), Column + Length * cos(Angle), 1)
gen_arrow_contour_xld (Arrow, Row, Column, Row - Length * sin(Angle), Column + Length * cos(Angle), 5, 5)
endfor
作业3: 三角形阈值分割
* 读取图像
read_image(Image, 'D:/桌面/Halcon/day02/triangleBlob.jpg')
* 将RGB图像转换为灰度图
rgb1_to_gray (Image, GrayImage)
* ---------------------------
* 全局阈值分割(自动阈值)
* ---------------------------
* 使用最大类间方差法(类似大津法)进行二值化
* 'dark' 表示提取较暗区域
binary_threshold (GrayImage, Region, 'max_separability', 'dark', UsedThreshold)
* 限制后续处理区域,提高效率
reduce_domain (GrayImage, Region, ImageReduced)
* ---------------------------
* 均值滤波(生成背景图)
* ---------------------------
* 使用较大的窗口进行平滑,相当于生成“背景亮度图”
* 参数 (100, 3) 表示横向100,纵向3的滤波窗口
mean_image (ImageReduced, ImageMean, 100, 3)
* ---------------------------
* 动态阈值分割(重点)
* ---------------------------
* dyn_threshold 的核心思想:
* 将原图 GrayImage 与 平滑图 ImageMean 进行逐像素比较
*
* 参数说明:
* dyn_threshold (Image, ThresholdImage, RegionDynThresh, Offset, LightDark)
*
* 1. Image:原始图像(GrayImage)
* 2. ThresholdImage:参考图像(这里是 ImageMean,表示局部背景)
* 3. RegionDynThresh:输出区域
* 4. Offset:偏移量(阈值差)
* 5. 'light' 或 'dark':
* - 'light':提取比背景“更亮”的区域
* - 'dark':提取比背景“更暗”的区域
*
* 工作原理(非常重要):
* 对每个像素做如下判断:
*
* 如果选择 'light':
* GrayImage(x,y) > ImageMean(x,y) + Offset
*
* 如果选择 'dark':
* GrayImage(x,y) < ImageMean(x,y) - Offset
*
* 本例中:
* dyn_threshold (GrayImage, ImageMean, RegionDynThresh, 5, 'light')
*
* 含义是:
* 提取“比局部背景亮至少 5 灰度值”的区域
*
* 优点:
* ✔ 适用于光照不均匀情况
* ✔ 比全局阈值更稳定
* ✔ 能检测局部亮/暗目标
*
* Offset = 5:
* - 越小:检测更敏感(容易噪声)
* - 越大:检测更严格(可能漏检)
dyn_threshold (GrayImage, ImageMean, RegionDynThresh, 5, 'light')
* ---------------------------
* 形态学闭运算
* ---------------------------
* 填补小孔、连接断裂区域
closing_circle (RegionDynThresh, RegionClosing, 3.5)
* ---------------------------
* 连通区域分析
* ---------------------------
connection (RegionClosing, ConnectedRegions)
* ---------------------------
* 根据面积筛选目标
* ---------------------------
* 只保留面积在 1400~1500 的区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1400, 1500)
* ---------------------------
* 转换为轮廓(用于显示)
* ---------------------------
gen_contour_region_xld (SelectedRegions, Contours, 'border')
* 显示原图
dev_display (Image)
* 显示轮廓
dev_display (Contours)
轮廓提取
* =========================
* 1. 读取图像
* =========================
read_image(Image, 'fabrik')
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
* 创建一个窗口,并根据图像大小自动适配窗口尺寸
dev_display (Image)
* =========================
* 3. 初步阈值分割
* =========================
threshold (Image, Region, 80, 110)
* 对灰度图进行阈值分割:
* 保留灰度值在 [80,110] 之间的像素区域
* 输出为二值区域 Region
connection (Region, ConnectedRegions)
* 将二值区域拆分为多个连通区域(每个独立目标)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 40000, 99999)
* 根据面积筛选区域:
* 只保留面积在 40000~99999 像素之间的目标
* 目的是去掉小噪声和过大的无关区域
* =========================
* 6. 开运算(去噪 + 平滑)
* =========================
opening_circle (SelectedRegions, RegionOpening, 3.5)
* 圆形开运算 = 腐蚀 + 膨胀
* 半径 3.5:
* - 去除小噪声
* - 平滑边界
* - 保留主要结构
* =========================
* 7. 形状转换
* =========================
shape_trans (RegionOpening, RegionTrans, 'rectangle1')
* 将区域转换为最小外接矩形(轴对齐)
* 用矩形近似原始目标区域
* 常用于ROI提取
* =========================
* 8. 限制处理区域(ROI)
* =========================
reduce_domain (Image, RegionTrans, ImageReduced)
* 将图像限制在矩形区域内(ROI)
* 提高后续处理效率
* 避免背景干扰
* =========================
* 9. 二次阈值分割(精细分割)
* =========================
threshold (ImageReduced, Region1, 80, 255)
* 在ROI内进行更宽范围的阈值分割
* 提取目标内部更完整的区域
* =========================
* 10. 提取轮廓(内轮廓)
* =========================
boundary (Region1, RegionBorder, 'inner')
* 提取区域的“内边界”
* 边界位于区域内部一圈像素
* =========================
* 11. 提取轮廓(外轮廓)
* =========================
boundary (RegionBorder, RegionBorder1, 'outer')
* 再对内轮廓做一次外边界提取
* 得到更外层的一圈轮廓
保存图片
* =========================
* 【1】读取图像
* =========================
read_image (Image, 'printer_chip/printer_chip_01')
* 获取当前窗口句柄
dev_get_window (WindowHandle)
* 显示图像(否则dump_window可能是空的)
dev_display (Image)
* 显示文字标注
dev_disp_text ('hello', 'window', 'top', 'left', 'black', [], [])
* =========================
* 【2】方式1:直接导出窗口(带标注)
* =========================
dump_window (WindowHandle, 'bmp', 'test')
* 👉 保存内容 = 图像 + 所有显示的标注
* =========================
* 【3】方式2:保存原图(不带标注)
* =========================
write_image (Image, 'tiff', 0, 'output1')
* 👉 只保存原始图像数据
* =========================
* 【4】方式3:窗口转图像再保存(推荐)
* =========================
dump_window_image (ImageWithOverlay, WindowHandle)
write_image (ImageWithOverlay, 'tiff', 0, 'output2')
* 👉 保存带标注图像(更灵活,可继续处理)
生成棋盘格
* =========================
* 【1】生成棋盘格区域
* =========================
gen_checker_region (RegionChecker, 511, 511, 32, 32)
* 511x511:整体尺寸
* 32x32:每个格子大小
* =========================
* 【2】区域转二值图像
* =========================
region_to_bin (RegionChecker, BinImage, 255, 0, 512, 512)
* 前景=255(白)
* 背景=0(黑)
* 输出图像尺寸512x512
* 👉 得到标准黑白棋盘格图像
图像裁剪
* =========================
* 【0】读取图像
* =========================
read_image (Image2, 'monkey')
* =========================
* 【1】方式一:crop_part(直接裁剪)
* =========================
crop_part (Image2, ImageCrop, 40, 150, 210, 400)
* 参数说明:
* 40 -> 起始行(row)
* 150 -> 起始列(column)
* 210 -> 高度
* 400 -> 宽度
* 👉 特点:
* - 直接按坐标裁剪
* - 输出图像尺寸 = 210x400
* - 原图信息被“物理裁掉”
* =========================
* 【2】方式二:reduce_domain(限制处理区域)
* =========================
* ① 生成ROI区域
gen_rectangle1 (Rectangle, 40, 150, 250, 550)
* ② 限制图像处理范围
reduce_domain (Image2, Rectangle, ImageReduced)
* 👉 特点:
* - 图像尺寸不变
* - 仅限制运算区域
* - 非ROI区域仍存在(但不参与处理)
* =========================
* 【3】方式三:crop_domain(按ROI真正裁剪)
* =========================
* 在reduce_domain基础上进一步裁剪
crop_domain (ImageReduced, ImageCropDomain)
* 👉 特点:
* - 根据当前domain(ROI)自动裁剪最小外接矩形
* - 输出图像尺寸变小
* - 相当于:
* reduce_domain + 自动crop
* 👉 使用前提:
* 必须先有有效的domain(比如reduce_domain之后)
* =========================
* 【4】推荐组合(工程常用)
* =========================
reduce_domain (Image2, Rectangle, ImageReduced)
crop_domain (ImageReduced, ImageFinal)
* 👉 优点:
* - 先限制计算范围(提升速度)
* - 再输出最小ROI图像(干净)
阈值分割算法
* 读取示例图像(芯片焊盘)
read_image (Image, 'die_pads')
* 获取图像尺寸
get_image_size (Image, Width, Height)
*==========================
* 1. 基本阈值分割
*==========================
* 按灰度范围提取区域(标准逐像素判断)
threshold (Image, Region, 128, 255)
*==========================
* 2. 快速阈值分割(可选)
*==========================
* fast_threshold:
* - 在局部窗口(如20x20)内判断中心像素
* - 不逐像素精确判断 → 速度更快
* - 适用于目标较大、对精度要求不高的场景
*
* fast_threshold (Image, Region, 128, 255, 20)
*==========================
* 3. 图像平滑(用于动态阈值)
*==========================
* 均值滤波(平滑图像)
* 参数10,10 表示滤波窗口大小
* 值越大 → 图像越模糊(背景估计更平滑)
*
* mean_image (Image, ImageMean, 10, 10)
*==========================
* 4. 动态阈值分割(抗光照不均)
*==========================
* dyn_threshold:
* - Image:原图
* - ImageMean:平滑后的图(背景)
* - Region:输出区域
* - Offset:偏移值(类似阈值)
* - 'light':提取比背景亮的区域
*
* 原理类似:原图 - 背景(有点像“顶帽”思想)
*
* dyn_threshold (Image, ImageMean, Region, 10, 'light')
*==========================
* 5. 连通域分析
*==========================
* 将二值区域分割成多个连通区域
connection (Region, ConnectedRegions)
*==========================
* 6. 按形状筛选
*==========================
* anisometry:外接矩形长轴 / 短轴(形状细长程度)
*
* 条件:
* - 面积 ≥ 150
* - anisometry 在 1~2 之间(接近矩形)
*
select_shape (ConnectedRegions, SelectedRegions, \
['area','anisometry'], 'and', \
[150,1], [9999,2])
*==========================
* 7. 填充区域
*==========================
* 填充内部空洞(让区域变成实心)
fill_up (SelectedRegions, RegionFillUp)
*==========================
* 8. 形状转换
*==========================
* 转换为最小外接矩形(带角度)
* rectangle2 → 带方向的矩形
shape_trans (RegionFillUp, RegionTrans, 'rectangle2')
*==========================
* 9. 计算方向
*==========================
* 获取区域主方向角(弧度制)
orientation_region (SelectedRegions, Phi)
*==========================
* 10. 获取几何信息
*==========================
length := 30
* 获取区域中心点
area_center (RegionTrans, Area, Row, Column)
* 获取窗口句柄(用于显示)
dev_get_window (WindowHandle)
*==========================
* 11. 提取边界
*==========================
* 提取内边界轮廓
boundary (RegionTrans, RegionBorder, 'inner')
*==========================
* 12. 显示结果
*==========================
dev_display (Image)
dev_display (RegionBorder)
*==========================
* 13. 绘制方向箭头
*==========================
* 从中心点出发,沿着方向 Phi 画箭头
* 行(Row)方向用 sin
* 列(Column)方向用 cos
*
disp_arrow (WindowHandle, \
Row, Column, \
Row - length * sin(Phi), \
Column + length * cos(Phi), \
1)
形态学调整
*图形预处理
*腐蚀 膨胀 打开 关闭 顶帽 底帽
read_image (Image, 'printer_chip/printer_chip_01')
threshold (Image, Region, 128, 255)
*圆形的腐蚀:
*3.5腐蚀区域的半径
erosion_circle (Region, RegionErosion, 3.5)
*形态学膨胀
dilation_circle (RegionErosion, RegionDilation, 3.5)
*打开运算 先腐蚀后膨胀
opening_circle (Region, RegionOpening,3.5)
*关闭运算 先膨胀再腐蚀
closing_circle (Region, RegionClosing, 11.5)
read_image (Image1, 'clip')
threshold (Image1, Region1, 10, 80)
gen_circle (Circle, 200, 200, 3.5)
*参数1 传入的区域
*参数2 结构图 可以使用gen_circle等绘制出来结构图
*参数3 输出的区域
*参数4 形态学操作迭代次数,1 形态学操作一次
dilation1 (Region1, Circle, RegionDilation1, 1)
*dilation_circle (Region1, RegionDilation2, 3.5)// 等同于上面这俩句
顶帽和底帽
read_image (Image, 'fuse')
get_image_size (Image, Width, Height)
*创建一个SE结构图
*byte 创建一个结构转成byte类型的图片
* 100 、100 结构图的大小
*最后一个参数 结构图中间灰度值
gen_disc_se (SE, 'byte',100, 100, 255)
*获取像素点灰度值 原图中心点灰度值
get_grayval (Image, Width/2, Height/2, Grayval) //247
*对原始图片进行开运算 结构图是顶帽的结构图
gray_opening ( Image,SE, ImageOpening)
get_grayval (ImageOpening,Width/2, Height/2, Grayval2)//247
*顶帽:顶帽之后的图= 原始图片-gray_opening(打开运算之后的图)
*顶帽使用的场景:提取图像当中的微小的亮斑(如医学上影像中病灶、工业检测中亮的缺陷)
*参数1 输入图片
*参数2 输入结构图
*参数3 经过顶帽之后的处理图
gray_tophat (Image, SE, ImageTopHat)
*获取顶帽之后的图中心点的灰度值
get_grayval (ImageTopHat, Width/2, Height/2, Grayval1)//0
*底冒
*底帽之后的图= 原始图片-gray_closing(闭运算之后的图)
*底帽使用的场景:提取图像当中的微小的暗斑(如医学上影像中肿瘤、工业检测中暗的缺陷)
gray_bothat (Image, SE, ImageBotHat)
作业1: 电路板提取
* 课堂练习
* 读取图像
read_image (Image, 'die/die_03')
* 生成一个矩形ROI(感兴趣区域)
* 参数:上行、左列、下行、右列
gen_rectangle1 (Rectangle, 100, 2, 150, 664)
* 将图像限制在ROI区域内(只处理该区域)
reduce_domain (Image, Rectangle, ImageReduced)
* 对ROI区域进行灰度阈值分割
* 提取灰度值在15~40之间的区域
threshold (ImageReduced, Region, 15, 40)
* 将连通区域分离(把粘在一起的区域拆开)
connection (Region, ConnectedRegions)
* 根据面积筛选目标区域
* 只保留面积在900~1500之间的区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 900, 1500)
* 将选中的区域转换为“内接圆”区域
* 相当于用圆来近似这些目标
shape_trans (SelectedRegions, RegionTrans, 'inner_circle')
* 计算每个区域的最小外接圆
* 输出:圆心行(Row)、列(Column)、半径(Radius)
smallest_circle (RegionTrans, Row, Column, Radius)
* 统计目标区域的个数
count_obj (RegionTrans, Number)
* 显示原图
dev_display (Image)
* 显示检测到的圆形区域
dev_display (RegionTrans)
* 遍历每个检测到的目标
for Index := 1 to Number by 1
* 在图像上显示半径(保留2位小数)
* 显示位置:圆心上方50像素
dev_disp_text (Radius$'.2f', 'image', Row - 50, Column, 'black', [], [])
endfor
老师的方法
*关闭窗体的实时更新 等待dev_disp() 统一更新窗体,既提高了算子执行速度也防止窗体闪烁的问题
dev_update_window ('off')
dev_close_window ()
dev_open_window (0, 0, 512, 512, 'black', WindowHandle)
read_image (Image, 'die/die_03')
set_display_font (WindowHandle, 20, 'mono', 'true', 'false')
dev_display (Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*********主要是为了提取一个感兴趣区域********************
threshold (Image, Region, 100, 255)
shape_trans (Region, RegionTrans, 'rectangle2')
reduce_domain (Image, RegionTrans, ImageReduced)
dev_display (ImageReduced)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*****************************阈值分割
threshold (ImageReduced, Region1, 10, 70)
*填充面积范围在0-100之间区域
fill_up_shape (Region1, RegionFillUp, 'area', 1, 100)
dev_set_draw ('fill')
dev_display (Image)
dev_display (RegionFillUp)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
************************
opening_circle (RegionFillUp, RegionOpening, 15.5)
connection (RegionOpening, ConnectedRegions)
*'circularity' 圆形的设置
select_shape (ConnectedRegions, SelectedRegions, 'circularity', 'and', 0.80, 1)
*排序区域
*first_point 排序时候参考的属性 第一个点的坐标
*'true' 升序排列
*'column' 列坐标进行
sort_region (SelectedRegions, SortedRegions, 'first_point', 'true', 'column')
dev_display (Image)
dev_display (SortedRegions)
************计算
*获取外接圆的坐标和半径
smallest_circle (SortedRegions, Row, Column, Radius)
zhijing:=Radius*2
*绘制一个圆
gen_circle (Circle, Row, Column, Radius)
dev_display (Image)
dev_display (Circle)
dev_disp_text (zhijing$'.2f', 'image', Row-40, Column-15, 'black', [], [])
dev_update_window ('on') //开启实时更新
作业2: 树桩提取
* 作业
* 读取本地图像(树的图片)
read_image (Image, 'D:/桌面/Halcon/day03/tree.jpg')
* 获取当前显示窗口句柄
dev_get_window (WindowHandle)
* 显示“点击继续”提示
disp_continue_message (WindowHandle, 'black', 'true')
* 程序暂停(等待手动继续)
stop ()
* 将RGB彩色图像转换为灰度图
rgb1_to_gray (Image, GrayImage)
* 再次显示继续提示
disp_continue_message (WindowHandle, 'black', 'true')
stop()
* 对灰度图进行阈值分割
* 提取灰度值在68~206之间的区域(一般是树冠区域)
threshold (GrayImage, Regions, 68, 206)
* 使用圆形结构元素进行腐蚀
* 半径4.5:去除小噪声、缩小区域
erosion_circle (Regions, RegionErosion, 4.5)
* 开运算(先腐蚀再膨胀)
* 半径3.5:去除细小干扰、平滑边界
opening_circle (RegionErosion, RegionOpening, 3.5)
* 连通域分析(分离不同目标)
connection (RegionOpening, ConnectedRegions)
* 按面积筛选区域
* 只保留面积大于200的目标(过滤小噪点)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 200, 99999)
* 清空窗口
dev_clear_window()
* 显示原图
dev_display (Image)
* 显示筛选后的区域
dev_display (SelectedRegions)
* 提示继续
disp_continue_message (WindowHandle, 'black', 'true')
stop()
* 填充区域内部(去除孔洞)
fill_up (SelectedRegions, RegionFillUp)
* 转换为凸包区域(让形状更规则)
* 'convex':生成最小凸多边形
shape_trans (RegionFillUp, RegionTrans, 'convex')
* 暂停观察结果
stop()
* 计算最小外接圆
* 输出:圆心(Row1, Column1),半径Radius
smallest_circle (RegionTrans, Row1, Column1, Radius)
* 在图像上显示半径(保留2位小数)
* 显示在圆心位置
dev_disp_text (Radius$'.2f', 'image', Row1, Column1, 'black', [], [])
图形增强
* ==============================
* 图像增强(参数说明版注释)
* ==============================
read_image (Image, 'printer_chip/printer_chip_01')
get_image_size (Image, Width, Height)
dev_display (Image)
* 1 灰度反转
get_grayval (Image, 100, 100, Grayval1)
invert_image (Image, ImageInvert)
* Image 输入图像
* ImageInvert 输出图像(灰度反转后)
* 简单原理:g = 255 - f
get_grayval (ImageInvert, 100, 100, Grayval2)
* 2 对比度增强(锐化)
emphasize (ImageInvert, ImageEmphasize, 100, 100, 100)
* ImageInvert 输入图像
* ImageEmphasize 输出图像(增强后)
* 100,100 滤波窗口大小(作用范围)
* 100 增强强度
* 简单原理:原图 + 边缘(高频信息)
* 3 灰度线性缩放
get_grayval (ImageInvert, 100, 100, Grayval3)
scale_image (ImageInvert, ImageScaled, 1, -255)
* ImageInvert 输入图像
* ImageScaled 输出图像
* 1 乘数(对比度)
* -255 加数(亮度)
* 简单原理:g = f * Mult + Add
get_grayval (ImageScaled, 100, 100, Grayval4)
* 4 自动灰度拉伸
scale_image_max (ImageInvert, ImageScaleMax)
* ImageInvert 输入图像
* ImageScaleMax 输出图像(拉伸后)
* 简单原理:最小值→0,最大值→255
* 5 对数变换
get_grayval (ImageInvert, 100, 100, Grayval5)
log_image (ImageInvert, LogImage, 2)
* ImageInvert 输入图像
* LogImage 输出图像
* 2 对数底数
* 简单原理:g = log_base(f)
get_grayval (LogImage, 100, 100, Grayval6)
* 6 幂次变换
get_grayval (Image, 247, 217, Grayval7)
pow_image (Image, PowImage, 2)
* Image 输入图像
* PowImage 输出图像(real类型)
* 2 幂次(Gamma)
* 简单原理:g = f^Gamma
get_grayval (PowImage, 247, 217, Grayval8)
* 灰度自动设置
scale_image_max (PowImage, ImageScaleMax1)
get_grayval (ImageScaleMax1, 247, 217, Grayval9)
获取灰度直方图
read_image (Image, 'clip')
get_image_size (Image, Width, Height)
dev_display (Image)
* 获取灰度直方图
gray_histo (Image, Image, AbsoluteHisto, RelativeHisto)
* Image 输入图像
* Image 区域(此处为整幅图像)
* AbsoluteHisto 输出:绝对直方图(像素个数)
* RelativeHisto 输出:相对直方图(百分比)
* 简单原理:统计每个灰度值(0~255)的像素分布
count:= AbsoluteHisto[10]
count1:= RelativeHisto[10]
* 获取灰度值区间
min_max_gray (Image, Image, 0, Min, Max, Range)
* Image 输入图像
* Image 区域
* 0 忽略的灰度值(一般填0)
* Min 最小灰度值
* Max 最大灰度值
* Range 灰度范围
* 简单原理:扫描区域内灰度,得到最小/最大值
* 绘制直方图
gen_region_histo (Region, AbsoluteHisto, 255, 255, 1)
* Region 输出区域(直方图区域)
* AbsoluteHisto 输入直方图数据
* 255,255 图像尺寸(宽、高)
* 1 缩放因子
* 简单原理:将直方图数据转换为可显示的区域
* 直方图均衡化(增强对比度)
equ_histo_image (Image, ImageEquHisto)
* Image 输入图像
* ImageEquHisto 输出图像(均衡化后)
* 简单原理:重新分布灰度,使直方图更均匀
中值滤波和均值滤波
* 中值滤波和均值滤波
read_image (Image, '1')
* 创建高斯噪声分布
gauss_distribution (10, Distribution)
* 10 噪声强度(值越大噪声越多)
* Distribution 输出噪声分布
* 简单原理:生成服从高斯分布的随机噪声
* 添加高斯噪声
add_noise_distribution (Image, ImageNoise, Distribution)
* Image 输入图像
* ImageNoise 输出图像(加噪后)
* Distribution 噪声分布
* 简单原理:按分布将随机噪声叠加到图像
* 均值滤波(去高斯噪声)
mean_image (ImageNoise, ImageMean, 3, 3)
* ImageNoise 输入图像(含噪声)
* ImageMean 输出图像(滤波后)
* 3,3 滤波核大小(一般用奇数)
* 简单原理:邻域像素求平均值替代当前像素
rgb1_to_gray (Image , GrayImage)
* 创建椒盐噪声
sp_distribution (5, 5, Distribution1)
* 5,5 椒盐噪声比例(黑点/白点)
* Distribution1 输出噪声分布
* 简单原理:随机产生黑白噪声点
* 添加椒盐噪声
add_noise_distribution (GrayImage, ImageNoise1, Distribution1)
* 中值滤波(去椒盐噪声)
median_image (ImageNoise1, ImageMedian, 'square', 1, 'cyclic')
* ImageNoise1 输入图像(含噪声)
* ImageMedian 输出图像(滤波后)
* 'square' 滤波核形状(square / circle)
* 1 半径(决定核大小)
* 'cyclic' 边界处理方式(循环取值)
* 简单原理:邻域像素排序后取中值替代当前像素
高斯滤波
* ==============================
* 频域高斯滤波(带简要原理)
* ==============================
read_image (Image, 'printer_chip/printer_chip_01')
get_image_size (Image, Width, Height)
dev_display (Image)
gauss_distribution (100, Distribution)
* 100 噪声强度
* Distribution 输出噪声分布
* 简单原理:生成高斯分布随机噪声
add_noise_distribution (Image, ImageNoise, Distribution)
* Image 输入图像
* ImageNoise 输出图像(加噪)
* Distribution 噪声分布
* 简单原理:将高斯噪声叠加到图像
dev_display (ImageNoise)
* =========================================
* 1 创建高斯滤波核(频域)
* =========================================
gen_gauss_filter (ImageGauss, 1, 1, 0, 'n', 'rft', Width, Height)
* ImageGauss 输出高斯滤波核
* 1,1 σx σy(标准差,越小→核越集中,平滑弱)
* 0 方向角
* 'n' 归一化(保证滤波后亮度不变)
* 'rft' 频域格式
* Width,Height 滤波核尺寸
* 简单原理:生成频域中的高斯低通滤波器
* =========================================
* 2 傅里叶变换(空域 → 频域)
* =========================================
rft_generic (ImageNoise, ImageFFT, 'to_freq', 'none', 'complex', Width)
* ImageNoise 输入图像(空域)
* ImageFFT 输出频域图像
* 'to_freq' 正变换
* 'none' 不额外处理
* 'complex' 输出复数(实部+虚部)
* Width 图像宽度
* 简单原理:将图像转换为频率表示(低频+高频)
* =========================================
* 3 频域滤波(卷积)
* =========================================
convol_fft (ImageFFT, ImageGauss, ImageConvol)
* ImageFFT 输入频域图像
* ImageGauss 高斯滤波核
* ImageConvol 输出频域结果
* 简单原理:频域相乘 = 空域卷积
* =========================================
* 4 傅里叶逆变换(频域 → 空域)
* =========================================
rft_generic (ImageConvol, ImageFFT1, 'from_freq', 'none', 'byte', Width)
* ImageConvol 输入频域图像
* ImageFFT1 输出空域图像
* 'from_freq' 逆变换
* 'byte' 输出为byte类型
* Width 图像宽度
* 简单原理:将频域结果还原为空间图像
上述代码主要是
- 图像加了高斯噪声 → 再用高斯滤波把噪声“抹平”
本质就是: 让随机噪声变得不明显,让图像更平滑
如果不太理解,详细步骤简单理解如下:
第一步:生成一个高斯核,中间的权重比较大,如下
1 2 1
2 4 2
1 2 1
第二步:傅里叶变换(空域 → 频域)
空域就是我们的原始图像,频域就是频率图像,也就是说从像素图像转换为了频率图像
通过转换,我们的图片不同区域的频率转换结果如下:
| 内容 | 频率 |
|---|---|
| 大块平滑区域 | 低频 |
| 边缘/细节 | 高频 |
| 噪声 | 很高频 |
把图片像音谱一样拆分为了低频和高频
低频(主体) + 高频(细节 + 噪声)
第三步:频域滤波(convol_fft)
使用第一步生成的高斯核对频率进行运算,实现过滤效果
本质上就是保留低频率,去除高频率 -> 低频滤波器
将图片里杂乱抖动(噪声)过滤掉,只留下平滑的部分。
第四步:逆傅里叶变换(频域 → 空域)
最后一步将使用高斯核滤波后的频率图,也就是频域转换回滤波后的空域(图像)
最后会得到一张:
更平滑、更干净、噪声更少的图像
想象一下音乐的场景,加深印象:
音频降噪
1️⃣ 把声音变成频谱
2️⃣ 找到“刺耳噪声”(高频)
3️⃣ 把这些频率压掉
4️⃣ 再还原声音
图像运算 + 边缘检测
* 图像运算
read_image (Image1, 'printer_chip/printer_chip_01')
read_image (Image2, 'printer_chip/printer_chip_02')
get_grayval (Image1, 200, 200, Grayval1)
get_grayval (Image2, 200, 200, Grayval2)
* 图像加法
add_image (Image1, Image2, ImageResult, 0.5, 0)
* Image1 输入图像1
* Image2 输入图像2
* ImageResult 输出图像
* 0.5 乘数因子(控制叠加强度)
* 0 加法偏移
* 简单原理:g = (f1 + f2) * Mult + Add
get_grayval (ImageResult, 200, 200, Grayval3)
* 图像减法
sub_image (Image1, Image2, ImageSub, 1, 128)
* Image1 输入图像1
* Image2 输入图像2
* ImageSub 输出图像
* 1 乘数因子
* 128 偏移(避免负值)
* 简单原理:g = (f1 - f2) * Mult + Add
get_grayval (ImageSub, 200, 200, Grayval4)
* 图像乘法
mult_image (Image1, Image2, ImageResult1, 0.005, 0)
* Image1 输入图像1
* Image2 输入图像2
* ImageResult1 输出图像
* 0.005 缩放因子(防止溢出)
* 0 偏移
* 简单原理:g = (f1 × f2) * Scale + Add
* 图像除法
div_image (Image1, Image2, ImageResult2, 255, 0)
* Image1 输入图像1(被除数)
* Image2 输入图像2(除数)
* ImageResult2 输出图像
* 255 缩放因子
* 0 偏移
* 简单原理:g = (f1 / f2) * Scale + Add
* Sobel边缘检测(锐化)
sobel_amp (Image1, EdgeAmplitude, 'thin_sum_abs', 11)
* Image1 输入图像
* EdgeAmplitude 输出边缘强度图
* 'thin_sum_abs' 细边缘(|dx| + |dy|,带细化)
* 'sum_abs' |dx| + |dy|(边缘较粗)
* 'sum_sqrt' sqrt(dx^2 + dy^2)(标准梯度幅值)
* 'thin_max_abs' 细边缘(max(|dx|,|dy|),更细更干净)
* 11 滤波核大小(越大边缘越平滑/越粗)
* 简单原理:计算灰度变化(梯度),突出边缘(高频)
边缘检测原理:
找图像中“变化最明显”的地方(亮变暗、暗变亮的位置)
一般最常见的算法原理为:
通过计算水平和垂直方向的灰度变化(梯度)来找边缘
有几个常见的算法
| 算法(Algorithm) | 一句话原理 | 特点 |
|---|---|---|
| Sobel(索贝尔) | 计算水平和垂直灰度变化(梯度)找边缘 | 简单稳定,边缘偏粗 |
| Prewitt(普鲁伊特) | 类似Sobel,用简单权重计算梯度 | 更简单,抗噪较差 |
| Laplace(拉普拉斯) | 用二阶导数找灰度突变(不分方向) | 全方向,易受噪声影响 |
| Canny(坎尼) | 去噪+梯度+细化+筛选得到边缘 | 最精确,效果最好 |
| Roberts(罗伯茨) | 通过对角线灰度差检测边缘 | 最简单,噪声敏感 |
作业1: 墙壁划痕检测
* 墙壁划痕检测
dev_update_window ('off')
dev_get_window (WindowHandle)
* 读取原始墙面图像
read_image (Image, 'D:/桌面/Halcon/day04/wall.png')
dev_display(Image)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 对图像进行均值滤波(平滑处理),减少噪声
mean_image (Image, ImageMean, 15, 15)
* 动态阈值分割,提取比背景更暗的划痕区域
dyn_threshold (Image, ImageMean, RegionDynThresh, 3.0, 'dark')
* 将分割结果进行连通域分析,得到独立区域
connection (RegionDynThresh, ConnectedRegions)
* 根据面积筛选目标区域,去除小噪声
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 127, 99999)
dev_display (SelectedRegions)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
作业2:毛刺检测
* 读取文件夹中的所有图像文件
dev_update_on ()
dev_get_window (WindowHandle)
list_image_files ('D:/桌面/Halcon/day04/burr_check', 'default', [], ImageFiles)
for Index := 0 to |ImageFiles| - 1 by 1
read_image (Image, ImageFiles[Index])
* 使用自动阈值(最大类间方差)分割,提取暗区域目标
binary_threshold (Image, Region, 'max_separability', 'dark', UsedThreshold)
* 进行圆形腐蚀,去除边缘细小干扰
erosion_circle (Region, RegionErosion, 3.5)
* 连通域分析,分离独立区域
connection (RegionErosion, ConnectedRegions)
* 根据面积筛选出目标物体区域
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 160000, 999999)
dev_clear_window ()
dev_display (SelectedRegions)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 对目标区域进行开运算(先腐蚀再膨胀),平滑边界并缩小物体
opening_circle (SelectedRegions, RegionSmooth, 19.5)
dev_clear_window ()
dev_display (RegionSmooth)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 计算原始区域与平滑区域的差异,提取可能的毛刺区域
difference (SelectedRegions, RegionSmooth, BurrRegion)
dev_clear_window ()
dev_display (BurrRegion)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* 对毛刺区域进行连通域分析
connection (BurrRegion, ConnectedRegions1)
* 根据面积筛选出真实毛刺,去除噪声
select_shape (ConnectedRegions1, SelectedRegions1, 'area', 'and', 150, 99999)
dev_clear_window ()
* 显示原图及检测到的毛刺区域
dev_display (Image)
dev_display (SelectedRegions1)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
endfor
基于灰度值模板匹配
* 基于灰度值的模板匹配
read_image (Image, 'smd/smd_on_chip_05')
dev_get_window(WindowHandle)
dev_set_draw ('margin')
dev_set_color ('green')
* 制作模板
gen_rectangle2 (ROI_0, 310.154, 313.196, rad(0.666331), 132.938, 110.822)
* 获取区域中心点和面积
area_center (ROI_0, Area, Row, Column)
orientation_region (ROI_0, Phi)
* 显示中心点(绘制十字架)
gen_cross_contour_xld (Cross, Row, Column, 20, Phi)
* 裁剪感兴趣区域
reduce_domain (Image, ROI_0, ImageReduced)
* 创建基于灰度模板(基于归一化相关性模板)
* 参数1 模板图片
* 参数2 金字塔层级,auto自动选择金字塔层级, 值越大,匹配速度越快
* 参数3 起始角度 -3.14 == -180
* 参数4 结束角度 3.14 == 180
* 参数5 角度递增 'auto' 自动
* 参数6 'user_polarity' 使用极性
* 参数7 ModelID 模板ID,获取模板匹配结果通过 id 获取
create_ncc_model (ImageReduced, 'auto', -3.14, 3.14, 'auto', 'use_polarity', ModelID)
*create_ncc_model (ImageReduced, 'auto', rad(-180), rad(180), 'auto', 'use_polarity', ModelID)
* rad(-180) 将-180转换为弧度,大约为: -3.1416
* 查找匹配结果
for Index := 1 to 11 by 1
dev_clear_window ()
read_image (Image1, 'smd/smd_on_chip_' + Index$'02' + '.png')
* 查找模板匹配结果
*参数1 输入的图片
*参数2 模板id
*参数3,4 开始角度和结束角度
*参数5 最小得分 0.8
*参数6 匹配个数 1, 值 0 匹配多个
*参数7 重叠率 0.5 得分高匹配谁
*参数8 是否启用亚像素(把一个像素精确到小数级别) 例如精确到半个像素
*参数9 金字塔层级 0 最高等级,保留细节多,计算量大
*参数10,11 模板匹配结果中心点坐标
*参数12 模板匹配结果角度
*参数13 模板匹配结果得分
find_ncc_model (Image1, ModelID, -3.14, 3.14, 0.8, 1, 0.5, 'true', 0, Row1, Column1, Angle, Score)
if (|Row1| > 0)
if (Score > 0.9)
dev_display_ncc_matching_results (ModelID, 'green', Row1, Column1, Angle, 0)
dev_disp_text ('ok', 'image', Row1, Column1, 'green', [], [])
else
dev_display_ncc_matching_results (ModelID, 'red', Row1, Column1, Angle, 0)
dev_disp_text ('ng', 'image', Row1, Column1, 'red', [], [])
endif
else
dev_disp_text ('未匹配到结果', 'window', 100, 100, 'red', [], [])
endif
stop ()
endfor
* 释放模板
clear_ncc_model (ModelID)
模板导入和导出
* 模板导出和导入
read_image (Image, 'clip')
* 模板匹配区域
* gen_rectangle2 (ROI_0, 269.124, 242.53, rad(19.5943), 106.585, 36.7617)
* reduce_domain (Image, ROI_0, ImageReduced)
* 创建模板匹配模板
* create_ncc_model (ImageReduced, 'auto', -3.14, 3.14, 'auto', 'use_polarity', ModelID)
* write_ncc_model (ModelID, 'Model.ncm') // 导出模板
* 导入模板
read_ncc_model ('D:/桌面/Halcon/day05/Model.shm', ModelID)
* 对图片进行模板匹配
find_ncc_model (Image, ModelID, -3.14, 3.14, 0.6, 0, 0.5, 'true', 0, Row, Column, Angle, Score)
dev_display (Image)
* 展示模板匹配结果
dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
* 展示文字
dev_disp_text (Score, 'image', Row, Column, 'black', [], [])
* 释放模板
clear_ncc_model (ModelID)
基于形状的模板匹配
* 基于形状的模板匹配
dev_update_window ('off')
read_image (Image, 'green-dot')
dev_get_window (WindowHandle)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('green')
dev_display (Image)
* 绘制模板区域
gen_circle (ROI_0, 275.034, 282.538, 93.955)
reduce_domain (Image, ROI_0, ImageReduced)
* 创建基于形状模板
* 参数6,7 缩放比例
* 参数8 缩放的递增量
* 参数9 Optimization == 'auto' 优化方式 自动优化模式
* 参数11 Contrast == 'auto' 增强对比度 自动增强模式
* 参数12 MinContrast == 'auto' 最小对比度 自动对比度
create_scaled_shape_model (ImageReduced, 'auto', -3.14, 3.14, 'auto', 0.8, 1.1, 'auto', 'auto', 'ignore_global_polarity', 'auto', 'auto', ModelID)
* 获取模板的轮廓信息
get_shape_model_contours (ModelContours, ModelID, 1)
* 获取模板中心点坐标
area_center(ROI_0, Area, Row, Column)
* 仿射变换,将模板轮廓显示在模板中心点位置
* 刚性的仿射变换,返回结果为一个变换矩阵
* 参数1,2,3 起始位置row,column,angle
* 参数4,5,6 结束位置row,column,angle
vector_angle_to_rigid (0, 0, 0, Row, Column, 0, HomMat2D)
* 应用变换矩阵到指定的轮廓
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2D)
dev_display(ContoursAffineTrans)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
* =============模板匹配==============
read_image (Image1, 'green-dots')
dev_display (Image1)
* 参数10 SubPixel 亚像素模式 'least_squares' 最小二乘法模式
* 参数12 Greedliness 贪婪程度(值越大查找速度越快)
find_scaled_shape_model (Image1, ModelID, -3.14, 3.14, 0.9, 1.1, 0.3, 0, 0.5, 'least_squares', 0, 0.9, Row1, Column1, Angle, Scale, Score)
* 基于形状模板匹配结果
* dev_display_shape_matching_results (ModelID, 'red', Row1, Column1, Angle, 1, 1, 0)
* 手动绘制模板匹配结果区域
gen_circle (Circle, Row1, Column1, 100)
dev_display(Circle)
dev_set_color ('red')
gen_cross_contour_xld (Cross, Row1, Column1, 30, Angle)
dev_display(Cross)
* 释放模板
clear_shape_model (ModelID)
仿射变换 -> 显示匹配结果
*仿射变换查找显示结果
* 基于形状的模板匹配
dev_update_window ('off')
read_image (Image, 'green-dot')
dev_get_window (WindowHandle)
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('green')
dev_display (Image)
* 绘制模板区域
gen_circle (ROI_0, 275.034, 282.538, 93.955)
reduce_domain (Image, ROI_0, ImageReduced)
* 创建基于形状模板
create_scaled_shape_model (ImageReduced, 'auto', rad(-45), rad(90), 'auto', 0.8, 1.1, 'auto', 'auto', 'ignore_global_polarity', 'auto', 'auto', ModelID)
* 获取模板轮廓
get_shape_model_contours (ModelContours, ModelID, 1)
*=======读取图片,模板匹配========
read_image (Image1, 'green-dots')
dev_display (Image1)
find_scaled_shape_model (Image1, ModelID, rad(-45), rad(90), 0.9, 1.1, 0.3, 0, 0.5, 'least_squares', 0, 0.9, Row1, Column1, Angle, Scale, Score)
for Index := 0 to |Row1|-1 by 1
*1 创建初始化仿射矩阵
hom_mat2d_identity (HomMat2DIdentity)
*2 生成一个平移矩阵 参数1初始化的矩阵 参数2和参数3移动的位置
hom_mat2d_translate (HomMat2DIdentity, Row1[Index], Column1[Index], HomMat2DTranslate)
*3 生成一个旋转矩阵 参数1是平移矩阵
hom_mat2d_rotate (HomMat2DTranslate, Angle[Index], Row1[Index], Column1[Index], HomMat2DRotate)
*4 生成一个缩放矩阵 参数1是旋转矩阵
hom_mat2d_scale (HomMat2DRotate, Scale[Index], Scale[Index], Row1[Index], Column1[Index], HomMat2DScale)
*5 使用矩阵
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2DScale)
*6 展示变换后的轮廓区域
dev_display (ContoursAffineTrans)
endfor
* 基于形状模板匹配结果
* dev_display_shape_matching_results (ModelID, 'red', Row1, Column1, Angle, Scale, Scale, 0)
* 释放模板
clear_shape_model (ModelID)
作业1: 开关匹配
* 开关匹配
dev_get_window (WindowHandle)
dev_set_draw ('margin')
list_image_files ('D:/桌面/Halcon/day05/dip_switch', 'default', [], ImageFiles)
* 模板匹配
* read_image (Image, ImageFiles[0])
* 模板匹配区域
* gen_rectangle2 (ROI_0, 189.802, 333.217, rad(-2.49119), 191.242, 62.491)
* reduce_domain (Image, ROI_0, ImageReduced)
* 创建模板匹配
* create_ncc_model (ImageReduced, 'auto', -3.14, 3.14, 'auto', 'use_polarity', ModelID)
* 进行模板匹配
* find_ncc_model (ImageReduced, ModelID, -3.14, 3.14, 0.8, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
* 查看模板匹配区域
* dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
* 写入模板
* write_ncc_model (ModelID, 'output.ncm')
* 读取模板
read_ncc_model ('output.ncm', ModelID)
* 获取模板匹配边框(主要用于手动显示模板匹配)
get_ncc_model_region (ModelRegion, ModelID)
* 循环模板匹配
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
find_ncc_model (Image, ModelID, -3.14, 3.14, 0.7, 1, 0.5, 'true', 0, Row, Column, Angle, Score)
dev_display_ncc_matching_results (ModelID, 'green', Row, Column, Angle, 0)
* 显示模板匹配区域
*disp_continue_message (WindowHandle, 'black', 'true')
* 手动显示模板区域
for i := 0 to |Row|-1 by 1
* 计算仿射变换矩阵(从模板原点 → 匹配位置)
* 生成一个规则,从位置0,0,角度0 移动到位置Row[i], Column[i],角度Angle[i],规则名称为 HomMat2D
vector_angle_to_rigid (0, 0, 0, Row[i], Column[i], Angle[i], HomMat2D)
* 对模板区域做仿射变换
* 应用 HomMat2D 这个规则
affine_trans_region (ModelRegion, TransRegion, HomMat2D, 'nearest_neighbor')
* 显示
dev_set_color ('green')
dev_display (TransRegion)
endfor
* 显示中心点
gen_cross_contour_xld (Cross, Row, Column, 20, Angle)
stop ()
endfor
* 释放模板
clear_ncc_model (ModelID)
作业2: 卡簧匹配
* 卡簧匹配
dev_set_draw ('margin')
read_image (Image, 'D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp')
gen_circle (ROI_0, 697.24, 530.533, 123.137)
reduce_domain (Image, ROI_0, ImageReduced)
create_scaled_shape_model (ImageReduced, 'auto', -8, 8, 'auto', 0.9, 1.1, 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
* find_scaled_shape_model (Image, ModelID, -8, 8, 0.9, 1.1, 0.5, 0, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Scale, Score)
* 显示模板匹配区域
* dev_clear_window ()
* dev_display(Image)
* dev_display_shape_matching_results (ModelID, 'green', Row, Column, Angle, Scale, Scale, 0)
* dev_set_color ('red')
* gen_cross_contour_xld (Cross, Row, Column, 30, Angle)
* dev_disp_text ('数量:' + |Row|, 'image', 200, 200, 'black', [], [])
* 手动绘制模板匹配区域
* 获取模板区域
* get_shape_model_contours (ModelContours, ModelID, 1)
* dev_clear_window ()
* dev_display(Image)
* for Index := 0 to |Row|-1 by 1
* vector_angle_to_rigid (0, 0, 0, Row[Index], Column[Index], Angle[Index], HomMat2D)
* affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2D)
* endfor
* dev_set_color ('red')
* gen_cross_contour_xld (Cross, Row, Column, 30, Angle)
* dev_disp_text ('数量:' + |Row|, 'image', 200, 200, 'black', [], [])
* 循环检测多张图片
* list_image_files ('D:/桌面/Halcon/day05/快速匹配', 'default', [], ImageFiles)
* for Index := 0 to |ImageFiles|-1 by 1
* read_image (Image1, ImageFiles[Index])
* find_scaled_shape_model (Image1, ModelID, -8, 8, 0.9, 1.1, 0.5, 0, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Scale, Score)
* dev_clear_window ()
* dev_display(Image1)
* dev_display_shape_matching_results (ModelID, 'green', Row, Column, Angle, Scale, Scale, 0)
* dev_set_color ('red')
* gen_cross_contour_xld (Cross, Row, Column, 30, Angle)
* dev_disp_text ('数量:' + |Row|, 'image', 200, 200, 'black', [], [])
* stop ()
* endfor
* 循环检测多张图片(手动绘制区域)
list_image_files ('D:/桌面/Halcon/day05/快速匹配', 'default', [], ImageFiles)
get_shape_model_contours (ModelContours, ModelID, 1)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image1, ImageFiles[Index])
find_scaled_shape_model (Image1, ModelID, -8, 8, 0.9, 1.1, 0.5, 0, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Scale, Score)
dev_clear_window ()
dev_display (Image1)
for Index1 := 0 to |Row|-1 by 1
vector_angle_to_rigid (0, 0, 0, Row[Index1], Column[Index1], Angle[Index1], HomMat2D)
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2D)
endfor
*dev_set_color ('red')
gen_cross_contour_xld (Cross, Row, Column, 30, Angle)
dev_disp_text ('数量:' + |Row|, 'image', 200, 200, 'black', [], [])
stop ()
endfor
clear_shape_model (ModelID)
匹配助手
选择菜单栏 -> 助手 -> 打开新的Matching就可以创建匹配模板
插入代码如下
* 匹配助手
read_image (Image, 'D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp')
*
gen_circle (ModelRegion, 692.964, 532.8, 118.926)
reduce_domain (Image, ModelRegion, TemplateImage)
create_generic_shape_model (ModelID)
set_generic_shape_model_param (ModelID, 'metric', 'use_polarity')
train_generic_shape_model (TemplateImage, ModelID)
get_shape_model_contours (ModelContours, ModelID, 1)
area_center (ModelRegion, ModelRegionArea, RefRow, RefColumn)
vector_angle_to_rigid (0, 0, 0, RefRow, RefColumn, 0, HomMat2D)
affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
dev_display (Image)
dev_set_color ('green')
dev_set_draw ('margin')
dev_display (ModelRegion)
dev_display (TransContours)
stop ()
set_generic_shape_model_param (ModelID, 'border_shape_models', 'false')
set_generic_shape_model_param (ModelID, 'pyramid_level_lowest', 4)
TestImages := ['D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424150956101.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151025909.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151103837.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151223821.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151314446.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151418749.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151424525.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151433765.bmp']
for T := 0 to 8 by 1
read_image (Image, TestImages[T])
find_generic_shape_model (Image, ModelID, MatchResultID, NumMatchResult)
for I := 0 to NumMatchResult-1 by 1
*dev_display (Image)
get_generic_shape_model_result_object (MatchContour, MatchResultID, I, 'contours')
dev_set_color ('green')
dev_display (MatchContour)
get_generic_shape_model_result (MatchResultID, I, 'row', Row)
get_generic_shape_model_result (MatchResultID, I, 'column', Column)
get_generic_shape_model_result (MatchResultID, I, 'angle', Angle)
get_generic_shape_model_result (MatchResultID, I, 'scale_row', ScaleRow)
get_generic_shape_model_result (MatchResultID, I, 'scale_column', ScaleColumn)
get_generic_shape_model_result (MatchResultID, I, 'hom_mat_2d', HomMat2D)
get_generic_shape_model_result (MatchResultID, I, 'score', Score)
endfor
dev_disp_text ('个数:' + NumMatchResult, 'window', 100, 100, 'black', [], [])
stop ()
*Fixtrue
* for I := 0 to NumMatchResult-1 by 1
* get_generic_shape_model_result (MatchResultID, I, 'hom_mat_2d', HomMat2D)
* hom_mat2d_identity (AlignmentHomMat2D)
* hom_mat2d_translate (AlignmentHomMat2D, -RefRow, -RefColumn, AlignmentHomMat2D)
* hom_mat2d_compose (HomMat2D, AlignmentHomMat2D, AlignmentHomMat2D)
* endfor
*仿射变换
* hom_mat2d_identity (HomMat2DModel)
* hom_mat2d_translate (HomMat2DModel, RefRow, RefColumn, HomMat2DModel)
* for I := 0 to NumMatchResult-1 by 1
* get_generic_shape_model_result (MatchResultID, I, 'hom_mat_2d', HomMat2D)
* hom_mat2d_invert (HomMat2D, HomMat2DMatchInvert)
* hom_mat2d_compose (HomMat2DModel, HomMat2DMatchInvert, RectificationHomMat2D)
* affine_trans_image (Image, RectifiedImage, RectificationHomMat2D, 'constant', 'false')
* endfor
endfor
模板匹配 -> 金字塔层级(作业)
* =========================
* 图像采集
* =========================
open_framegrabber ('File', 1, 1, 0, 0, 0, 0, 'default', -1, 'default', -1, \
'false', 'E:/halcon/data/HALCON-24.11-Progress-Steady/examples/images/rings/rings.seq', \
'default', 1, -1, AcqHandle)
grab_image (Image, AcqHandle)
dev_update_window ('off')
dev_set_draw ('margin')
dev_set_line_width (3)
* =========================
* 制作模板
* =========================
* 绘制ROI(定义模板区域)
gen_circle (ROI_0, 249.177, 198.107, 95.4509)
* 裁剪图像,仅保留ROI区域
reduce_domain (Image, ROI_0, ImageReduced)
* =========================
* ⭐ 金字塔核心(重点部分)
* =========================
* inspect_shape_model 用于检查模板在不同金字塔层级下的表现
* 同时生成金字塔图像(从高分辨率到低分辨率)
inspect_shape_model (ImageReduced, ModelImages, ModelRegions, 4, 30)
* 参数说明:
* ImageReduced : 输入图像(ROI区域)
* ModelImages : 输出金字塔各层图像(数组,每个元素是一层)
* ModelRegions : 每一层对应的特征区域
* 4 : 金字塔层数(从原图逐步下采样生成4层)
* 层级说明:
* 第1层:原始分辨率(最清晰)
* 第2层:下采样1次
* 第3层:下采样2次
* 第4层:最小图(最模糊,用于快速匹配)
*
* 匹配时执行顺序:
* 第4层 → 第3层 → 第2层 → 第1层
* (先粗匹配,再精细匹配)
*
* 30 : 对比度阈值(决定哪些边缘作为特征)
* 值越大 → 特征越少但更稳定
* 值越小 → 特征更多但可能受噪声影响
* 显示金字塔各层图像(用于观察分辨率变化)
dev_display (ModelImages)
* =========================
* 创建模板
* =========================
create_shape_model (ImageReduced, 'auto', rad(0), rad(360), 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
* 自动创建模板:
* 支持0~360度旋转
* use_polarity 表示考虑灰度极性(黑白方向)
* =========================
* 获取模板轮廓
* =========================
get_shape_model_contours (ModelContours, ModelID, 1)
* 参数1表示使用金字塔第1层(最高分辨率)轮廓
* =========================
* 计算模板中心位置
* =========================
area_center (ImageReduced, Area, Row, Column)
* 生成刚性变换矩阵(用于显示轮廓)
vector_angle_to_rigid (0, 0, 0, Row, Column, 0, HomMat2D)
* 对模板轮廓做仿射变换
affine_trans_contour_xld (ModelContours, ContoursAffineTrans, HomMat2D)
* 显示模板
dev_display (Image)
dev_display (ContoursAffineTrans)
stop ()
* =========================
* 模板匹配阶段
* =========================
Length := 30
while (true)
grab_image (Image1, AcqHandle)
dev_display(Image1)
find_shape_model (Image1, ModelID, rad(0), rad(360), 0.5, 0, 0.5, 'least_squares', 0, 0.9, Row1, Column1, Angle, Score)
* 参数说明:
* 0.5 : 最低匹配分数
* 0 : 返回所有匹配
* 0.5 : 最大重叠
* least_squares : 高精度定位
*
* ⭐ 内部自动使用金字塔:
* 从低分辨率层开始匹配 → 逐层细化 → 提高速度
* 显示匹配结果
dev_display_shape_matching_results (ModelID, 'red', Row1, Column1, Angle, 1, 1, 0)
* 绘制方向箭头
gen_arrow_contour_xld (Arrow, Row1, Column1, Row1 - Length * sin(Angle + rad(-90)), Column1 + Length * cos(Angle + rad(-90)), 5, 5)
dev_display(Arrow)
stop()
endwhile
* =========================
* 关闭采集设备
* =========================
close_framegrabber (AcqHandle)
测量工具(测量边缘对)
* 测量工具
read_image (Image, 'ic_pin')
dev_set_draw ('margin')
dev_set_color ('green')
dev_get_window (WindowHandle)
get_image_size (Image, Width, Height)
* 测量ROI
gen_rectangle2 (ROI_0, 51.4416, 482.088, rad(-0.628189), 403.787, 7.00836)
* 生成测量对象
* 前五个参数定义一个仿射矩形测量区域(中心+角度+长宽)
* 51.4416, 482.088:矩形中心坐标(Row, Col)
* 0:矩形角度(弧度),决定测量线方向(此处为水平/垂直基准)
* 403.787:长边半长 → 决定测量范围长度(影响能检测多少个引脚)
* 7.00836:短边半长 → 决定测量宽度(影响每条测量线的采样深度)
* Width, Height:图像尺寸(必须传入,用于建立内部坐标映射)
* 'nearest_neighbor':插值方式(影响亚像素精度,nearest较快但精度低)
* MeasureHandle:输出测量句柄(后续所有测量操作的核心对象)
gen_measure_rectangle2 (51.4416, 482.088, 0, 403.787, 7.00836, Width, Height, 'nearest_neighbor', MeasureHandle)
* 测量边缘对的算子
* Image:输入图像
* MeasureHandle:测量句柄(由 gen_measure_rectangle2 生成)
* 1:Sigma,高斯平滑系数(越大抗噪越强,但边缘会变钝)
* 30:Threshold,边缘幅值阈值(过滤弱边缘,值越大越严格)
* 'all':Transition(极性)
* positive:暗→亮
* negative:亮→暗
* all:两种都检测(适用于未知方向或复杂情况)
* 'all':Select(选择方式)
* first:每条测量线上第一个边
* last:最后一个边
* all:全部保留(用于边缘配对)
*
* RowEdgeFirst, ColumnEdgeFirst:第一条边的位置(每一对的起点)
* AmplitudeFirst:第一条边的灰度梯度幅值(强度)
*
* RowEdgeSecond, ColumnEdgeSecond:第二条边的位置(每一对的终点)
* AmplitudeSecond:第二条边的灰度梯度幅值
*
* IntraDistance:同一对边之间的距离(关键测量值,如引脚宽度)
* InterDistance:相邻边对之间的距离(可用于分析节距/间距)
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
* 绘制线
* disp_line (WindowHandle, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
* 根据检测到的边生成线段:
* RowEdgeFirst, ColumnEdgeFirst:线起点
* RowEdgeSecond, ColumnEdgeSecond:线终点
* 每一对边生成一条测量线(用于可视化测量结果)
gen_region_line (RegionLines, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
dev_disp_text ('引脚个数:' + |RowEdgeFirst|, 'window', 100, 100, 'black', [], [])
* 移除第一条边
tuple_remove (RowEdgeFirst, 0, Reduced1)
tuple_remove (ColumnEdgeFirst, 0, Reduced2)
tuple_remove (RowEdgeSecond, |RowEdgeSecond|-1, Reduced3)
tuple_remove (ColumnEdgeSecond, |ColumnEdgeSecond|-1, Reduced4)
dev_set_color ('yellow')
* 使用过滤后的边重新生成测量线(去掉首尾异常边)
* Reduced1/Reduced2:新的起点集合
* Reduced3/Reduced4:新的终点集合
gen_region_line (Image, Reduced1, Reduced2, Reduced3, Reduced4)
* IntraDistance:每一对边之间的距离集合
* sum(IntraDistance):所有测量值求和
* |RowEdgeFirst|:边对数量(用于求平均)
sum1 := sum(IntraDistance)
count := |RowEdgeFirst|
avg := (sum1 / count)$'.2f'
dev_disp_text ('平均值:' + avg, 'window', 100, 150, 'black', [], [])
测量边缘
* 测量边缘
read_image (Image, 'ic_pin')
get_image_size (Image, Width, Height)
dev_set_draw('margin')
* 创建ROI
gen_rectangle2 (ROI_0, 506.017, 457.643, rad(-90), 484.076, 65.4091)
* 创建测量模型
* 506.017, 457.643:测量矩形中心(Row, Col)
* rad(-90):矩形旋转角度(弧度),决定测量线方向(此处为垂直方向扫描)
* 484.076:长边半长 → 决定测量范围长度(影响可检测边数量)
* 65.4091:短边半长 → 决定测量宽度(影响单条测量线的采样深度/稳定性)
* Width, Height:图像尺寸(用于建立测量模型的坐标映射,必须输入)
* 'nearest_neighbor':插值方式(最近邻插值,速度快但亚像素精度较低)
* MeasureHandle:输出测量句柄(后续 measure_pos 必须使用)
gen_measure_rectangle2 (506.017, 457.643, rad(-90), 484.076, 65.4091, Width, Height, 'nearest_neighbor', MeasureHandle)
* 测量边缘
* Image:输入图像
* MeasureHandle:测量句柄(由 gen_measure_rectangle2 生成)
* 1:Sigma,高斯平滑系数(用于平滑灰度剖面,减小噪声影响)
* 30:Threshold,边缘幅值阈值(梯度阈值,过滤弱边缘)
* 'all':Transition(极性)
* positive:暗→亮
* negative:亮→暗
* all:两种边缘都检测
* 'all':Select(选择方式)
* first:每条测量线上第一个边
* last:最后一个边
* all:返回所有检测到的边
*
* RowEdge:检测到的边缘行坐标集合
* ColumnEdge:检测到的边缘列坐标集合
* Amplitude:对应边缘的梯度幅值(强度,越大越可靠)
* Distance:相邻边之间的距离(沿测量方向的投影距离)
measure_pos (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
* 根据检测到的边生成十字标记
* RowEdge, ColumnEdge:边缘位置
* 6:十字尺寸
* 0:角度
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 6, 0)
dev_disp_text ('上高速:' + Distance[0], 'image', RowEdge[0] + Distance[0] / 2, ColumnEdge[0], 'black', [], [])
dev_disp_text ('中高速:' + Distance[1], 'image', RowEdge[1] + Distance[1] / 2, ColumnEdge[1], 'black', [], [])
dev_disp_text ('下高速:' + Distance[2], 'image', RowEdge[2] + Distance[2] / 2, ColumnEdge[2], 'black', [], [])
* 绘制线
* 使用相邻边点构成线段,用于表示测量距离
* RowEdge[i],ColumnEdge[i] → 起点
* RowEdge[i+1],ColumnEdge[i+1] → 终点
* 每两点之间对应 Distance[i]
gen_region_line (RegionLines, RowEdge[0], ColumnEdge[0], RowEdge[1], ColumnEdge[1])
dev_set_color ('yellow')
gen_region_line (RegionLines, RowEdge[1], ColumnEdge[1], RowEdge[2], ColumnEdge[2])
dev_set_color ('green')
gen_region_line (RegionLines, RowEdge[2], ColumnEdge[2], RowEdge[3], ColumnEdge[3])
测量助手
图形化界面操作,操作即可
练习: 测量练习
* 课堂练习
read_image (Image, 'D:/桌面/Halcon/day05/dip_switch/dip_switch_07.png')
get_image_size (Image, Width, Height)
dev_set_draw ('margin')
* 绘制ROI
gen_rectangle2 (ROI_0, 349.987, 254.498, rad(2.55003), 169.537, 25.8391)
* 生成测量模型
* 349.987, 254.498:测量矩形中心(Row, Col)
* rad(2.55003):旋转角度(弧度),决定测量线方向
* 169.537:长边半长 → 决定测量范围长度(影响检测到的开关数量)
* 25.8391:短边半长 → 决定测量宽度(影响每条测量线采样深度与稳定性)
* Width, Height:图像尺寸(必须提供,用于内部坐标映射)
* 'nearest_neighbor':插值方式(最近邻,速度快但精度较低)
* MeasureHandle:输出测量句柄
gen_measure_rectangle2 (349.987, 254.498, rad(2.55003), 169.537, 25.8391, Width, Height, 'nearest_neighbor', MeasureHandle)
* 边缘对测量
* Image:输入图像
* MeasureHandle:测量句柄
* 1:Sigma(高斯平滑系数,抑制噪声)
* 30:Threshold(边缘幅值阈值,过滤弱边缘)
* 'all':Transition(极性:暗→亮/亮→暗都检测)
* 'all':Select(返回所有边,用于组成边缘对)
*
* RowEdgeFirst / ColumnEdgeFirst:每对边的第一条边坐标
* AmplitudeFirst:第一条边强度
*
* RowEdgeSecond / ColumnEdgeSecond:第二条边坐标
* AmplitudeSecond:第二条边强度
*
* IntraDistance:同一对边之间的距离(关键 → 单个开关宽度/间隔)
* InterDistance:相邻边对之间的距离(可用于分析节距)
measure_pairs (Image, MeasureHandle, 1, 30, 'all', 'all', RowEdgeFirst, ColumnEdgeFirst, AmplitudeFirst, RowEdgeSecond, ColumnEdgeSecond, AmplitudeSecond, IntraDistance, InterDistance)
* 根据边对生成线(用于可视化测量结果)
* 每一对边 → 一条线段
gen_region_line (Imag, RowEdgeFirst, ColumnEdgeFirst, RowEdgeSecond, ColumnEdgeSecond)
dev_disp_text ('开关数量:' + |RowEdgeFirst|, 'image', 100, 100, 'black', [], [])
gen_rectangle2 (ROI_0, 353.874, 268.204, rad(-87.6482), 67.3727, 13.2039)
* 生成测量模型(用于长度测量)
* 参数含义同上(中心、角度、长宽、图像尺寸、插值方式、句柄)
gen_measure_rectangle2 (353.874, 268.204, rad(-87.6482), 67.3727, 13.2039, Width, Height, 'nearest_neighbor', MeasureHandle1)
* 单边缘测量
* Image:输入图像
* MeasureHandle1:测量句柄
* 1:Sigma(平滑)
* 30:Threshold(边缘阈值)
* 'all':Transition(检测所有极性边缘)
* 'all':Select(返回所有边)
*
* RowEdge / ColumnEdge:检测到的边缘坐标
* Amplitude:边缘强度
* Distance:相邻边之间的距离(沿测量方向的投影距离)
measure_pos (Image, MeasureHandle1, 1, 30, 'all', 'all', RowEdge, ColumnEdge, Amplitude, Distance)
* 生成边缘标记(十字)
gen_cross_contour_xld (Cross, RowEdge, ColumnEdge, 6, 0.785398)
* 使用首尾边构成线段(表示整体长度)
gen_region_line (RegionLines, RowEdge[0], ColumnEdge[0], RowEdge[|RowEdge|-1], ColumnEdge[|ColumnEdge|-1])
* Distance:每两个相邻边之间的距离
* sum(Distance):所有段长度累加 → 总长度
height := sum(Distance)
dev_disp_text ('长度:' + height, 'image', 100, 200, 'black', [], [])
gen_rectangle2 (ROI_0, 315.003, 252.665, rad(2.9391), 197.342, 6.51632)
* 生成测量模型(用于宽度测量)
* 参数含义同上
gen_measure_rectangle2 (315.003, 252.665, rad(2.9391), 197.342, 6.51632, Width, Height, 'nearest_neighbor', MeasureHandle2)
* 单边缘测量(宽度方向)
* 返回多个边 → Distance 表示相邻边之间距离
measure_pos (Image, MeasureHandle2, 1, 30, 'all', 'all', RowEdge1, ColumnEdge1, Amplitude1, Distance1)
* 显示边缘位置
gen_cross_contour_xld (Cross1, RowEdge1, ColumnEdge1, 6, 0.785398)
* sum(Distance1):累加所有边间距离 → 总宽度
width := sum(Distance1)
dev_disp_text ('宽度:' + width, 'image', 100, 300, 'black', [], [])
测量工具-卡尺
* 测量工具-直线 圆 矩形等
read_image (Image, 'printer_chip/printer_chip_01')
dev_set_draw('margin')
dev_set_line_width (3)
dev_get_window (WindowHandle)
get_image_size (Image, Width, Height)
* 绘制ROI
gen_region_line (ROI_0, 14.0161, 1163.94, 268.855, 1163.94)
*1 创建测量对象
create_metrology_model (MetrologyHandle)
*2 设置测量对象的宽度和高度
set_metrology_model_image_size (MetrologyHandle, Width, Height)
*3 添加测量形状
*参数2 形状
* Line: 起点和终点坐标
* Circle: 圆心坐标和半径
*参数3 需要根据测量形状设置参数
*参数4 测量长度 卡尺的长度
*参数5 测量宽度 卡次的宽度
*参数6 sigam 平滑程序
*参数7 Threshold 阈值
*参数8,9 预留参数
add_metrology_object_generic (MetrologyHandle, 'line', [14.0161, 1163.94, 268.855, 1163.94], 50, 5, 1, 30, [], [], Index)
*add_metrology_object_generic (MetrologyHandle, 'line', [14.0161, 1163.94, 268.855, 1163.94], 20, 5, 1, 30, [], [], Index1)
*4 设置卡尺数量 'num_instances'
*参数2 Index: 写成all 所有测量对象
set_metrology_object_param (MetrologyHandle, 'all', 'num_measures', 10)
*set_metrology_object_param (MetrologyHandle, Index, 'num_measures', 10)
*set_metrology_object_param (MetrologyHandle, Index1, 'num_measures', 10)
*5 设置卡尺极性
set_metrology_object_param (MetrologyHandle, 'all', 'measure_transition', 'all')
*6 设置最大的实例个数 查找线个数,最多为30个
set_metrology_object_param (MetrologyHandle, 'all', 'num_instances', 30)
*7 应用测量模型
apply_metrology_model (Image, MetrologyHandle)
*8 获取测量结果
* 获取卡尺
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row, Column)
* 获取找到点
gen_cross_contour_xld (Cross, Row, Column, 6, 0.785398)
* 获取测量卡尺线
get_metrology_object_model_contour (Contour, MetrologyHandle, 'all', 1.5)
* 获取返回结果边
dev_set_color ('green')
get_metrology_object_result_contour (Contour1, MetrologyHandle, 'all', 'all', 1.5)
测量工具-卡尺(找圆)
* 找圆
read_image (Image, 'printer_chip/printer_chip_01')
dev_set_draw ('margin')
get_image_size (Image, Width, Height)
dev_get_window (WindowHandle)
* 绘制感兴趣区域
gen_circle (ROI_0, 338.599, 1030.32, 22.3507)
* 创建测量对象
create_metrology_model (MetrologyHandle)
* 设置创建测量对象宽度和高度
set_metrology_model_image_size (MetrologyHandle, Width, Height)
* 添加测量形状
add_metrology_object_generic (MetrologyHandle, 'circle', [338.599, 1030.32, 22.3507], 10, 5, 1, 30, [], [], Index)
* 设置卡尺数量
set_metrology_object_param (MetrologyHandle, 'all', 'num_measures', 10)
* 设置极性
set_metrology_object_param (MetrologyHandle, 'all', 'measure_transition', 'all')
* 设置查找个数
set_metrology_object_param (MetrologyHandle, 'all', 'num_instances', 2)
* 应用测量模型
apply_metrology_model (Image, MetrologyHandle)
dev_clear_window ()
dev_display (Image)
* 获取测量卡尺
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row, Column)
* 获取卡尺模板测量区域
dev_set_color ('blue')
get_metrology_object_model_contour (Contour1, MetrologyHandle, 0, 1.5)
* 获取卡尺测量结果
dev_set_color ('green')
get_metrology_object_result_contour (Contour, MetrologyHandle, 0, 'all', 1.5)
* 获取测量结果对象
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'all_param', Parameter)
* 获取测量行坐标
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'row', Parameter1)
* 获取测量列坐标
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'column', Parameter2)
* 获取测量角度
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'radius', Parameter3)
* 获取测量得分
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'score', Parameter4)
练习:测量小耳朵(找圆)
* 小耳朵测量
*找圆
read_image (Image, 'D:/桌面/Halcon/day07/abc.bmp')
get_image_size (Image, Width, Height)
dev_set_draw ('margin')
gen_circle (ROI_0, 263.242, 236.484, 22.2325)
gen_circle (ROI_1, 261.953, 391.306, 12.6353)
create_metrology_model (MetrologyHandle)
set_metrology_model_image_size (MetrologyHandle, Width,Height)
add_metrology_object_generic (MetrologyHandle, 'circle', [263.242, 236.484, 22.2325], 20, 3, 1, 30, [], [], Index)
add_metrology_object_generic (MetrologyHandle, 'circle', [261.953, 391.306, 12.6353], 20, 3, 1, 30, [], [], Index1)
set_metrology_object_param (MetrologyHandle, 'all', 'num_instances', 30)
set_metrology_object_param (MetrologyHandle, 'all', 'num_measures', 6)
set_metrology_object_param (MetrologyHandle, 'all', 'measure_transition', 'positive')
apply_metrology_model (Image, MetrologyHandle)
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row, Column)
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
*获取测量结果对象all_param
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'all_param', Parameter)
*测量结果行坐标
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'row', Parameter1)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'column', Parameter2)
*测量半径
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'radius', Parameter3)
get_metrology_object_result (MetrologyHandle, 'all', 'all', 'result_type', 'score', Parameter4)
* 绘制线
gen_region_line (RegionLines, Parameter1[0], Parameter2[0], Parameter1[1], Parameter2[1])
dev_display (Image)
dev_display (Contours)
dev_display (Contour)
dev_set_color ('yellow')
dev_display (RegionLines)
模板匹配 + 定位 + 测量
* 模板匹配 + 对齐模板 + 测量
read_image (Image, 'D:/桌面/Halcon/day05/dip_switch/dip_switch_01.png')
dev_update_window ('on')
dev_set_draw ('margin')
dev_set_line_width (3)
get_image_size (Image, Width, Height)
dev_get_window (WindowHandle)
*====================绘制ROI区域===========================
draw_line (WindowHandle, Row1, Column1, Row2, Column2)
gen_region_line (RegionLines, Row1, Column1, Row2, Column2)
draw_line (WindowHandle, Row3, Column3, Row4, Column4)
gen_region_line (RegionLines1, Row3, Column3, Row4, Column4)
*====================绘制模板区域==========================
draw_rectangle2 (WindowHandle, Row, Column, Phi, Length1, Length2)
gen_rectangle2 (Rectangle, Row, Column, Phi, Length1, Length2)
reduce_domain (Image, Rectangle, ImageReduced)
* 制作模板
create_shape_model (ImageReduced, 'auto', rad(0),rad(360), 'auto', 'auto', 'use_polarity', 'auto', 'auto', ModelID)
* 找模板
find_shape_model (Image, ModelID, rad(0), rad(360), 0.5, 1, 0.5, 'least_squares', 0, 0.9, Row5, Column5, Angle, Score)
dev_display_shape_matching_results (ModelID, 'red', Row5, Column5, Angle, 1, 1, 0)
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*===========================创建测量工具======================
create_metrology_model (MetrologyHandle)
set_metrology_model_image_size (MetrologyHandle, Width, Height)
* 增加检测区域
add_metrology_object_generic (MetrologyHandle, 'line', [[Row1, Column1, Row2, Column2],[Row3, Column3, Row4, Column4]], 20, 5, 1, 5, [], [], Index)
* 应用测量
apply_metrology_model (Image, MetrologyHandle)
* 获取卡尺轮廓
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row6, Column6)
* 获取卡尺测量结果
get_metrology_object_result_contour (Contours1, MetrologyHandle, 'all', 'all', 1.5)
* 绑定系统坐标系 reference_system
set_metrology_model_param (MetrologyHandle, 'reference_system', [Row5, Column5,0])
dev_display (Image)
dev_display_shape_matching_results (ModelID, 'red', Row5, Column5, Angle, 1, 1, 0)
*dev_display (Contours)
dev_display (Contours1)
list_files ('D:/桌面/Halcon/day05/dip_switch', 'files', Files)
for Index1 := 1 to |Files|-1 by 1
read_image (Image1, Files[Index1])
* 模板匹配
find_shape_model (Image1, ModelID, rad(0), rad(360), 0.5, 1, 0.5, 'least_squares', 0, 0.9, Row7, Column7, Angle1, Score1)
* 对齐模板
align_metrology_model (MetrologyHandle, Row7, Column7, Angle1)
* 测量
apply_metrology_model (Image1, MetrologyHandle)
* 测量距离
* 手动绘制检测线
*Parameter 第一条线的起点坐标和结束坐标
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'all_param', Parameter)
gen_region_line (RegionLines2, Parameter[0], Parameter[1], Parameter[2], Parameter[3])
*parameter1 第二条线的起始点坐标和结束坐标
get_metrology_object_result (MetrologyHandle, 1, 'all', 'result_type', 'all_param', Parameter1)
gen_region_line (RegionLines3, Parameter1[0], Parameter1[1], Parameter1[2], Parameter1[3])
* 测量两个局域之间的最小距离
distance_rr_min (RegionLines2, RegionLines3, MinDistance, Row11, Column11, Row21, Column21)
* 画一个水平线
gen_region_line (RegionLines4, Parameter[0] + 20, Parameter[1], Parameter1[0] + 20, Parameter1[1])
dev_display(Image1)
dev_display(RegionLines4)
*获取卡尺轮廓图
get_metrology_object_measures (Contours2, MetrologyHandle, 'all', 'all', Row8, Column8)
*测量结果边
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
dev_disp_text ('物体的宽度:' + MinDistance, 'image', 100, 100, 'black', [], [])
stop ()
endfor
条形码识别
read_image (Image, 'E:/halcon/data/HALCON-24.11-Progress-Steady/examples/images/barcode/ean8/ean801.png')
dev_set_draw ('margin')
*1创建条形码的句柄
create_bar_code_model ([], [], BarCodeHandle)
*2 设置条形码的的参数 条形码的最小单位,黑条之间的最小间距
*set_bar_code_param (BarCodeHandle, 'element_size_min', 8)
*3 条形码的最小的宽度
set_bar_code_param (BarCodeHandle, 'barcode_width_min', 100)
*4 设置条形码查找的精度 0快 ,1 精确
*set_bar_code_param (BarCodeHandle, 'persistence', 0)
*5设置条形码的对比度
*set_bar_code_param (BarCodeHandle, 'contrast_min',8)
*6查找条形码
*1 输入图片 2输出的区域 3 条形码句柄 4 条形码类型 5转成字符串
find_bar_code (Image, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)
*7获取条形码结果的
*'decoded_types' 条形码类型 code39
get_bar_code_result (BarCodeHandle, 'all', 'decoded_types', BarCodeResults)
* decoded_strings 转码字符串
get_bar_code_result (BarCodeHandle, 'all', 'decoded_strings', BarCodeResults1)
识别多种条形码
*没有检测到条形码的判断 code39和code32的转换
*code39 支持0-9字符还有A-Z 以及一些特殊符号
*code32 支持0-9数字和部分字符
*识别多种条形码
dev_get_window (WindowHandle)
query_font (WindowHandle, Font) //当前支持的字体
tuple_find (Font,'新宋体', Indices) // 判断当前是否支持新宋体
if (Indices>=0)
set_display_font (WindowHandle, 16, '新宋体', 'true', 'false')
endif
count_seconds (Seconds) //7772.08 开机时间
*读取图片
list_files ('条形码图片', 'files', Files)
*tuple_regexp_select 根据正则表达式进行筛选
* .* 匹配所有资源
* .(jpg|bmp|png) 后缀名为jpg bmp png
tuple_regexp_select (Files, '.(jpg|bmp|png)', Selection)
*创建条形码句柄
create_bar_code_model ([], [], BarCodeHandle)
set_bar_code_param (BarCodeHandle, 'barcode_width_min', 200)
set_bar_code_param (BarCodeHandle, 'barcode_height_min', 8)
dev_set_draw ('margin')
gen_empty_obj (EmptyObject) // 定义一个空对象
for Index := 0 to |Selection|-1 by 1
read_image (Image, Selection[Index])
*SymbolRegions 条形码的区域
find_bar_code (Image, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)
test_equal_obj (EmptyObject, SymbolRegions, IsEqual) //对比俩个参数是否为空
if (IsEqual) // true 证明没找到条形码区域
dev_display (Image)
dev_disp_text ('未找到条形码', 'window', 'top', 'left', 'black', [], [])
else //false 证明找到到条形码区域
dev_display (Image)
dev_display (SymbolRegions)
get_bar_code_result (BarCodeHandle, 'all', 'decoded_types', BarCodeResults) //类型
get_bar_code_result (BarCodeHandle, 'all', 'decoded_strings', BarCodeResults1)//字符串
if (BarCodeResults=='Code 39')
convert_decoded_string_code39_to_code32 (BarCodeResults1, ConvertedDataStringCode32)
dev_disp_text ('Code39转成Code32:'+ConvertedDataStringCode32, 'window', 100, 100, 'black', [], [])
endif
dev_disp_text ('找到条形码:'+ BarCodeResults+':'+BarCodeResults1, 'window', 'top', 'left', 'black', [], [])
endif
stop ()
endfor
二维码检测
*二维码检测
*创建二维码对象
*'default_parameters' 默认参数设置
*'maximum_recognition' 最大的识别度
create_data_code_2d_model ('Data Matrix ECC 200', ['default_parameters'], ['maximum_recognition'], DataCodeHandle) // Data Matrix ECC 200 数据矩阵码 简称D码
create_data_code_2d_model ('QR Code', [], [], DataCodeHandle1) //创建QR码对象
create_data_code_2d_model ('PDF417', [], [], DataCodeHandle2) //创建PDF417码对象 二维码堆叠的条形结构
** 设置句柄的解析数据的字符类型
*set_data_code_2d_param (DataCodeHandle, 'string_encoding', 'utf8')
list_image_files ('C:/Users/Administrator/Desktop/二维码/二维码', 'default', [], ImageFiles)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
* if (Index==2)
* invert_image (Image, ImageInvert)
* find_data_code_2d (ImageInvert, SymbolXLDs66, DataCodeHandle, [], [], ResultHandles66, DecodedDataStrings66)
* dev_disp_text ('找到的是D码ImageInvert:'+DecodedDataStrings66, 'window', 'top', 'left', 'black', [], [])
* stop ()
* continue
* endif
find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, [], [], ResultHandles, DecodedDataStrings) //查找D码
count_obj (SymbolXLDs, Number)
if (Number>0)
dev_disp_text ('找到的是D码:'+DecodedDataStrings, 'window', 'top', 'left', 'black', [], [])
else
find_data_code_2d (Image, SymbolXLDs1, DataCodeHandle1, [], [], ResultHandles1, DecodedDataStrings1)
if (|DecodedDataStrings1|>0)
dev_disp_text ('找到的是QR码:'+DecodedDataStrings1, 'window', 'top', 'left', 'black', [], [])
else
find_data_code_2d (Image, SymbolXLDs2, DataCodeHandle2, [], [], ResultHandles2, DecodedDataStrings2)
if (|DecodedDataStrings2|>0)
dev_disp_text ('找到的是PDF417码:'+DecodedDataStrings2, 'window', 'top', 'left', 'black', [], [])
else
dev_disp_text ('没找到的是二维码:', 'window', 'top', 'left', 'black', [], [])
endif
endif
endif
stop ()
endfor
多个二维码检测
*二维码检测
*创建二维码对象
*'default_parameters' 默认参数设置
*'maximum_recognition' 最大的识别度
create_data_code_2d_model ('QR Code', ['default_parameters'], ['maximum_recognition'], DataCodeHandle)
list_image_files ('D:/桌面/Halcon/2026.3.30halcon第八天/二维码', 'default', [], ImageFiles)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
* 'stop_after_result_num' 批量识别参数 找到16 个二维码后立即停止,提升效率
find_data_code_2d (Image, SymbolXLDs, DataCodeHandle, 'stop_after_result_num', 16, ResultHandles, DecodedDataStrings) //查找QR码
count_obj (SymbolXLDs, Number)
gen_region_contour_xld (SymbolXLDs, RegionQrCode, 'margin')
area_center (RegionQrCode, Area, Row, Column)
if (Number>0)
dev_disp_text ('找到的是QR码:'+DecodedDataStrings, 'image', Row, Column, 'black', [], [])
else
dev_disp_text ('没找到的是二维码:', 'window', 'top', 'left', 'black', [], [])
endif
stop ()
endfor
OCR字符识别
*ocr字符提取
*1 提取字符每一个区域
*2 读取内置的分类器或者自定义分类器 read_ocr_class_mlp()
*3 获取读取的结果
*4 处理结果释放句柄
*分类器
* NoRej 不拒绝,如果一个字符串没有匹配到 返回一个类似的字符
* Rej 拒绝 如果一个字符串没有匹配到 返回一个reject
*内置的分类器
*Document_0-9_NoRej.omc 、OCRA_A-Z+_Rej.omc
*自定义分类器 通过ocr助手进行设置
*字体是最好是黑色字体白色的背景
*read_image (Image, 'engraved')
read_image (Image, 'E:/halcon/data/HALCON-24.11-Progress-Steady/examples/images/ocr/airplane_ticket_01.png')
get_image_size (Image, Width, Height)
dev_set_draw ('margin')
dev_set_color ('green')
*矩形范围内阈值修改 使用7*7的矩阵 ,把里面像素最大值减去最小值,得到值作为图新值
gray_range_rect (Image, ImageResult, 7, 7)
invert_image (ImageResult, ImageInvert)
threshold (ImageResult, Region, 128,255)
connection (Region, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 1000, 99999)
sort_region (SelectedRegions, SortedRegions, 'first_point', 'true', 'column')
shape_trans (SortedRegions, RegionTrans, 'rectangle1')
area_center (RegionTrans, Area, Row, Column)
*读取ocr
read_ocr_class_mlp ('新建文本文档.omc', OCRHandle)
count_obj (RegionTrans, Number)
dev_display (Image)
for Index := 1 to Number by 1
select_obj (SortedRegions, ObjectSelected, Index) //选择一个字符区域
*获取单独结果
do_ocr_single_class_mlp (ObjectSelected, ImageInvert, OCRHandle, 1, Class, Confidence)
dev_disp_text (Class, 'image', Row[Index-1], Column[Index-1], 'black', [], [])
dev_display (RegionTrans)
stop ()
endfor
*一次性读取完
do_ocr_multi_class_mlp (SortedRegions, ImageInvert, OCRHandle, Class1, Confidence1)
环形条形码读取
*环形字符提取
read_image (Image, 'D:/桌面/Halcon/day08/9e8e7d760e832a6b1ffe932c2a7e6047_720.png')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width/2, Height/2, 'black', WindowHandle)
threshold (Image, Region, 0, 100)
closing_circle (Region, Region, 3.5)
connection (Region, ConnectedRegions)
*width和height 外接矩形的宽度和高度
select_shape (ConnectedRegions, SelectedRegions, ['width','height'], 'and', [550,550], [750,750])
shape_trans (SelectedRegions, RegionTrans, 'outer_circle')
*区域取反
complement (SelectedRegions, RegionComplement)
connection (RegionComplement, ConnectedRegions1)
select_shape (ConnectedRegions1, SelectedRegions1, ['width','height'], 'and', [480,480], [650,650])
smallest_circle (SelectedRegions, Row, Column, Radius)
gen_circle (Circle, Row, Column, Radius)
smallest_circle (SelectedRegions1, Row1, Column1, Radius1)
gen_circle (Circle1, Row1, Column1, Radius1)
dev_display (Image)
dev_display (Circle)
dev_set_color ('green')
dev_display (Circle1)
stop ()
*=================转换矩形==================
* 极坐标转换
* 参数1 输入的图片
* 参数2 输出图片
* 参数3,4 圆心坐标
* 参数5,6 转换的角度
* 参数7,8 两个半径 半径最小值和最大值
* 参数9,10 矩形的宽度和高度
Width1 := 1440
Height1 := round(Radius - Radius1 - 10)
polar_trans_image_ext (Image, PolarTransImage,Row, Column,rad(360), 0,Radius-5, Radius1+5, Width1, Height1,'nearest_neighbor')
invert_image (PolarTransImage, ImageInvert)
*缩放图片
zoom_image_factor (ImageInvert, ImageZoomed, 1, 2, 'weighted')
create_bar_code_model ([], [], BarCodeHandle)
find_bar_code (ImageZoomed, SymbolRegions, BarCodeHandle, 'auto', DecodedDataStrings)
* 展示
dev_set_window_extents (-1, -1, Width1, Height1)
dev_display (SymbolRegions)
dev_disp_text (DecodedDataStrings, 'window', 0, 0, 'black', [], [])
stop ()
* 展示到环形上
zoom_region (SymbolRegions, RegionZoom, 1, 0.5)
* 极坐标逆转换
polar_trans_region_inv (RegionZoom, XYTransRegion, Row, Column, rad(360), rad(0), Radius-5, Radius1+5, Width1, Height1, Width, Height, 'nearest_neighbor')
dev_set_window_extents (-1, -1, Width/2, Height/2)
dev_display(Image)
dev_display(XYTransRegion)
dev_disp_text (DecodedDataStrings, 'window', 0, 0, 'black', [], [])
封装函数
*本地函数,当前项目中可以使用
F1 (1, 2, c)
*外部函数,可以使用在其他项目中
read_image (Image, 'printer_chip/printer_chip_01')
Select_Region (Image, region, 128, 255, 2000, 99999)
联合编程
首先使用模板匹配快速生成代码
* 联合编程
read_image (Image, 'D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp')
gen_circle (ModelRegion, 695.889, 531.406, 126.737)
reduce_domain (Image, ModelRegion, TemplateImage)
create_generic_shape_model (ModelID)
set_generic_shape_model_param (ModelID, 'metric', 'use_polarity')
train_generic_shape_model (TemplateImage, ModelID)
get_shape_model_contours (ModelContours, ModelID, 1)
area_center (ModelRegion, ModelRegionArea, RefRow, RefColumn)
vector_angle_to_rigid (0, 0, 0, RefRow, RefColumn, 0, HomMat2D)
affine_trans_contour_xld (ModelContours, TransContours, HomMat2D)
dev_display (Image)
dev_set_color ('green')
dev_set_draw ('margin')
dev_display (ModelRegion)
dev_display (TransContours)
stop ()
set_generic_shape_model_param (ModelID, 'border_shape_models', 'false')
TestImages := ['D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424150956101.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151025909.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151103837.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151223821.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151314446.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151418749.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151424525.bmp','D:/桌面/Halcon/day05/快速匹配/Image_20220424151433765.bmp']
for T := 0 to 8 by 1
read_image (Image, TestImages[T])
find_generic_shape_model (Image, ModelID, MatchResultID, NumMatchResult)
dev_display (Image)
for I := 0 to NumMatchResult-1 by 1
get_generic_shape_model_result_object (MatchContour, MatchResultID, I, 'contours')
dev_set_color ('green')
dev_display (MatchContour)
get_generic_shape_model_result (MatchResultID, I, 'row', Row)
get_generic_shape_model_result (MatchResultID, I, 'column', Column)
get_generic_shape_model_result (MatchResultID, I, 'angle', Angle)
get_generic_shape_model_result (MatchResultID, I, 'scale_row', ScaleRow)
get_generic_shape_model_result (MatchResultID, I, 'scale_column', ScaleColumn)
get_generic_shape_model_result (MatchResultID, I, 'hom_mat_2d', HomMat2D)
get_generic_shape_model_result (MatchResultID, I, 'score', Score)
endfor
dev_disp_text ('个数:' + NumMatchResult, 'window', 0, 0, 'black', [], [])
stop ()
endfor
到处为c#代码,将action函数关键代码提取即可
//
// File generated by HDevelop for HALCON/.NET (C#) Version 24.11.1.0
// Non-ASCII strings in this file are encoded in local-8-bit encoding (cp936).
//
// Please note that non-ASCII characters in string constants are exported
// as octal codes in order to guarantee that the strings are correctly
// created on all systems, independent on any compiler settings.
//
// Source files with different encoding should not be mixed in one project.
//
using HalconDotNet;
public partial class HDevelopExport
{
#if !(NO_EXPORT_MAIN || NO_EXPORT_APP_MAIN)
public HDevelopExport()
{
// Default settings used in HDevelop
HOperatorSet.SetSystem("width", 512);
HOperatorSet.SetSystem("height", 512);
if (HalconAPI.isWindows)
HOperatorSet.SetSystem("use_window_thread","true");
action();
}
#endif
#if !NO_EXPORT_MAIN
// Main procedure
private void action()
{
// Local iconic variables
HObject ho_Image, ho_ModelRegion, ho_TemplateImage;
HObject ho_ModelContours, ho_TransContours, ho_MatchContour=null;
// Local control variables
HTuple hv_ModelID = new HTuple(), hv_ModelRegionArea = new HTuple();
HTuple hv_RefRow = new HTuple(), hv_RefColumn = new HTuple();
HTuple hv_HomMat2D = new HTuple(), hv_TestImages = new HTuple();
HTuple hv_T = new HTuple(), hv_MatchResultID = new HTuple();
HTuple hv_NumMatchResult = new HTuple(), hv_I = new HTuple();
HTuple hv_Row = new HTuple(), hv_Column = new HTuple();
HTuple hv_Angle = new HTuple(), hv_ScaleRow = new HTuple();
HTuple hv_ScaleColumn = new HTuple(), hv_Score = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_ModelRegion);
HOperatorSet.GenEmptyObj(out ho_TemplateImage);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_TransContours);
HOperatorSet.GenEmptyObj(out ho_MatchContour);
//联合编程
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, "D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp");
ho_ModelRegion.Dispose();
HOperatorSet.GenCircle(out ho_ModelRegion, 695.889, 531.406, 126.737);
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(ho_Image, ho_ModelRegion, out ho_TemplateImage);
hv_ModelID.Dispose();
HOperatorSet.CreateGenericShapeModel(out hv_ModelID);
HOperatorSet.SetGenericShapeModelParam(hv_ModelID, "metric", "use_polarity");
HOperatorSet.TrainGenericShapeModel(ho_TemplateImage, hv_ModelID);
ho_ModelContours.Dispose();
HOperatorSet.GetShapeModelContours(out ho_ModelContours, hv_ModelID, 1);
hv_ModelRegionArea.Dispose();hv_RefRow.Dispose();hv_RefColumn.Dispose();
HOperatorSet.AreaCenter(ho_ModelRegion, out hv_ModelRegionArea, out hv_RefRow,
out hv_RefColumn);
hv_HomMat2D.Dispose();
HOperatorSet.VectorAngleToRigid(0, 0, 0, hv_RefRow, hv_RefColumn, 0, out hv_HomMat2D);
ho_TransContours.Dispose();
HOperatorSet.AffineTransContourXld(ho_ModelContours, out ho_TransContours, hv_HomMat2D);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Image, HDevWindowStack.GetActive());
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetColor(HDevWindowStack.GetActive(), "green");
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ModelRegion, HDevWindowStack.GetActive());
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_TransContours, HDevWindowStack.GetActive());
}
// stop(...); only in hdevelop
HOperatorSet.SetGenericShapeModelParam(hv_ModelID, "border_shape_models", "false");
hv_TestImages.Dispose();
hv_TestImages = new HTuple();
hv_TestImages[0] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp";
hv_TestImages[1] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424150956101.bmp";
hv_TestImages[2] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151025909.bmp";
hv_TestImages[3] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151103837.bmp";
hv_TestImages[4] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151223821.bmp";
hv_TestImages[5] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151314446.bmp";
hv_TestImages[6] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151418749.bmp";
hv_TestImages[7] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151424525.bmp";
hv_TestImages[8] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151433765.bmp";
for (hv_T=0; (int)hv_T<=8; hv_T = (int)hv_T + 1)
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, hv_TestImages.TupleSelect(hv_T));
}
hv_MatchResultID.Dispose();hv_NumMatchResult.Dispose();
HOperatorSet.FindGenericShapeModel(ho_Image, hv_ModelID, out hv_MatchResultID,
out hv_NumMatchResult);
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_Image, HDevWindowStack.GetActive());
}
HTuple end_val36 = hv_NumMatchResult-1;
HTuple step_val36 = 1;
for (hv_I=0; hv_I.Continue(end_val36, step_val36); hv_I = hv_I.TupleAdd(step_val36))
{
ho_MatchContour.Dispose();
HOperatorSet.GetGenericShapeModelResultObject(out ho_MatchContour, hv_MatchResultID,
hv_I, "contours");
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetColor(HDevWindowStack.GetActive(), "green");
}
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_MatchContour, HDevWindowStack.GetActive());
}
hv_Row.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "row", out hv_Row);
hv_Column.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "column",
out hv_Column);
hv_Angle.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "angle",
out hv_Angle);
hv_ScaleRow.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "scale_row",
out hv_ScaleRow);
hv_ScaleColumn.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "scale_column",
out hv_ScaleColumn);
hv_HomMat2D.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "hom_mat_2d",
out hv_HomMat2D);
hv_Score.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "score",
out hv_Score);
}
if (HDevWindowStack.IsOpen())
{
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
HOperatorSet.DispText(HDevWindowStack.GetActive(), "个数:"+hv_NumMatchResult,
"window", 0, 0, "black", new HTuple(), new HTuple());
}
}
// stop(...); only in hdevelop
}
ho_Image.Dispose();
ho_ModelRegion.Dispose();
ho_TemplateImage.Dispose();
ho_ModelContours.Dispose();
ho_TransContours.Dispose();
ho_MatchContour.Dispose();
hv_ModelID.Dispose();
hv_ModelRegionArea.Dispose();
hv_RefRow.Dispose();
hv_RefColumn.Dispose();
hv_HomMat2D.Dispose();
hv_TestImages.Dispose();
hv_T.Dispose();
hv_MatchResultID.Dispose();
hv_NumMatchResult.Dispose();
hv_I.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
hv_Angle.Dispose();
hv_ScaleRow.Dispose();
hv_ScaleColumn.Dispose();
hv_Score.Dispose();
}
#endif
}
#if !(NO_EXPORT_MAIN || NO_EXPORT_APP_MAIN)
public class HDevelopExportApp
{
static void Main(string[] args)
{
new HDevelopExport();
}
}
#endif
创建c#项目,添加 Halcon 安装目录 bin/dotnet35/halcondotnet.dll 文件添加引用,接着引用命名空间
using HalconDotNet;,最后修改代码逻辑
思路如下:使用picturebox显示halcon图片实现自适应,每次点击切换图片
最终代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using HalconDotNet;
namespace 联合Halcon
{
public partial class Form1 : Form
{
// 1.添加 Halcon 安装目录 bin/dotnet35/halcondotnet.dll 文件,添加引用
// 2.添加命名空间 using HalconDotNet
public Form1()
{
InitializeComponent();
}
HTuple windowHandle = new HTuple();
HTuple hv_TestImages = new HTuple();
private void Form1_Load(object sender, EventArgs e)
{
// HOperatorSet C#中操作Halcon类
// Halcon在c#中使用 HTuple 数据类型
// 设置窗体背景色
HOperatorSet.SetWindowAttr("background_color", "black");
// 打开新窗体到 pictureBox
HOperatorSet.OpenWindow(0, 0, pictureBox1.Width, pictureBox1.Height, pictureBox1.Handle, "visible", "", out windowHandle);
hv_TestImages.Dispose();
hv_TestImages = new HTuple();
hv_TestImages[0] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp";
hv_TestImages[1] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424150956101.bmp";
hv_TestImages[2] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151025909.bmp";
hv_TestImages[3] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151103837.bmp";
hv_TestImages[4] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151223821.bmp";
hv_TestImages[5] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151314446.bmp";
hv_TestImages[6] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151418749.bmp";
hv_TestImages[7] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151424525.bmp";
hv_TestImages[8] = "D:/桌面/Halcon/day05/快速匹配/Image_20220424151433765.bmp";
// 显示halcon图片到pictureBox,并设置图片大小自适应
FitSize(hv_TestImages[0]);
}
public void FitSize(string path)
{
HObject ho_Image;// 定义图片
HTuple hv_width, hv_height = null;//定义图片大小
HTuple win_Row, win_Column, win_Width, win_height = null; //窗口的坐标和宽度和高度
HTuple cwin_Width, cwinHeight = null; // 计算出来展示的区域
// 读取图片
HOperatorSet.ReadImage(out ho_Image, path);
//获取图像大小
HOperatorSet.GetImageSize(ho_Image, out hv_width, out hv_height);
HOperatorSet.GetWindowExtents(windowHandle, out win_Row, out win_Column, out win_Width, out win_height);//获取窗口的大小
//计算展示的高度 a = c/d * b
cwinHeight = 1.0 * win_height / win_Width * hv_width; // 宽度不变计算高度
if (cwinHeight > hv_height) //上下留相等黑边
{
cwinHeight = 1.0 * (cwinHeight - hv_height) / 2;
//展示图像哪一部分 坐标原点在图像的左上角
HOperatorSet.SetPart(windowHandle, -cwinHeight, 0, cwinHeight + hv_height, hv_width);
HOperatorSet.DispObj(ho_Image, windowHandle);
}
else // 高度不变 宽度自适应
{
cwin_Width = 1.0 * win_Width / win_height * hv_height;
cwin_Width = 1.0 * (cwin_Width - hv_width) / 2;
HOperatorSet.SetPart(windowHandle, 0, -cwin_Width, hv_height, hv_width + cwin_Width);
HOperatorSet.DispObj(ho_Image, windowHandle);
}
}
int count = 0;
private void action()
{
// Local iconic variables
HObject ho_Image, ho_ModelRegion, ho_TemplateImage;
HObject ho_ModelContours, ho_TransContours, ho_MatchContour = null;
// Local control variables
HTuple hv_Width = new HTuple(), hv_Height = new HTuple();
HTuple hv_ModelID = new HTuple(), hv_ModelRegionArea = new HTuple();
HTuple hv_RefRow = new HTuple(), hv_RefColumn = new HTuple();
HTuple hv_HomMat2D = new HTuple();
HTuple hv_T = new HTuple(), hv_MatchResultID = new HTuple();
HTuple hv_NumMatchResult = new HTuple(), hv_I = new HTuple();
HTuple hv_Row = new HTuple(), hv_Column = new HTuple();
HTuple hv_Angle = new HTuple(), hv_ScaleRow = new HTuple();
HTuple hv_ScaleColumn = new HTuple(), hv_Score = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_ModelRegion);
HOperatorSet.GenEmptyObj(out ho_TemplateImage);
HOperatorSet.GenEmptyObj(out ho_ModelContours);
HOperatorSet.GenEmptyObj(out ho_TransContours);
HOperatorSet.GenEmptyObj(out ho_MatchContour);
//联合编程
hv_Width.Dispose(); hv_Height.Dispose();
// 获取图像大小
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
#region 模板匹配
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, "D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp");
//FitSize("D:/桌面/Halcon/day05/快速匹配/Image_20220424150926357.bmp");
ho_ModelRegion.Dispose();
HOperatorSet.GenCircle(out ho_ModelRegion, 695.889, 531.406, 126.737);
ho_TemplateImage.Dispose();
HOperatorSet.ReduceDomain(ho_Image, ho_ModelRegion, out ho_TemplateImage);
hv_ModelID.Dispose();
HOperatorSet.CreateGenericShapeModel(out hv_ModelID);
HOperatorSet.SetGenericShapeModelParam(hv_ModelID, "metric", "use_polarity");
HOperatorSet.TrainGenericShapeModel(ho_TemplateImage, hv_ModelID);
ho_ModelContours.Dispose();
HOperatorSet.GetShapeModelContours(out ho_ModelContours, hv_ModelID, 1);
#endregion
#region 获取模板匹配结果
hv_ModelRegionArea.Dispose(); hv_RefRow.Dispose(); hv_RefColumn.Dispose();
HOperatorSet.AreaCenter(ho_ModelRegion, out hv_ModelRegionArea, out hv_RefRow,
out hv_RefColumn);
hv_HomMat2D.Dispose();
HOperatorSet.VectorAngleToRigid(0, 0, 0, hv_RefRow, hv_RefColumn, 0, out hv_HomMat2D);
ho_TransContours.Dispose();
HOperatorSet.AffineTransContourXld(ho_ModelContours, out ho_TransContours, hv_HomMat2D);
#endregion
// 设置窗口参数
HOperatorSet.DispObj(ho_Image, windowHandle);
HOperatorSet.SetColor(windowHandle, "green");
HOperatorSet.SetDraw(windowHandle, "margin");
HOperatorSet.DispObj(ho_ModelRegion, windowHandle);
HOperatorSet.DispObj(ho_TransContours, windowHandle);
// 设置模板匹配参数
HOperatorSet.SetGenericShapeModelParam(hv_ModelID, "border_shape_models", "false");
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, hv_TestImages.TupleSelect(count));
}
// 查找模板匹配结果
hv_MatchResultID.Dispose(); hv_NumMatchResult.Dispose();
HOperatorSet.FindGenericShapeModel(ho_Image, hv_ModelID, out hv_MatchResultID,
out hv_NumMatchResult);
// 展示原图
HOperatorSet.DispObj(ho_Image, windowHandle);
HTuple scores = new HTuple(); // 所有得分
HTuple end_val36 = hv_NumMatchResult - 1;
HTuple step_val36 = 1;
for (hv_I = 0; hv_I.Continue(end_val36, step_val36); hv_I = hv_I.TupleAdd(step_val36))
{
// 获取模板匹配轮廓
ho_MatchContour.Dispose();
HOperatorSet.GetGenericShapeModelResultObject(out ho_MatchContour, hv_MatchResultID,
hv_I, "contours");
// 设置颜色
HOperatorSet.SetColor(windowHandle, "green");
// 显示模板匹配结果
HOperatorSet.DispObj(ho_MatchContour, windowHandle);
// 获取匹配结果参数
hv_Row.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "row", out hv_Row);
hv_Column.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "column",
out hv_Column);
hv_Angle.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "angle",
out hv_Angle);
hv_ScaleRow.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "scale_row",
out hv_ScaleRow);
hv_ScaleColumn.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "scale_column",
out hv_ScaleColumn);
hv_HomMat2D.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "hom_mat_2d",
out hv_HomMat2D);
hv_Score.Dispose();
HOperatorSet.GetGenericShapeModelResult(hv_MatchResultID, hv_I, "score",
out hv_Score);
scores[hv_I] = hv_Score; // 添加到元组
}
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
HOperatorSet.DispText(windowHandle, "个数:" + hv_NumMatchResult,
"window", 0, 0, "black", new HTuple(), new HTuple());
}
ho_Image.Dispose();
ho_ModelRegion.Dispose();
ho_TemplateImage.Dispose();
ho_ModelContours.Dispose();
ho_TransContours.Dispose();
ho_MatchContour.Dispose();
hv_ModelID.Dispose();
hv_ModelRegionArea.Dispose();
hv_RefRow.Dispose();
hv_RefColumn.Dispose();
hv_HomMat2D.Dispose();
hv_TestImages.Dispose();
hv_T.Dispose();
hv_MatchResultID.Dispose();
hv_NumMatchResult.Dispose();
hv_I.Dispose();
hv_Row.Dispose();
hv_Column.Dispose();
hv_Angle.Dispose();
hv_ScaleRow.Dispose();
hv_ScaleColumn.Dispose();
hv_Score.Dispose();
count++;
if (count == 9)
{
count = 0;
}
// 获取平均得分
HTuple mean = new HTuple();
mean.Dispose();
HOperatorSet.TupleMean(scores, out mean);
label1.Text = "平均得分:" + mean.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
action();
}
}
}
图片自适应
public void FitSize(string path)
{
HObject ho_Image;// 定义图片
HTuple hv_width, hv_height = null;//定义图片大小
HTuple win_Row, win_Column, win_Width, win_height = null; //窗口的坐标和宽度和高度
HTuple cwin_Width, cwinHeight = null; // 计算出来展示的区域
// 读取图片
HOperatorSet.ReadImage(out ho_Image, path);
//获取图像大小
HOperatorSet.GetImageSize(ho_Image, out hv_width, out hv_height);
HOperatorSet.GetWindowExtents(windowHandle, out win_Row, out win_Column, out win_Width, out win_height);//获取窗口的大小
//计算展示的高度 a = c/d * b
cwinHeight = 1.0 * win_height / win_Width * hv_width; // 宽度不变计算高度
if (cwinHeight > hv_height) //上下留相等黑边
{
cwinHeight = 1.0 * (cwinHeight - hv_height) / 2;
//展示图像哪一部分 坐标原点在图像的左上角
HOperatorSet.SetPart(windowHandle, -cwinHeight, 0, cwinHeight + hv_height, hv_width);
HOperatorSet.DispObj(ho_Image, windowHandle);
}
else // 高度不变 宽度自适应
{
cwin_Width = 1.0 * win_Width / win_height * hv_height;
cwin_Width = 1.0 * (cwin_Width - hv_width) / 2;
HOperatorSet.SetPart(windowHandle, 0, -cwin_Width, hv_height, hv_width + cwin_Width);
HOperatorSet.DispObj(ho_Image, windowHandle);
}
}
作业:模板匹配 + 字符识别(半导体)
* OCR字符识别作业
list_image_files ('D:/桌面/Halcon/2026.3.31halcon第九天/ocr1', 'default', [], ImageFiles)
dev_set_draw ('margin')
dev_set_color ('green')
* 读取字符识别库
read_ocr_class_mlp ('SEMI_Rej.omc', OCRHandle)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image, ImageFiles[Index])
* 动态阈值分割
mean_image (Image, ImageMean, 9, 9)
dyn_threshold (Image, ImageMean, RegionDynThresh, 5, 'light')
closing_circle (RegionDynThresh, RegionClosing, 2)
connection (RegionClosing, ConnectedRegions)
* 第一次通过宽高筛选
select_shape (ConnectedRegions, SelectedRegions, ['width','height'], 'and', [0,28.15], [30.04,55.46])
* 第二次通过行列筛选
area_center (SelectedRegions, Area, Row, Column)
mediaRow := median(Row)
select_shape (SelectedRegions, SelectedRegions1, 'row', 'and', mediaRow-50, mediaRow+50)
select_shape (SelectedRegions1, SelectedRegions2, 'column', 'and', 0, 600)
* 通过中心点填充区域为矩形
dev_display(Image)
shape_trans (SelectedRegions2, RegionTrans, 'rectangle1')
* 将原图颜色反转,进行字符识别
invert_image (Image, ImageInvert)
do_ocr_multi_class_mlp (RegionTrans, ImageInvert, OCRHandle, Class, Confidence)
* 显示匹配区域
dev_display(RegionTrans)
area_center (RegionTrans, Area1, Row1, Column1)
* 显示识别文字
dev_disp_text (Class, 'image', Row1 + 30, Column1 - 10, 'black', [], [])
stop ()
endfor
联合编程-测量内圆半径
* 完善联合编程项目
read_image (Image, 'D:/桌面/Halcon/day10/img/0.bmp')
dev_set_draw('margin')
dev_get_window (WindowHandle)
* 模板匹配区域
gen_circle (ROI_0, 788.195, 1250.11, 381.432)
reduce_domain (Image, ROI_0, ImageReduced)
* 创建模板匹配
create_shape_model (ImageReduced, 'auto', rad(0), rad(360), 'auto', 'auto', 'ignore_global_polarity', 'auto', 'auto', ModelID)
find_shape_model (Image, ModelID, rad(0), rad(360), 0.5, 1, 0.5, 'least_squares', 0, 0.9, Row, Column, Angle, Score)
dev_display_shape_matching_results (ModelID, 'red', Row, Column, Angle, 1, 1, 0)
* 创建卡尺工具
gen_circle (ROI_1, 790.6, 1250.11, 336.781)
create_metrology_model (MetrologyHandle)
* 添加卡尺类型
add_metrology_object_generic (MetrologyHandle, 'circle', [790.6, 1250.11, 336.781], 50, 5, 1, 30, [], [], Index)
* 应用卡尺工具
apply_metrology_model (Image, MetrologyHandle)
* 获取卡尺检测区域
get_metrology_object_measures (Contours, MetrologyHandle, 'all', 'all', Row1, Column1)
dev_set_color('green')
* 获取卡尺显示结果
get_metrology_object_result_contour (Contour, MetrologyHandle, 'all', 'all', 1.5)
* 绑定系统坐标系
set_metrology_model_param (MetrologyHandle, 'reference_system', [Row, Column, 0])
* disp_continue_message (WindowHandle, 'black', 'true')
* stop ()
list_image_files ('D:/桌面/Halcon/day10/img', 'default', [], ImageFiles)
for Index := 0 to |ImageFiles|-1 by 1
read_image (Image1, ImageFiles[Index])
find_shape_model (Image1, ModelID, -90, 90, 0.3, 1, 0.5, 'least_squares', 0, 0.9,Row2, Column2, Angle1, Score1)
dev_display_shape_matching_results (ModelID, 'red', Row2, Column2, Angle1, 1, 1, 0)
* 定位: 将卡尺绑定到模板匹配位置
align_metrology_model (MetrologyHandle, Row2, Column2, Angle1)
* 卡尺检测
apply_metrology_model (Image1, MetrologyHandle)
get_metrology_object_measures (Contours1, MetrologyHandle, 'all', 'all', Row3, Column3)
dev_set_color ('green')
get_metrology_object_result_contour (Contour1, MetrologyHandle, 0, 'all', 1.5)
get_metrology_object_result (MetrologyHandle, 0, 'all', 'result_type', 'all_param', Parameter)
dev_disp_text ('半径:' + Parameter[2], 'image', 0, 0, 'black', [], [])
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
endfor
上述是自己写的测量内圆半径的代码,下面是老师的halcon代码到处的c#代码,actiono为关键逻辑代码
// Main procedure
private void action()
{
// Local iconic variables
HObject ho_Image, ho_ResultImage=null, ho_ResultRegion=null;
HObject ho_ResultConnectedRegions=null, ho_ResultSelectedRegions=null;
HObject ho_ResultCircle=null, ho_ResultContour=null;
// Local control variables
HTuple hv_ImageFiles1 = new HTuple(), hv_Width = new HTuple();
HTuple hv_Height = new HTuple(), hv_WindowHandle = new HTuple();
HTuple hv_MetrologyHandle = new HTuple(), hv_CircleRadiusTolerance = new HTuple();
HTuple hv_NewRadius = new HTuple(), hv_Index = new HTuple();
HTuple hv_ResultArea = new HTuple(), hv_ResultRow = new HTuple();
HTuple hv_ResultColumn = new HTuple(), hv_MetrologyCircleIndice = new HTuple();
HTuple hv_CircleRadiusResult = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_ResultImage);
HOperatorSet.GenEmptyObj(out ho_ResultRegion);
HOperatorSet.GenEmptyObj(out ho_ResultConnectedRegions);
HOperatorSet.GenEmptyObj(out ho_ResultSelectedRegions);
HOperatorSet.GenEmptyObj(out ho_ResultCircle);
HOperatorSet.GenEmptyObj(out ho_ResultContour);
//读取一张图像
hv_ImageFiles1.Dispose();
list_image_files("C:/Users/Administrator/Desktop/img", "default", new HTuple(),
out hv_ImageFiles1);
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
ho_Image.Dispose();
HOperatorSet.ReadImage(out ho_Image, hv_ImageFiles1.TupleSelect(0));
}
//获取图像大小
hv_Width.Dispose();hv_Height.Dispose();
HOperatorSet.GetImageSize(ho_Image, out hv_Width, out hv_Height);
//打开窗口
HOperatorSet.SetWindowAttr("background_color","black");
HOperatorSet.OpenWindow(0,0,hv_Width/3,hv_Height/3,0,"visible","",out hv_WindowHandle);
HDevWindowStack.Push(hv_WindowHandle);
//1创建测量模型
hv_MetrologyHandle.Dispose();
HOperatorSet.CreateMetrologyModel(out hv_MetrologyHandle);
//2设置测量对象图像大小
HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
//环状区域宽度可允许范围
hv_CircleRadiusTolerance.Dispose();
hv_CircleRadiusTolerance = 100;
//圆半径
hv_NewRadius.Dispose();
hv_NewRadius = 324;
//加载多张离线图像
//Image Acquisition 01: Code generated by Image Acquisition 01
for (hv_Index=0; (int)hv_Index<=(int)((new HTuple(hv_ImageFiles1.TupleLength()
))-1); hv_Index = (int)hv_Index + 1)
{
//读取图像
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
ho_ResultImage.Dispose();
HOperatorSet.ReadImage(out ho_ResultImage, hv_ImageFiles1.TupleSelect(hv_Index));
}
//阈值图像
ho_ResultRegion.Dispose();
HOperatorSet.Threshold(ho_ResultImage, out ho_ResultRegion, 0, 60);
//区域连通
ho_ResultConnectedRegions.Dispose();
HOperatorSet.Connection(ho_ResultRegion, out ho_ResultConnectedRegions);
//根据面积和圆度来过滤想要的圆区域
ho_ResultSelectedRegions.Dispose();
HOperatorSet.SelectShape(ho_ResultConnectedRegions, out ho_ResultSelectedRegions,
(new HTuple("area")).TupleConcat("circularity"), "and", (new HTuple(250000)).TupleConcat(
0.9), (new HTuple(320000)).TupleConcat(1));
//获取圆的中心坐标和面积
hv_ResultArea.Dispose();hv_ResultRow.Dispose();hv_ResultColumn.Dispose();
HOperatorSet.AreaCenter(ho_ResultSelectedRegions, out hv_ResultArea, out hv_ResultRow,
out hv_ResultColumn);
//设置输出对象的颜色
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetColor(HDevWindowStack.GetActive(), "green");
}
//设置区域的填充模式
if (HDevWindowStack.IsOpen())
{
HOperatorSet.SetDraw(HDevWindowStack.GetActive(), "margin");
}
//显示图像
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ResultImage, HDevWindowStack.GetActive());
}
//生成圆
ho_ResultCircle.Dispose();
HOperatorSet.GenCircle(out ho_ResultCircle, hv_ResultRow, hv_ResultColumn,
hv_NewRadius);
//3 添加圆到测量模型里
hv_MetrologyCircleIndice.Dispose();
HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, hv_ResultRow,
hv_ResultColumn, hv_NewRadius, hv_CircleRadiusTolerance, 5, 1.5, 30, (new HTuple("measure_transition")).TupleConcat(
"min_score"), (new HTuple("all")).TupleConcat(0.4), out hv_MetrologyCircleIndice);
//4 测量并拟合几何形状
HOperatorSet.ApplyMetrologyModel(ho_ResultImage, hv_MetrologyHandle);
//5 获取测量模型里的测量轮廓
ho_ResultContour.Dispose();
HOperatorSet.GetMetrologyObjectResultContour(out ho_ResultContour, hv_MetrologyHandle,
"all", "all", 1.5);
//获取测量模型里的测量结果
hv_CircleRadiusResult.Dispose();
HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, hv_MetrologyCircleIndice,
"all", "result_type", "radius", out hv_CircleRadiusResult);
//显示图像
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ResultImage, HDevWindowStack.GetActive());
}
//显示测量轮廓
if (HDevWindowStack.IsOpen())
{
HOperatorSet.DispObj(ho_ResultContour, HDevWindowStack.GetActive());
}
//设置文字显示位置
HOperatorSet.SetTposition(hv_WindowHandle, 0, 0);
//在窗口指定位置输出文字信息
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
HOperatorSet.WriteString(hv_WindowHandle, "圆外径:"+hv_CircleRadiusResult);
}
// stop(...); only in hdevelop
}
//清除测量模型
HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
ho_Image.Dispose();
ho_ResultImage.Dispose();
ho_ResultRegion.Dispose();
ho_ResultConnectedRegions.Dispose();
ho_ResultSelectedRegions.Dispose();
ho_ResultCircle.Dispose();
ho_ResultContour.Dispose();
hv_ImageFiles1.Dispose();
hv_Width.Dispose();
hv_Height.Dispose();
hv_WindowHandle.Dispose();
hv_MetrologyHandle.Dispose();
hv_CircleRadiusTolerance.Dispose();
hv_NewRadius.Dispose();
hv_Index.Dispose();
hv_ResultArea.Dispose();
hv_ResultRow.Dispose();
hv_ResultColumn.Dispose();
hv_MetrologyCircleIndice.Dispose();
hv_CircleRadiusResult.Dispose();
}
联合winform修改后的完整项目
using HalconDotNet;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace 联合编程again
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
dataGridView1.AutoGenerateColumns = false;
}
HTuple hv_WindowHandle = new HTuple();
private void Form1_Load(object sender, EventArgs e)
{
// 打开一个 Halcon 窗体显示到 Picturebox
HOperatorSet.OpenWindow(0, 0, pictureBox1.Width, pictureBox1.Height, pictureBox1.Handle, "visible", "", out hv_WindowHandle);
HOperatorSet.SetFont(hv_WindowHandle, "微软雅黑-30");
// 获取图片宽高
GetImageSize(@"img/0.bmp");
// 加载一张图片
FitSize(@"img/0.bmp");
// 添加测试图片
LoadTestImage();
}
HObject image = new HObject();
HTuple hv_Width = new HTuple(); HTuple hv_Height = new HTuple();
public void GetImageSize(string path)
{
// 读取图片
HOperatorSet.ReadImage(out image, path);
// 获取图像宽高
HOperatorSet.GetImageSize(image, out hv_Width, out hv_Height);
//HOperatorSet.SetColor(hv_WindowHandle, "red");
//// 修改图片的显示部分
//HOperatorSet.SetPart(hv_WindowHandle, 0, 0, height, width);
//// 展示图片
//HOperatorSet.DispImage(image, hv_WindowHandle);
}
public void FitSize(string path)
{
HObject ho_Image;// 定义图片
HTuple hv_width, hv_height = null;//定义图片大小
HTuple win_Row, win_Column, win_Width, win_height = null; //窗口的坐标和宽度和高度
HTuple cwin_Width, cwinHeight = null; // 计算出来展示的区域
// 读取图片
HOperatorSet.ReadImage(out ho_Image, path);
//获取图像大小
HOperatorSet.GetImageSize(ho_Image, out hv_width, out hv_height);
HOperatorSet.GetWindowExtents(hv_WindowHandle, out win_Row, out win_Column, out win_Width, out win_height);//获取窗口的大小
//计算展示的高度 a = c/d * b
cwinHeight = 1.0 * win_height / win_Width * hv_width; // 宽度不变计算高度
if (cwinHeight > hv_height) //上下留相等黑边
{
cwinHeight = 1.0 * (cwinHeight - hv_height) / 2;
//展示图像哪一部分 坐标原点在图像的左上角
HOperatorSet.SetPart(hv_WindowHandle, -cwinHeight, 0, cwinHeight + hv_height, hv_width);
HOperatorSet.DispObj(ho_Image, hv_WindowHandle);
}
else // 高度不变 宽度自适应
{
cwin_Width = 1.0 * win_Width / win_height * hv_height;
cwin_Width = 1.0 * (cwin_Width - hv_width) / 2;
HOperatorSet.SetPart(hv_WindowHandle, 0, -cwin_Width, hv_height, hv_width + cwin_Width);
HOperatorSet.DispObj(ho_Image, hv_WindowHandle);
}
}
// 加载所有图片
HObject[] imgArr;
string[] fileDirs;
public void LoadTestImage()
{
fileDirs = Directory.GetFiles(@"img");
imgArr = new HObject[fileDirs.Length];
for (int i = 0; i < fileDirs.Length; i++)
{
HOperatorSet.ReadImage(out imgArr[i], fileDirs[i]);
}
}
// 开始事件
Thread th1;
bool isStart = false; // 开启while循环的条件(是否开始测量图片)
private void button1_Click(object sender, EventArgs e)
{
th1 = new Thread(startMeasure);
th1.Start();
isStart = true;
}
int count = 0;
List<Data> data = new List<Data>(); // 存储表格数据
public void startMeasure()
{
while (isStart)
{
// 获取图像宽高
GetImageSize(fileDirs[count]);
FitSize(fileDirs[count]);
#region 视觉处理
// Local iconic variables
HObject ho_Image, ho_ResultImage = null, ho_ResultRegion = null;
HObject ho_ResultConnectedRegions = null, ho_ResultSelectedRegions = null;
HObject ho_ResultCircle = null, ho_ResultContour = null;
// Local control variables
HTuple hv_ImageFiles1 = new HTuple();
HTuple hv_MetrologyHandle = new HTuple(), hv_CircleRadiusTolerance = new HTuple();
HTuple hv_NewRadius = new HTuple(), hv_Index = new HTuple();
HTuple hv_ResultArea = new HTuple(), hv_ResultRow = new HTuple();
HTuple hv_ResultColumn = new HTuple(), hv_MetrologyCircleIndice = new HTuple();
HTuple hv_CircleRadiusResult = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_ResultImage);
HOperatorSet.GenEmptyObj(out ho_ResultRegion);
HOperatorSet.GenEmptyObj(out ho_ResultConnectedRegions);
HOperatorSet.GenEmptyObj(out ho_ResultSelectedRegions);
HOperatorSet.GenEmptyObj(out ho_ResultCircle);
HOperatorSet.GenEmptyObj(out ho_ResultContour);
////打开窗口
//HOperatorSet.SetWindowAttr("background_color", "black");
//HOperatorSet.OpenWindow(0, 0, hv_Width / 3, hv_Height / 3, 0, "visible", "", out hv_WindowHandle);
//HDevWindowStack.Push(hv_WindowHandle);
//1创建测量模型
HOperatorSet.CreateMetrologyModel(out hv_MetrologyHandle);
//2设置测量对象图像大小
HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
//环状区域宽度可允许范围
hv_CircleRadiusTolerance.Dispose();
hv_CircleRadiusTolerance = 100;
//圆半径
hv_NewRadius = 324;
//加载多张离线图像
//读取图像
image = imgArr[count]; // 全局图片
ho_ResultImage = imgArr[count];
//阈值图像
HOperatorSet.Threshold(ho_ResultImage, out ho_ResultRegion, 0, 60);
//区域连通
HOperatorSet.Connection(ho_ResultRegion, out ho_ResultConnectedRegions);
//根据面积和圆度来过滤想要的圆区域
ho_ResultSelectedRegions.Dispose();
HOperatorSet.SelectShape(ho_ResultConnectedRegions, out ho_ResultSelectedRegions,
(new HTuple("area")).TupleConcat("circularity"), "and", (new HTuple(250000)).TupleConcat(
0.9), (new HTuple(320000)).TupleConcat(1));
//获取圆的中心坐标和面积
hv_ResultArea.Dispose(); hv_ResultRow.Dispose(); hv_ResultColumn.Dispose();
HOperatorSet.AreaCenter(ho_ResultSelectedRegions, out hv_ResultArea, out hv_ResultRow,
out hv_ResultColumn);
//设置输出对象的颜色
HOperatorSet.SetColor(hv_WindowHandle, "green");
//显示图像
HOperatorSet.DispObj(ho_ResultImage, hv_WindowHandle);
//生成圆
ho_ResultCircle.Dispose();
HOperatorSet.GenCircle(out ho_ResultCircle, hv_ResultRow, hv_ResultColumn,
hv_NewRadius);
//3 添加圆到测量模型里
hv_MetrologyCircleIndice.Dispose();
HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, hv_ResultRow,
hv_ResultColumn, hv_NewRadius, hv_CircleRadiusTolerance, 5, 1.5, 30, (new HTuple("measure_transition")).TupleConcat(
"min_score"), (new HTuple("all")).TupleConcat(0.4), out hv_MetrologyCircleIndice);
//4 测量并拟合几何形状
HOperatorSet.ApplyMetrologyModel(ho_ResultImage, hv_MetrologyHandle);
//5 获取测量模型里的测量轮廓
ho_ResultContour.Dispose();
HOperatorSet.GetMetrologyObjectResultContour(out ho_ResultContour, hv_MetrologyHandle,
"all", "all", 1.5);
//获取测量模型里的测量结果
hv_CircleRadiusResult.Dispose();
HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, hv_MetrologyCircleIndice,
"all", "result_type", "radius", out hv_CircleRadiusResult);
//显示图像
HOperatorSet.DispObj(ho_ResultImage, hv_WindowHandle);
//显示测量轮廓
HOperatorSet.DispObj(ho_ResultContour, hv_WindowHandle);
//设置文字显示位置
HOperatorSet.SetTposition(hv_WindowHandle, 0, 0);
//在窗口指定位置输出文字信息
using (HDevDisposeHelper dh = new HDevDisposeHelper())
{
HOperatorSet.WriteString(hv_WindowHandle, "圆外径:" + hv_CircleRadiusResult);
}
if (!Directory.Exists("img/ok"))
{
Directory.CreateDirectory("img/ok");
}
if (!Directory.Exists("img/ng"))
{
Directory.CreateDirectory("img/ng");
}
string end = "";
// 保存图片
if ((double)hv_CircleRadiusResult > 312)
{
// OK
end = "OK";
HOperatorSet.DumpWindow(hv_WindowHandle, "bmp", @"img/ok/" + DateTime.Now.ToString("yyyy-dd-MM-hh-mm-ss-fff"));
}
else
{
end = "NG";
// NG
HOperatorSet.DumpWindow(hv_WindowHandle, "bmp", @"img/ng/" + DateTime.Now.ToString("yyyy-dd-MM-hh-mm-ss-fff"));
}
data.Add(new Data()
{
id = count,
radius = (double)hv_CircleRadiusResult,
result = end
});
dataGridView1.Invoke(new Action(() =>
{
dataGridView1.DataSource = null;
dataGridView1.DataSource = data;
}));
//清除测量模型
HOperatorSet.ClearMetrologyModel(hv_MetrologyHandle);
#endregion
count++;
if (count == fileDirs.Length)
{
count = 0;
}
Thread.Sleep(1000);
}
}
// 停止事件
private void button2_Click(object sender, EventArgs e)
{
isStart = false;
}
// 交互测量
private void button3_Click(object sender, EventArgs e)
{
// 测量圆半径
HObject ho_Image, ho_Circle;
// Local control variables
HTuple hv_Row = new HTuple(), hv_Column = new HTuple(), hv_Radius = new HTuple();
HTuple hv_MetrologyHandle = new HTuple();
HTuple hv_MetrologyCircleIndice = new HTuple();
HObject ho_ResultContour = null;
HTuple hv_CircleRadiusResult = new HTuple();
// Initialize local and output iconic variables
HOperatorSet.GenEmptyObj(out ho_Image);
HOperatorSet.GenEmptyObj(out ho_Circle);
// 获取当前全局的图片
ho_Image = image;
HOperatorSet.SetColor(hv_WindowHandle, "red");
HOperatorSet.SetDraw(hv_WindowHandle, "margin");
// 手动绘制圆
HOperatorSet.DrawCircle(hv_WindowHandle, out hv_Row, out hv_Column, out hv_Radius);
HOperatorSet.GenCircle(out ho_Circle, hv_Row, hv_Column, hv_Radius);
HOperatorSet.DispObj(ho_Circle, hv_WindowHandle);
//1创建测量模型
HOperatorSet.CreateMetrologyModel(out hv_MetrologyHandle);
//2设置测量对象图像大小
HOperatorSet.SetMetrologyModelImageSize(hv_MetrologyHandle, hv_Width, hv_Height);
//3 添加圆到测量模型里
HOperatorSet.AddMetrologyObjectCircleMeasure(hv_MetrologyHandle, hv_Row, hv_Column, hv_Radius, 100, 5, 1.5, 30, (new HTuple("measure_transition")).TupleConcat(
"min_score"), (new HTuple("all")).TupleConcat(0.4), out hv_MetrologyCircleIndice);
// 设置卡尺数量
HOperatorSet.SetMetrologyObjectParam(hv_MetrologyHandle, "all", "num_measures", 10);
//4 测量并拟合几何形状
HOperatorSet.ApplyMetrologyModel(image, hv_MetrologyHandle);
//5 获取测量模型里的测量轮廓
HOperatorSet.GetMetrologyObjectResultContour(out ho_ResultContour, hv_MetrologyHandle,
"all", "all", 1.5);
// 显示测量卡尺
HObject contours = new HObject();
HTuple row = new HTuple(), column = new HTuple();
HOperatorSet.GetMetrologyObjectMeasures(out contours, hv_MetrologyHandle, "all", "all", out row, out column);
HOperatorSet.DispObj(contours, hv_WindowHandle);
// 获取测量结果
HObject contour1 = new HObject();
HOperatorSet.GetMetrologyObjectResultContour(out contour1, hv_MetrologyHandle, "all", "all", 1.5);
HOperatorSet.SetColor(hv_WindowHandle, "green");
HOperatorSet.DispObj(contour1, hv_WindowHandle);
//获取测量模型里的测量结果值
hv_CircleRadiusResult.Dispose();
HOperatorSet.GetMetrologyObjectResult(hv_MetrologyHandle, hv_MetrologyCircleIndice,
"all", "result_type", "radius", out hv_CircleRadiusResult);
MessageBox.Show(hv_CircleRadiusResult.ToString());
}
// 创建模型
HTuple modelID = new HTuple();
HTuple metrologyHandle = new HTuple();
private void button4_Click(object sender, EventArgs e)
{
HTuple row = new HTuple(), column = new HTuple();
HTuple phi = new HTuple();
HTuple length1 = new HTuple(), length2 = new HTuple();
HOperatorSet.SetColor(hv_WindowHandle, "red");
HOperatorSet.DrawRectangle2(hv_WindowHandle, out row, out column, out phi, out length1, out length2);
HObject rectangle = new HObject();
HOperatorSet.GenRectangle2(out rectangle, row, column, phi, length1, length2);
HObject imageReduced = new HObject();
HOperatorSet.ReduceDomain(image, rectangle, out imageReduced);
// 创建模板匹配
HOperatorSet.CreateShapeModel(imageReduced, "auto", -3.14, 3.14, "auto", "auto", "use_polarity", "auto", "auto",out modelID);
// 查找模板匹配结果
HTuple row1 = new HTuple(), column1 = new HTuple();
HTuple angle = new HTuple(), score = new HTuple();
HOperatorSet.FindShapeModel(image, modelID, -3.14, 3.14, 0.5, 1, 0.5, "least_squares", 0, 0.9, out row1, out column1, out angle, out score);
// 显示模板匹配结果
HObject modelContours = new HObject();
HOperatorSet.GetShapeModelContours(out modelContours, modelID, 1);
// 仿射变换
HTuple homMat2D = new HTuple();
HOperatorSet.VectorAngleToRigid(0, 0, 0, row1, column1, angle, out homMat2D);
HObject modelContoursAffineTrans = new HObject();
HOperatorSet.AffineTransContourXld(modelContours, out modelContoursAffineTrans, homMat2D);
// 显示模板匹配结果
HOperatorSet.DispObj(modelContoursAffineTrans, hv_WindowHandle);
// 绘制测量区域
// 第一条线
HTuple row2 = new HTuple(), column2 = new HTuple(), row3 = new HTuple(), column3 = new HTuple();
HOperatorSet.DrawLine(hv_WindowHandle, out row2, out column2, out row3, out column3);
HObject regionLine1 = new HObject();
HOperatorSet.GenRegionLine(out regionLine1, row2, column2, row3, column3);
// 第二条线
HTuple row4 = new HTuple(), column4 = new HTuple(), row5 = new HTuple(), column5 = new HTuple();
HOperatorSet.DrawLine(hv_WindowHandle, out row4, out column4, out row5, out column5);
HObject regionLine2 = new HObject();
HOperatorSet.GenRegionLine(out regionLine2, row4, column4, row5, column5);
// 创建绘制对象
HOperatorSet.CreateMetrologyModel(out metrologyHandle);
HOperatorSet.SetMetrologyModelImageSize(metrologyHandle, hv_Width, hv_Height);
HTuple shapeParam = new HTuple(
row2, column2, row3, column3,
row4, column4, row5, column5
);
HTuple Index = new HTuple();
HOperatorSet.AddMetrologyObjectGeneric(metrologyHandle, "line", shapeParam, 50, 10, 1, 30, new HTuple(), new HTuple(), out Index);
HOperatorSet.ApplyMetrologyModel(image, metrologyHandle);
HTuple rRow = new HTuple(), rColumn = new HTuple();
HObject contours = new HObject();
HOperatorSet.GetMetrologyObjectMeasures(out contours, metrologyHandle, "all", "all", out rRow, out rColumn);
HObject rContour = new HObject();
HOperatorSet.GetMetrologyObjectResultContour(out rContour, metrologyHandle, "all", "all", 1.5);
//set_metrology_model_param(MetrologyHandle, 'reference_system', [Row, Column, 0])
HTuple referenceSystem = new HTuple(row1, column1, new HTuple(0));
HOperatorSet.SetMetrologyModelParam(metrologyHandle, "reference_system", referenceSystem);
HOperatorSet.DispObj(contours, hv_WindowHandle);
HOperatorSet.SetColor(hv_WindowHandle, "green");
HOperatorSet.DispObj(rContour, hv_WindowHandle);
}
// 测量宽度
private void button5_Click(object sender, EventArgs e)
{
// 首先调用模板匹配获取模板的位置
HTuple row = new HTuple(), column = new HTuple(), angle = new HTuple(), score = new HTuple();
HOperatorSet.FindShapeModel(image, modelID, -3.14, 3.14, 0.1, 1, 0.5, "least_squares", 0, 0.9, out row, out column, out angle, out score);
HTuple empty = new HTuple();
if (row == empty || column == empty || angle == empty || score == empty)
{
HOperatorSet.DispText(hv_WindowHandle, "没有找到模板匹配结果", "image", 12, 12, "block", new HTuple(), new HTuple());
return;
}
else
{
// 模板对齐
HOperatorSet.AlignMetrologyModel(metrologyHandle, row, column, angle);
// 测量模板匹配后的距离
HOperatorSet.ApplyMetrologyModel(image, metrologyHandle);
HTuple rRow = new HTuple(), rColumn = new HTuple();
HObject contours = new HObject();
HOperatorSet.GetMetrologyObjectMeasures(out contours, metrologyHandle, "all", "all", out rRow, out rColumn);
HObject rContour = new HObject();
HOperatorSet.GetMetrologyObjectResultContour(out rContour, metrologyHandle, "all", "all", 1.5);
HTuple line1 = new HTuple();
HOperatorSet.GetMetrologyObjectResult(metrologyHandle, 0, "all", "result_type", "all_param", out line1);
HTuple line2 = new HTuple();
HOperatorSet.GetMetrologyObjectResult(metrologyHandle, 1, "all", "result_type", "all_param", out line2);
if (line1 != empty && line2 != empty)
{
// 取出第一条线的中点
//line1[0].D 获取 HTuple 索引为 0 的值 .D 为 double 类型
double midRow = (line1[0].D + line1[2].D) / 2.0;
double midCol = (line1[1].D + line1[3].D) / 2.0;
// 获取第一条线中点到第二条线的距离
HTuple distance = new HTuple();
HOperatorSet.DistancePl(midRow, midCol, line2[0], line2[1], line2[2], line2[3],out distance);
//MessageBox.Show($"距离: {distance.D:F2}");
HOperatorSet.DispText(hv_WindowHandle, $"距离: {distance.D:F2}", "image", 100, 100, "black", new HTuple(), new HTuple());
}
HOperatorSet.DispObj(contours, hv_WindowHandle);
HOperatorSet.SetColor(hv_WindowHandle, "green");
HOperatorSet.DispObj(rContour, hv_WindowHandle);
}
}
}
}

浙公网安备 33010602011771号