拟合直线 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)

【参数】

【函数实现】

*提示
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)

【参数】

【函数实现】

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)

【参数】


【函数实现】

*初始化
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