Halcon自定义直线卡尺rake


摘自鸟叔教程。

1. 为什么要开发rake工具

  • halcon提供给我们使用的测量矩形只能返回一个点,操作起来比较复杂,实际项目中不好使用;
  • 为了提高工具的通用性,鲁棒性,也是为了提高项目的开发效率,基于halcon已有的算子进一步开发工具是比较不错的选择。
  • rake工具是用来检测直线的,通过鼠标画一条线,然后工具根据已设定好的参数去附近区域寻找并拟合直线,返回这条直线。两条直线就可以计算交点了。
  • rake工具封装了三个函数来完成,代码不少,下面我就来展示详细的代码和实际效果。

2. rake工具封装的三个函数

2.1 创建ROI的函数:draw_rake

【函数】
draw_rake( : Regions : WindowHandle, Elements, DetectHeight, DetectWidth : Row1, Column1, Row2, Column2)

【参数】

参数描述
Regions(输出)输出边缘点检测区域及检测方向
WindowHandle(输入)图形窗口句柄
Element(输入)检测边缘数
DetectHeight(输入)检测边缘的卡尺工具的高度
DetectWidth(输入)检测边缘的卡尺工具的宽度
Row1(输出)检测区域起点Y
Column1(输出)检测区域起点X
Row2(输出)检测区域终点Y
Column2(输出)检测区域终点X

【函数实现】

*提示
disp_message (WindowHandle, '点击鼠标左键画一条直线,点击右键确认', 'window', 12, 12, 'red', 'false')
*产生一个空显示对象,用于显示
gen_empty_obj (Regions)
*画矢量检测直线
draw_line (WindowHandle, Row1, Column1, Row2, Column2)
*产生直线xld
gen_contour_polygon_xld (RegionLines, [Row1,Row2], [Column1,Column2])
*存储到显示对象
concat_obj (Regions, RegionLines, Regions)
*计算直线与x轴的夹角,逆时针方向为正
angle_lx(Row1,Column1,Row2,Column2,ATan)
*边缘检测方向垂直于检测直线:直线方向正向旋转90°为边缘检测方向
ATan := ATan+rad(90)
*根据检测直线按顺序产生测量区域矩形,并存储到显示对象
for i:=1 to Elements by 1
       *如果只有一个测量矩形,作为卡尺工具,宽度为检测直线的长度
       if(Elements==1)
              RowC:=(Row1+Row2)*0.5
              ColC:=(Column1+Column2)*0.5
              distance_pp (Row1, Column1, Row2, Column2, Distance)
              gen_rectangle2_contour_xld (Rectangle, RowC, ColC, ATan, DetectHeight/2, Distance/2)
       else
              *如果有多个测量矩形,产生该测量矩形xld
              RowC:=Row1+(((Row2-Row1)*(i-1))/(Elements-1))
              ColC:=Column1+(Column2-Column1)*(i-1)/(Elements-1)
              gen_rectangle2_contour_xld (Rectangle, RowC, ColC, ATan, DetectHeight/2, DetectWidth/2)
       endif
       *把测量矩形xld存储到显示对象
       concat_obj(Regions, Rectangle,Regions)
       if(i==1)
              *在第一个测量矩形绘制一个箭头xld,用于知识边缘检测方向
              RowL2 := RowC+DetectHeight/2*sin(-ATan)
              RowL1 := RowC-DetectHeight/2*sin(-ATan)
              ColL2 := ColC+DetectHeight/2*cos(-ATan)
              ColL1 := ColC-DetectHeight/2*cos(-ATan)
              gen_arrow_contour_xld (Arrow, RowL1, ColL1, RowL2, ColL2, 25, 25)
       endif
endfor
return ()

2.2 边缘测量的函数:rake

【函数】
rake(Image : Regions : Elements, DetectHeight, DetectWidth, Sigma, Threshold, Transition, Select, Row1, Column1, Row2, Column2 : ResultRow, ResultColumn)

【参数】

参数描述
Image(输入)输入图像
Regions(输出)输出边缘检测ROI及检测方向
Elements(输入)检测边缘的数量
DetectHeight(输入)卡尺工具的高度
DetectWidth(输入)卡尺工具的宽度
Sigma(输入)高斯滤波因子
Threshold(输入)边缘幅度阈值。边缘幅度大于该值作为参考边缘,小于该值不是边缘
Transition(输入)极性:positive表示由黑到白,negative表示由白到黑,all表示以上两种方向
Select(输入)first表示选择第一点,last表示选择最后一点,max表示选择边缘幅度最强点
Row1(输入)直线ROI起点Y
Column1(输入)直线ROI起点X
Row2(输入)直线ROI终点Y
Column2(输入)直线ROI终点X
ResultRow(输出)检测到的边缘的Y坐标数组
ResultColumn(输出)检测到的边缘的X坐标数组

