• Halcon机器视觉实战--分水岭分割+距离变换实现粘连物体图像分割


    分水岭的原理

    把图像的灰度看作高度图,图像中每个像素点的灰度值看作该点的高度,高灰度值代表山脉,低灰度值代表盆地,每个局部最小值及其周围区域称为集水盆,而集水盆的边界则形成分水岭。
    在这里插入图片描述

    分水岭算法的步骤

    1.彩色图像转化成单通道灰度图
    2.求梯度图
    3.在梯度图的基础上进行分水岭算法,求取分区域的边缘线。

    局部最小值点:

    对应的是一个盆地的最小值,当我们在盆地里面滴一滴水的时候,由于重力作用,水最终会汇聚到该点。
    在这里插入图片描述

    盆地的其他位置点:

    该位置滴的水滴会汇聚到局部最小点。

    在盆地的最小值点,打一个洞,然后往盆地里面注水,并阻止两个盆地的水汇集,我们会在两个盆地的水汇集的时刻,在交接的边缘线上(即分水岭),建造大坝,来阻止两个盆地的水汇集成一个区域。图像被分为了两个像素集,一个是注水盆地像素集,一个是分水岭线像素集。

    在这里插入图片描述

    在真实图像中,由于噪声点的影响或者其他干扰因素的存在,使用分水岭算法常常出现过度分割的现象,这是因为很多很小的局部极值点的存在,这样的分割效果是毫无作用的。

    为了解决过度分割的问题,我们可以使用基于标记图像的分水岭算法,就是通过设定一个阈值指导分水岭算法,以便获得更好的图像分割效果。在这个区域的洪水淹没过程中,水平面都是从定义的高度开始的,这样可以避免一些很小的噪声极值区域的分割。

    算子:

    1.直接提取图像的盆地区域和分水岭区域:

    watersheds (Image, Basins, Watersheds)
    
    • 1

    输入是图像,输出的第一个参数是盆地区域,第二的参数是分水大坝区域。
    简单的案例,图片可以从这里下载

    *获取图像
    read_image (image, 'particle')
    *对单通道图像进行高斯平滑处理,去除噪声
    gauss_filter (image, ImageGauss, 11)
    *将图像颜色进行反转
    invert_image (ImageGauss, ImageInvert)
    *对高斯平滑后的图像进行分数岭处理,提取出盆地区域和分水岭大坝区域
    watersheds (ImageInvert, Basins, Watersheds)
    dev_display (ImageInvert)
    dev_display (Watersheds)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.阈值化分割分水岭盆地区域。

    watersheds_threshold (Image, Basins, 10)
    
    • 1

    注意,这里输出参数只有盆地区域,Basins即盆地区域,无分水岭区域,因此是从白色背景里面,提取黑色区域。若是黑色背景里提取白色目标,只需要图像image_invert即可。
    关键是第三个参数如何理解,以及这个参数对最终的算法分割结果的影响。
    查看Halcon的帮助文档可以看到,
    max ⁡ { W − B 1 , W − B 2 } <  Threshold.  \max \left\{W-B_{1}, W-B_{2}\right\}<\text { Threshold. } max{WB1,WB2}< Threshold. 
    B 1 B_{1} B1, B 2 B_{2} B2分别代表两个盆地的最小灰度值, W W W代表的是两个盆地的交界处的灰度值,即交界处分水岭的灰度值。取两者差值的最大值,如果最大值小于threshold,即两块盆地之间的灰度值差值很小,代表两个盆地可以合并在一起。因此这个threshold值越小,分割出来的盆地数目越多,分割的越精细。数值越大,分割的盆地区域越少

    距离变换

    像素之间的距离有欧式距离,城市街区距离,棋盘距离等
    欧式距离:就是高中课本定义的真实的两点之间的距离
    在这里插入图片描述
    城市街区距离:就是两个邻边长度之和
    D = ∣ x − s ∣ + ∣ y − t ∣ D = \left | x-s \right | +\left | y-t \right | D=xs+yt
    在这里插入图片描述
    棋盘距离:就是取长或者宽差值的最大值。
    D = m a x ( ∣ x − s ∣ , ∣ y − t ∣ ) D = max(\left | x-s \right | ,\left | y-t \right | ) D=max(xs,yt)
    在这里插入图片描述
    所以,对于任意两个像素点而言,一般棋盘距离<欧式距离<城市街区距离。
    算子:

    distance_transform (Regions, Image, 'octagonal', 'true', Width, Height)
    
    • 1

    输入是区域,这里的区域可以是多个不同的区域,输出是图像。 距离变换可以简化分水岭的复杂度。经格式变换后,region看起来变小了(腐蚀实现的是原图区域变小),同时图像背景全部为0,即背景变成黑色。
    那么距离变换底层原理是如何实现的?
    第一个参数,在图像处理中,区域本身代表的是图像的某一部分,其本身是不含灰度值的,很多时候,halcon的输入是图像和region一起的,这里只输入了region,没有输入图像,默认输入的是二值化图像的region,因此region部分的灰度值是1,代表目标区域,背景部分设定为0,代表的是背景区域。所以这里的输入是只含0和1的二值化图像。用矩阵表示就是:
    在这里插入图片描述
    第二个参数,输出是Image,这里的Image指的是另一副全新的,尺寸大小为Width*Height的含距离信息(不是灰度信息)的图像。此时这个图像的像素点的数值不是灰度值,而是区域中的点到背景之间的距离。用矩阵表示就是:
    在这里插入图片描述
    按住CTRL,鼠标显示图像信息是距离信息,而不是灰度值。
    在这里插入图片描述

    第三个参数,代表距离公式的选取:
    'city-block’代表的是街区距离
    'chessboard’代表的是棋盘距离
    'octagonal’代表的是欧式距离

    第四个参数,ture代表的是目标区域到背景的距离。false代表的是背景区域到目标区域边缘的距离,两个成像正好相反。
    在这里插入图片描述

    实例代码

    dev_close_window ()
    dev_open_window (0, 0, 800, 800, 'black', WindowHandle)
    read_image (Image, 'pellets.png')
    get_image_size (Image, Width, Height)
    **********第一步,先把目标区域提取出来
    *均值去噪,排除干扰
    mean_image (Image, ImageMean, 9, 9)
    *全局阈值
    threshold (ImageMean, Regions, 113, 202)
    connection (Regions, ConnectedRegions)
    **********第二步,做距离变换
    *距离变化的目的是将图像二值化
    distance_transform (ConnectedRegions, DistanceImage, 'octagonal', 'true', Width, Height)
    *因为分水岭用的二值化图像是从白色背景里提取黑色目标区域,因此需要做invert_image
    invert_image (DistanceImage, ImageInvert)
    **********第三步,分水岭阈值分割
    *距离变换后图像数据更改,在halcon中更换图像数据类型,可以使用convert_image_type
    *然而convert_image_type在改变图像类型的情况时,还会把像素值根据图像类型做像素值变换
    *变换,因此显示的图像会改变,所以也可以使用scale_image_max
    scale_image_max (ImageInvert, ImageScaleMax)
    watersheds_threshold (ImageScaleMax, Basins, 50)
    **********分水岭的盆地区域与原区域做交运算,相当于拆分原区域
    intersection (Basins, ConnectedRegions, RegionIntersection)
    *区域显示
    dev_display (Image)
    dev_display (RegionIntersection)
    stop()
    *边缘显示
    gen_contour_region_xld (RegionIntersection, Contours, 'border')
    dev_display (Image)
    dev_display (Contours)
    stop()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    图像效果

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

  • 相关阅读:
    bootstrap学习:栅格实例-不同用户端不同界面
    万数藏:国内首家影视IP艺术数藏平台今日上线
    Spring基础
    Kamiya丨Kamiya艾美捷人β2-微球蛋白ELISA说明书
    ASP.NET数据库连接(运行失败,不掌握)
    Leetcode -2
    再生龙clonezilla还原windows、linux操作系统(包含银河麒麟、ubuntu、centos等)
    泰女网红变身外汇投资大师诈骗逾20亿,请警惕身边的“投资大师”
    .NET中的数组在内存中如何布局?
    c++模板
  • 原文地址:https://blog.csdn.net/qq_43376782/article/details/127965165