二维测量--迭代的跟踪PCB上的导线

对应示例程序:
      track_wries_chip.hdev

目标:对图像中的PCB焊线进行定位 主要是利用迭代的方式实现的

思路为:
      1.窗口初始化
      2.读入图像,以及提前准备好的已知参数。包括:
         ⑴每条焊线的起点和终点坐标
         ⑵导线的偏离角度(导线偏离上述各点的角度)
         ⑶焊线的近似宽度(像素)
      3.设置一些容忍度参数,包括导线的最小长度,搜索的角度,半径等
      4.一条一条的对焊线进行处理:以每条焊线的起点为圆心 做一个搜索圆弧(自己参数决定),把圆弧对应的区域从原图中抠出来,然后利用lines_gauss算子寻找圆弧中的曲线 ,然后再以得到的曲线终点为起始点 再画圆弧 找曲线 进行迭代 按照一个一个小圆弧的形式 进行曲线的查找和合并
      5. 将上一步得到的线段 拟合成一条曲线。因为上一步可能得到几条断开的曲线,现在就是对其进行细化 :先合并最近的 然后选择最长的一条作为备选。 再根据之前的先验知识,对曲线进行裁剪到要求的范围内 因为在迭代过程中 会因为干扰 拟合过度 。其实就是把曲线裁剪到我们设置的起始 终止坐标范围左右,不能因为拟合 导致曲线一直延伸,延伸出图像的范围。
      6. 通过最后得到的曲线的端点 与 已知的终点坐标做两点距离计算,如果距离小于某一个值,就认为我们找到了一条合适的焊线曲线。但是如果距离过大,说明该算法失败了,需要再从终点坐标开始,往回找。以准备好的焊线终点为搜索起点,以之前得到的曲线(步骤5得到的曲线)的最后一段曲线的中点为终点进行画圆弧迭代查找焊线。
      7.如果步骤6中,从终点往中点查找曲线的时候,不止找到了一条曲线,那就再按步骤8进行处理。
      8.对从起点拟合得到的曲线 与 从终点开始拟合的曲线 进行合并,先计算二者的交点,然后分别进行裁剪,只保留联合的部分,其余部分裁剪掉。
      9.对最终得到的焊线进行一次合并和平滑,最后把全部焊线放到一个Obj进行显示即可。
图像:
*                                                                                                       原图:
在这里插入图片描述

*                                                                             利用圆弧的形式迭代法进行曲线拟合(从起点往终点方向查找)
在这里插入图片描述

*                                                                                 从终点开始,往回找曲线

在这里插入图片描述
*                                                                                                      **从起点到终点找到的曲线

在这里插入图片描述
*                                                                                                      **从终点到中点找到的曲线
在这里插入图片描述
*                                                                                  *两条曲线的交点

在这里插入图片描述
*                                                                                  最后合并得到的曲线

在这里插入图片描述
*                                                                                                结果曲线

在这里插入图片描述

代码:

*这个程序展示了如何迭代地跟踪导线连接。

*它假定以下值来自

*初始化阶段:

*1。与键合位点相对应的起点和终点坐标

*2。导线偏离上述各点的角度

