检测图像中的圆

对应示例程序:
measuring_circles.hdev

目标:将圆拟合成圆形轮廓段,提取圆的位置和半径

思路为:
      1.读取图像
      2.通过二值化,连通域分割等Blob分析手段,定位到ROI区域
      3.利用形态学的处理方法,提取出ROI的边缘,再膨胀,将ROI区域从原图中抠出来(形态学处理边缘:膨胀一个像素后的图 减去 原图 或者 原图 减去 腐蚀一个像素的图)
      4.利用canny算法对ROI区域进行精确检测,再判断其中的圆弧部分,压入到事先生成的HObj中。(因为原图中的圆并不是单纯的圆,还有其他的边缘干扰,因此先把边缘拆开,再判断其中的圆弧部分)
      5.合并是同一个圆的部分圆弧,然后对结果中的圆进行单独处理,拟合得到半径

图像:在这里插入图片描述
在这里插入图片描述

代码:

dev_update_off ()
* 
* step: acquire image
* 

*  前期准备以及一些参数设置
read_image (Image, 'circle_plate')
get_image_size (Image, Width, Height)
dev_close_window ()
dev_open_window (0, 0, Width / 2, Height / 2, 'light gray', WindowID)
dev_set_part (0, 0, Height - 1, Width - 1)
dev_set_line_width (3)
dev_set_color ('white')
dev_set_draw ('margin')
dev_display (Image)
set_display_font (WindowID, 14, 'mono', 'true', 'false')
disp_continue_message (WindowID, 'black', 'true')
stop ()
* 
* step: segment image into regions
* 
*分离图像   Blob分析
dev_set_colored (12)
dev_set_line_width (2)
dev_set_draw ('fill')
fast_threshold (Image, Region, 200, 255, 20)  //快速阈值分割  图像差异很大不是黑就是白
connection (Region, ConnectedRegions)  //连通域分割
select_shape (ConnectedRegions, SelectedRegions, 'area', 'and', 70, 50000)  //根据面积筛选出合适的区域

dev_display (Image)
dev_display (SelectedRegions)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* 
*这一步是先利用形态学求个初略轮廓,再膨胀一次,最后从原图中把ROI抠出来
* step: create ROI for contour processing
* 
boundary (SelectedRegions, RegionBorder, 'inner_filled')  //形态学处理边缘,获取最外边的边缘(膨胀再减去原图)
dilation_circle (RegionBorder, RegionDilation, 3.5)  //圆形膨胀
union1 (RegionDilation, RegionUnion)   //将全部分开的区域再合并起来
reduce_domain (Image, RegionUnion, ImageReduced)  //将ROI区域从原图中抠出来
dev_clear_window ()
dev_display (ImageReduced)
disp_continue_message (WindowID, 'black', 'true')
stop ()
* 
* step: create contours and fit circles to them
* 提取轮廓 并拟合
*这里就是精确的处理轮廓
edges_sub_pix (ImageReduced, Edges, 'canny', 1.5, 10, 40)  //canny算法的亚像素边缘检测
//因为图像中的圆并不是完全独立的,因此先把每段轮廓分割开
segment_contours_xld (Edges, ContoursSplit, 'lines_circles', 5, 2, 2)   //将提取出的轮廓进行分割,直线和圆
select_contours_xld (ContoursSplit, SelectedContours, 'contour_length', 25, 99999, -0.5, 0.5) //筛选符合要求的XLD轮廓
count_obj (SelectedContours, NumberContours) //计算筛选出的XLD轮廓的数量
gen_empty_obj (Circles)  //一个空的Obj  用来存放
//对分割的每段轮廓进行处理,将是圆弧的放入设定好的Obj中
for i := 1 to NumberContours by 1
    select_obj (SelectedContours, ObjectSelected, i)    //挨个处理提取出的XLD轮廓
    get_contour_global_attrib_xld (ObjectSelected, 'cont_approx', Attrib) //返回XLD轮廓的全局属性值  判断轮廓是否适合被划分为圆     //-1 适合直线 0适合圆弧  1 适合圆 
    if (Attrib == 1)
        concat_obj (Circles, ObjectSelected, Circles)    //如果是圆  就添加到之前新建的Obj中
    endif
