• 【OpenCV】 - 图像分割之分水岭算法,watershed()函数的输出,对marker和image的改变


    一、背景

    最近在学分水岭算法的opencv函数watershed()时,对函数执行完后image和marker的变化一无所知、懵懵懂懂。

    于是便结合网上资料和自己现身说法,给大家分享一下【watershed函数的执行效果】。

    OpenCV: Image Segmentation with Watershed Algorithm 

    OpenCV: Image Segmentation

    首先说明一点:

    传入watershed函数的marker参数可以有三种成分:背景、不确定、前景(也即object)。

    比如背景像素填充1,而object1填充2,不确定像素填充0。

    下文的“种子数值”代表Object成分的编号。

    因此,object1的种子数值是2。

    二、直接给结论

    watershed函数一旦执行,就会改变marker,但是image不变。

    改变A:从基点开始向外填充种子数值,直到边界。

    例如下面的第2个硬币对应的种子数值是2,原marker中只有硬币最中间才是填充了2

    函数执行后,整个硬币所处区域全被填充2。

     

    改变B:向外填充时,若即将与另一个山谷的积水相涉就停止扩展,最外围便是边界线,marker中的边界线区域填充-1。

    还是以第二个硬币为例,第二个硬币的边界像素点填充-1。

    也就是说,最后得到的marker想比原marker是更加完善的;原marker的object像素点只需要至少填充一个种子数值,而新marker是将object的所有像素全部填充种子数值,更加精确和点对点。

     

    三、测试(现身说法)

    测试用到的图片

    测试用到的代码

    1. import cv2 as cv
    2. import numpy as np
    3. from matplotlib import pyplot as plt
    4. def watershed_demo():
    5. # remove noise if any
    6. print(src.shape)
    7. blurred = cv.pyrMeanShiftFiltering(src, 10, 100)
    8. # gray\binary image
    9. gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    10. ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    11. cv.imshow("binary-image", binary)
    12. # morphology operation
    13. kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
    14. mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)
    15. sure_bg = cv.dilate(mb, kernel, iterations=3)
    16. cv.imshow("mor-opt", sure_bg)
    17. # distance transform
    18. dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    19. dist_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    20. cv.imshow("distance-t", dist_output*50)
    21. ret, surface = cv.threshold(dist, dist.max()*0.6, 255, cv.THRESH_BINARY)
    22. surface_fg = np.uint8(surface)
    23. cv.imshow("surface-bin", surface_fg)
    24. unknown = cv.subtract(sure_bg, surface_fg)
    25. ret, markers = cv.connectedComponents(surface_fg)
    26. # watershed transform
    27. markers = markers + 1
    28. markers[unknown == 255] = 0
    29. print(type(markers))
    30. print(np.sum(markers==2))
    31. markers = cv.watershed(src, markers=markers)
    32. print(np.unique(markers))
    33. print(np.sum(markers==2))
    34. src[markers==-1] = [0, 0, 255]
    35. cv.imshow("result", src)
    36. markers = markers + 1
    37. plt.imshow(markers)
    38. plt.show()
    39. src = cv.imread("D:\BaiduNetdiskDownload\pycv-learning\pythonProject\images\coins.jpg")
    40. cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
    41. cv.imshow("input image", src)
    42. watershed_demo()
    43. cv.waitKey(0)
    44. cv.destroyAllWindows()

     

    cv.imshow("surface-bin", surface_fg)的输出如下。

    这十个白圆块的区域,对应marker填充种子数值的范围。

    cv.imshow("result", src)的输出如下。

    硬币的边界上绘制了一个红圈,正是利用了上文第二部分的改变B。

     

    plt.imshow(markers)的输出如下。

    我们可以看到新得到的marker真正做到对各个硬币进行像素级别的标注,不同硬币object对应不同填充色。

     

  • 相关阅读:
    计算机毕业设计Java高铁在线购票系统(源码+系统+mysql数据库+lw文档)
    漫画 | 一位坑人的编程大师
    Vue的插槽&Vue的过渡动画
    “讳疾忌医”的开源走不远
    使用管道进行读取执行命令的返回值
    【Linux】线程池 | 自旋锁 | 读写锁
    【机器学习科学库】全md文档笔记:Matplotlib详细使用方法(已分享,附代码)
    深入了解HTTP与HTTPS关键差异与底层原理
    配置nacos组件
    SpringBoot试题及答案(第一章)
  • 原文地址:https://blog.csdn.net/PSpiritV/article/details/125994413