*3。近似线宽度(像素)
//初始化
dev_update_off ()
dev_get_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
dev_close_window ()
read_image (Image, 'die/die_01')
get_image_size (Image, Width, Height)
dev_open_window (0, 0, Width, Height, 'black', WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_colored (12)
dev_set_line_width (2)
* 
* SEARCH PARAMETERS ********************************
* Approximated half-widths of wires in image
*搜索参数********************************
*图像中导线的近似半宽度

WireWidths := [1.8,0,0,8,6,1.7,7.5]

* Minimum length of contours which may correspond to a wire
*与金属丝相对应的最小轮廓长度
MinSegmentLength := 5
* Angular search domain
*角搜索域
AngleTolerance := rad(20)
* Radius of the circular section defining the search region
*定义搜索区域的圆形截面的半径
MinSearchRadius := 10
MinWireDeviation := 5
* Radius of the circle with the center at the end point
* that the tracking algorithm must reach to
* consider the tracking as successful
*圆心位于跟踪算法必须达到的终点处的圆半径,才能认为跟踪成功
AcceptanceRadius := 5
MinWireLength := 80
* ***************************************************
* 
* 
for Img := 1 to 7 by 1
    
    //从文件中读入需要设置的参数
    //存放地址:C:\Users\Public\Documents\MVTec\HALCON-12.0\examples\hdevelop\Applications\Measuring-2D
    dev_set_preferences ('suppress_handled_exceptions_dlg', 'true') //在程序中设置HDevelop首选项
    try
        read_tuple ('die_' + Img$'02' + '_params.tup', Parameters) //从文件中读取Tuple
    catch (Exception)
        continue
    endtry
    dev_set_preferences ('suppress_handled_exceptions_dlg', PreferenceValue)
    //根据先验知识 将要提取的导线的数量 开始/结束 坐标 方向 存放在一个文件中 现在再读出来
    //存放的数据顺序按照:  数量 开始行 开始列 开始方向 结束行 结束列 结束方向 进行
    //行列 是导线的两个端点附近的坐标
    //方向 是导线的大体方向
        
    NPads := Parameters[0]   //数量
    
    StartPadRows := Parameters[1:NPads]  //开始行
    StartPadCols := Parameters[NPads + 1:2 * NPads]  //开始列
    
    StartInitOrientation := Parameters[2 * NPads + 1:3 * NPads] //开始方向
    
    EndPadRows := Parameters[3 * NPads + 1:4 * NPads]  //结束行
    EndPadCols := Parameters[4 * NPads + 1:5 * NPads]  //结束列
    EndInitOrientation := Parameters[5 * NPads + 1:6 * NPads] //结束方向
       
    //
    
    gen_empty_obj (Wires)
    read_image (Image, 'die/die_' + Img$'02')
    dev_display (Image)
    for Pad := 0 to |StartPadRows| - 1 by 1   //一条一条线的处理
        * Maximum distance between two consecutive contours
        * corresponding to the same wire
        //同一导线对应的两个连续轮廓之间的最大距离
        MaxDistSegment := 17 * WireWidths[Img - 1]
        //本地函数 检测图中的线  
        //以开始点为圆心 做一个起始方向和终止方向 指定大小的圆弧 
        //寻找圆弧中的曲线 然后再以得到的曲线终点为起始点  再画圆弧 找曲线  进行迭代 按照一个一个小圆弧的形式 进行曲线的查找和合并
        track_wire (Image, FwdWireSegments, StartPadRows[Pad], StartPadCols[Pad], StartInitOrientation[Pad], EndPadRows[Pad], EndPadCols[Pad], WireWidths[Img - 1], AngleTolerance, MinSegmentLength, MaxDistSegment)
        * Fuse all segments of the wire into a long contour covering the
        * whole trajectory  将导线的所有部分熔合成覆盖整个轨迹的长轮廓
        //将上一步得到的线段 拟合成一条曲线
        //上一步可能得到几条曲线 现在 就是对其进行细化  先合并最近的  然后选择最长的一条作为备选 再根据之前的先验知识
        //对曲线进行裁剪到要求的范围内  因为在迭代过程中 会因为干扰 拟合过度  其实就是把曲线裁剪到我们设置的起始  终止坐标范围左右
        //不能因为拟合 导致曲线跑出去
        fuse_wire_segments (FwdWireSegments, Wire, StartPadRows[Pad], StartPadCols[Pad], EndPadRows[Pad], EndPadCols[Pad], MinWireLength, MaxDistSegment, MinWireDeviation)
        * 
        * Check whether the algorithm could successfully track the whole wire.
        * If not, try to track the wire starting at the end point back to the
        * start point, and merge the results
        *检查该算法是否能够成功跟踪整个导线。
        *如果没有,请尝试跟踪从终点开始到起点的导线,并合并结果
        //计算点到Contour的距离
        //计算预设值中的终止点坐标与提取出的曲线的距离
        distance_pc (Wire, EndPadRows[Pad], EndPadCols[Pad], DistanceMin, DistanceMax)  
        
        if (DistanceMin > AcceptanceRadius)  //最小距离 大于可接受的阈值
            * The new end points correspond to the end points of the contour
            * where the algorithm left off in the previous attempt
            *新的端点对应于算法在上一次尝试中停止的轮廓的端点
            count_obj (FwdWireSegments, NXLDs)
            select_obj (FwdWireSegments, ObjectSelected, NXLDs)
            get_contour_xld (ObjectSelected, Row, Column)
            //本地函数  以预先知道的终点 为 起点  反方向往回找曲线
            track_wire (Image, BckWireSegments, EndPadRows[Pad], EndPadCols[Pad], EndInitOrientation[Pad], sum([Row[0],Row[|Row| - 1]]) / 2, sum([Column[0],Column[|Column| - 1]]) / 2, WireWidths[Img - 1], AngleTolerance, MinSegmentLength, MaxDistSegment)
            count_obj (BckWireSegments, WiresFound)
            if (WiresFound > 0) //如果找到了多条曲线 其实就是没连住
                * 
                * Find the point at which both contours cross each other 找出两个轮廓相交的点
                //计算从起始点拟合得到的曲线   与  从终点拟合得到的曲线  二者的交点  用来最终合并
                //下面这个函数是把两条曲线的最后一段进行曲线拟合  然后计算曲线的交点
                contour_intersection_point (FwdWireSegments, BckWireSegments, EndSegmentForwards, EndSegmentBackwards, IntersecRow, IntersecColumn)
                * Crop contours so that they do not go beyond the crossing point
                //本地函数:裁剪contour,使其不超出交叉点  其实就是根据上一步的交点 把每一个曲线进行分割 
                //将多余的部分都踢掉 只保留可以连在一起的部分
                crop_to_cross_point (FwdWireSegments, EndSegmentForwards, CroppedSegmentsFwd, IntersecRow, IntersecColumn)
                crop_to_cross_point (BckWireSegments, EndSegmentBackwards, CroppedSegmentsBck, IntersecRow, IntersecColumn)
                concat_obj (CroppedSegmentsFwd, CroppedSegmentsBck, WireSegments) //合并
            else
                count_obj (FwdWireSegments, NSegments)
                Sequence := [1:NSegments]
                select_obj (FwdWireSegments, WireSegments, Sequence)
            endif
            * Merge the resulting contours  合并生成的contour
            length_xld (WireSegments, Length)  //每段XLD的长度
            //合并XLD
            union_adjacent_contours_xld (WireSegments, FusedSegments, max(Length), max(Length) / max([min(Length),1]), 'attr_keep')
            smooth_contours_xld (FusedSegments, Wire, 11)  //平滑
            concat_obj (Wires, Wire, Wires) //把裁剪处理过的obj放到一个obj中 用于最后的合并
        else
            smooth_contours_xld (Wire, SmoothedContours1, 11)  //一幅图中的曲线全处理后 再平滑一次
            concat_obj (Wires, SmoothedContours1, Wires)  //把曲线全合并到一个obj中
        endif
    endfor
    dev_display (Image)
    dev_display (Wires)
    if (Img < 7)
        disp_continue_message (WindowHandle, 'black', 'true')
        stop ()
    endif
endfor

用到的几个算子:
    lines_gauss–检测线条及其宽度
    union_collinear_wire_segments–合并周围相近的曲线
    fit_line_contour_xld–用线段近似XLD轮廓
    distance_pc–计算点到Contour的距离
    crop_contours_xld–利用矩形裁剪一个Contours
    smooth_contours_xld–平滑XLD

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页