endfor
*合并是同一个圆的部分圆弧
union_cocircular_contours_xld (Circles, UnionContours, rad(60), rad(10), rad(30), 100, 50, 10, 'true', 1)
dev_clear_window ()
dev_set_color ('black')
dev_display (UnionContours)
disp_continue_message (WindowID, 'black', 'true')
stop ()
count_obj (UnionContours, NumberCircles)    //统计圆的数目
CenterRow := []   //中心坐标
CenterColumn := []
dev_clear_window ()
dev_set_color ('black')
set_display_font (WindowID, 12, 'mono', 'true', 'false')
dev_display (SelectedContours)
for i := 1 to NumberCircles by 1
    select_obj (UnionContours, ObjectSelected, i)  //对每个圆XLD轮廓 进行拟合和计算
    //拟合圆  
    fit_circle_contour_xld (ObjectSelected, 'algebraic', -1, 0, 0, 3, 2, Row, Column, Radius, StartPhi, EndPhi, PointOrder)
    gen_circle_contour_xld (ContCircle, Row, Column, Radius, 0, rad(360), 'positive', 1.5)
    dev_set_color ('white')
    //进行一些输出的坐标设计
    dev_display (ContCircle)
    if (i == 1)
        Row2 := Row + Radius * sin(rad(-45))
        Column2 := Column + Radius * cos(rad(-45))
        set_tposition (WindowID, Row2 - 35, Column2 + 5)
    endif
    if (i > 1)
        exist := 0
        for j := 0 to i - 2 by 1
            distance_pp (Row, Column, CenterRow[j], CenterColumn[j], DistanceCenters)
            if (DistanceCenters < 20)
                exist := 1
            endif
        endfor
        if (exist == 1)
            Row2 := Row + Radius * sin(rad(-135))
            Column2 := Column + Radius * cos(rad(-135))
            set_tposition (WindowID, Row2 - 40, Column2 - 30)
        else
            Row2 := Row + Radius * sin(rad(-45))
            Column2 := Column + Radius * cos(rad(-45))
            set_tposition (WindowID, Row2 - 35, Column2 + 5)
        endif
    endif
    disp_arrow (WindowID, Row, Column, Row2, Column2, 2)
    write_string (WindowID, i)
    if (i < 8)
        disp_message (WindowID, 'R' + i + ' = ' + Radius$'.4', 'window', i * 20, 130, 'black', 'false')
    else
        disp_message (WindowID, 'R' + i + ' = ' + Radius$'.4', 'window', (i - 7) * 20, 400, 'black', 'false')
    endif
    CenterRow := [CenterRow,Row]
    CenterColumn := [CenterColumn,Column]
endfor
* 
dev_update_window ('on')

用到的几个算子:
      boundary --形态学处理边缘,获取最外边的轮廓。其实就是膨胀一个像素 再和原来的图像取差 或者腐蚀一个像素再和原来的图像取差。
      segment_contours_xld-- 将亚像素轮廓分割为直线段、圆、或圆弧(三种方式:直线,直线和圆,直线和弧,根据实际图像进行选择)
      get_contour_global_attrib_xld -返回XLD轮廓的全局属性值 判断轮廓是否适合被划分为圆 返回值:-1 适合直线 0适合圆弧 1 适合圆
      union_cocircular_contours_xld–合并是同一个圆的部分圆弧
      fit_circle_contour_xld–根据轮廓拟合圆
      distance_pp–计算两点间的距离

参考资料:
[1].https://blog.csdn.net/ABC13222880223/article/details/98481651
[2].https://blog.csdn.net/touchych/article/details/44464045

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值