【函数实现】

SelectOut := Select
TransitionOut := Transition
*获取图像尺寸
get_image_size(Image,Width,Height)
*产生一个空显示对象,用于显示
gen_empty_obj (Regions)
*初始化边缘坐标数组
ResultRow:=[]
ResultColumn:=[]
*产生直线xld
gen_contour_polygon_xld (RegionLines, [Row1,Row2], [Column1,Column2])
*存储到显示对象
concat_obj (Regions, RegionLines, Regions)
*计算直线与x轴的夹角,逆时针方向为正向
angle_lx (Row1, Column1, Row2, Column2, ATan)

*边缘检测方向垂直由于检测直线:直线方向正向旋转90°为边缘检测方向
ATan:=ATan+rad(90)

*根据检测直线按顺序产生测量区域矩形,并存储到显示对象
for i:=1 to Elements by 1
     *如果只有一个测量矩形,作为卡尺工具,宽度为检测直线的长度
     if(Elements == 1)
            RowC:=(Row1+Row2)*0.5
            ColC:=(Column1+Column2)*0.5
            *判断是否超出图像,超出不检测边缘
            if(RowC>Height-1 or RowC<0 or ColC>Width-1 or ColC<0)
                   continue
            endif
            distance_pp(Row1, Column1, Row2, Column2, Distance)
            DetectWidth:=Distance
            gen_rectangle2_contour_xld (Rectangle, RowC, ColC, ATan, DetectHeight/2, Distance/2)
     else
            *如果有多个测量矩形,产生该测量矩形xld
            RowC:=Row1+(((Row2-Row1)*(i-1))/(Elements-1))
            ColC:=Column1+(Column2-Column1)*(i-1)/(Elements-1)
            *判断是否超出图像,超出不检测边缘
            if(RowC>Height-1 or RowC<0 or ColC>Width-1 or ColC<0)
                   continue
            endif
            gen_rectangle2_contour_xld (Rectangle, RowC, ColC, ATan, DetectHeight/2, DetectWidth/2)
     endif
     
     *把测量矩形xld存储到显示对象
     concat_obj (Regions, Rectangle, Regions)
     if(i==1)
            *在第一个测量矩形绘制一个箭头xld,用于指示边缘检测方向
            RowL2:=RowC+DetectHeight/2*sin(-ATan)
            RowL1:=RowC-DetectHeight/2*sin(-ATan)
            ColL2:=ColC+DetectHeight/2*cos(-ATan)
            ColL1:=ColC-DetectHeight/2*cos(-ATan)
            gen_arrow_contour_xld (Arrow1, RowL1, ColL1, RowL2, ColL2, 25, 25)
            *把xld存储到显示对象
            concat_obj (Regions, Arrow1, Regions)
     endif
     *产生测量对象句柄
     gen_measure_rectangle2 (RowC, ColC, ATan, DetectHeight/2, DetectWidth/2, Width, Height, 'nearest_neighbor', MeasureHandle)

     *设置极性
       if (TransitionOut=='negative')
              TransitionOut := 'negative'
       elseif (TransitionOut=='positive')
              TransitionOut := 'positive'
     else
              TransitionOut := 'all'
     endif
     *设置边缘位置。最强点是从所有边缘中选择幅度绝对值对大点,需要设置为'all'
       if (SelectOut=='first')
              SelectOut := 'first'
       elseif (SelectOut=='last')
              SelectOut := 'last'
     else
              SelectOut := 'all'
     endif
     *检测边缘
       measure_pos (Image, MeasureHandle, Sigma, Threshold, TransitionOut, SelectOut, RowEdge, ColEdge, Amplitude, Distance)
     *清除测量对象句柄
     close_measure (MeasureHandle)
     
     *临时变量初始化
     *保存找到指定边缘的坐标
     tRow:=0
     tCol:=0
     *保存边缘的幅度绝对值
     t:=0
     *找到的边缘必须至少为1个
     tuple_length (RowEdge, Number)
     if(Number<1)
            continue
     endif
     
     *有多个边缘时,选择幅度绝对之后最大的边缘
     for j:= 0 to Number-1 by 1
            if(abs(Amplitude[j])>t)
                   tRow:=RowEdge[j]
                   tCol:=ColEdge[j]
                   t:=abs(Amplitude)
            endif
     endfor
     *把找到的边缘保存在输出数组
     if(t>0)
            ResultRow:=[ResultRow,tRow]
            ResultColumn:=[ResultColumn,tCol]
     endif
