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就可以创建匹配模板

image-20260326174332390

image-20260326174518398

image-20260326174617298

image-20260326174659828

image-20260326174756439

插入代码如下

* 匹配助手


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);
            }
                
        }
    }
}
posted @ 2026-04-08 19:20  Junglezt  阅读(214)  评论(0)    收藏  举报