endfor
return ()

2.3 拟合直线的函数:pts_to_best_line

【函数】
pts_to_best_line( : Line : Rows, Cols, ActiveNum : Row1, Column1, Row2, Column2)

【参数】

参数描述
Line(输出)输出拟合直线的xld
Rows(输入)拟合直线的输入Y数组
Cols(输入)拟合直线的输入X数组
ActiveNum(输入)最小有效点数
Row1(输出)拟合的直线起点Y值
Column1(输出)拟合的直线起点X值
Row2(输出)拟合的直线终点Y值
Column2(输出)拟合的直线终点X值

【函数实现】

*初始化
Row1:=0
Column1:=0
Row2:=0
Column2:=0
*产生一个空的直线对象,用于保存拟合后的直线
gen_empty_obj (Line)
*计算边缘数量
tuple_length (Cols, Length)
*当边缘数量不小于有效点数时进行拟合
if(Length>=ActiveNum and ActiveNum>1)
       *halcon的拟合是基于xld的,需要把边缘连接成xld
       gen_contour_polygon_xld (Contour, Rows, Cols)
       *拟合直线。使用的算法是'tukey',其他算法参考fit_line_contour_xld的描述
       fit_line_contour_xld (Contour, 'tukey', -1, 0, 5, 2, Row1, Column1, Row2, Column2, Nr, Nc, Dist)
       *判断拟合结果是否有效:如果拟合成功,数组中元素的数量大于0
       tuple_length (Dist, Length1)
       if(Length1 < 1)
              return()             
       endif
       *根据拟合结果,产生直线xld
       gen_contour_polygon_xld (Line, [Row1,Row2], [Column1,Column2])
endif
return ()

3. rake工具使用示例

  • 如下图就是使用上面的三条函数得到的效果,红色的线是鼠标画出的,蓝色直线是抓取到并返回的直线。
    在这里插入图片描述
  • Talk is cheap, Show you my code
read_image(Image, '矩形.png')
dev_get_window (WindowHandle)
dev_set_color ('dark olive green')

* 1. 创建ROI draw_rake函数
Elements:=20
DetectHeight:=50
DetectWidth:=5
draw_rake (Regions, WindowHandle, Elements, DetectHeight, DetectWidth, Row1, Column1, Row2, Column2)

* 2. 边缘测量 rake函数
Sigma:=3
Threshold:=30
Transition:='all'
Select:='all'
rake (Image, Regions, Elements, DetectHeight, DetectWidth, Sigma, Threshold, Transition, Select, Row1, Column1, Row2, Column2, ResultRow, ResultColumn)

* 3. 拟合直线 pts_to_best_line函数
ActiveNum:=5
pts_to_best_line (Line, ResultRow, ResultColumn, ActiveNum, Row1, Column1, Row2, Column2)


dev_set_color ('blue')
dev_set_line_width (3)
dev_display (Line)

4. 代码下载

  • 不想自己写的,这里是代码和图片下载链接:

https://download.csdn.net/download/weixin_38566632/19515509

Halcon中可以使用angle_lx函数来计算旋转直线与水平轴之间的夹角。该函数接受两个点的坐标作为输入参数,并返回逆时针旋转向量到水平轴的角度,以弧度表示。结果的范围为-π <= Phi < π。\[1\] 另外,Halcon还提供了line_position函数来计算直线的重心、长度和角度。该函数接受起点和终点的坐标作为输入参数,并返回直线的重心坐标、长度和角度。角度的范围为-π/2 < Phi <= π/2。\[2\] 所以,如果你想在Halcon中旋转直线,可以使用angle_lx函数来计算旋转角度,然后使用line_position函数来获取旋转后直线的新位置和角度。 #### 引用[.reference_title] - *1* *2* [halcon 中几种求直线倾斜角度的算子分析](https://blog.csdn.net/fenglearning/article/details/122360514)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Halcon自定义直线卡尺rake](https://blog.csdn.net/weixin_38566632/article/details/117744728)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MechMaster

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值