图像分割与提取——分水岭算法

一、分水岭算法原理

分水岭算法基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。

二、图像分割步骤

1、通过形态学开运算对原始图像O去噪
2、通过腐蚀操作获取“确定背景B”
3、利用距离变换函数distanceTransform对原始图像O进行运算,并对其进行阈值处理
4、计算未知区域UN(UN=O-B-F)
5、利用函数connectedComponents对原始图像O进行标注
6、利用函数connectedComponents对原始图像O进行修正
7、使用分水岭函数完成对图像的分割

三、代码实例

# 分水岭算法流程:输入图像、灰度、二值、距离变换、寻找种子、生成Marker、分水岭变换、输出图像
def watershed_demo():
    print(src.shape)
    
    # 一、去除噪声remove noise if any
    # 1、边缘检测
    blurred = cv.pyrMeanShiftFiltering(src, 10, 100)
    # 2、灰度图像gray image
    gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
    # 3、二值图像binary image
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow('binary_image', binary)

    # 二、morphology operation:对图像进行开操作,能够去除图像内的噪声
    kernel = cv.getStructuringElement(cv.MORPH_RECT, (3, 3))
    # 1、膨胀操作可获取确定背景B
    mb = cv.morphologyEx(binary, cv.MORPH_OPEN, kernel, iterations=2)
    # 2、获取图像边界(图像O-确定背景B)=原始图像-dilate图像
    sure_bg = cv.dilate(mb, kernel, iterations=3)
    cv.imshow('mor_opt', sure_bg)

    # 三、距离变换函数distanceTransform:可用于计算对象的中心、细化轮廓和获取图像前景F等。
    """
    distanceTransform(src, distanceType, maskSize, dst=None, dstType=None)
        src:8位单通道的二值图像
        distanceType:距离类型参数
        maskSize:掩膜的尺寸,当distanceType=DIST_L1或DIST_C时,maskSize强制为3
        dst:计算得到的目标图像,可以是8位或32位浮点数
        dstType:目标图像的类型,默认CV_32F
    """
    # 1、计算二值图像内任意点到最近背景点的距离
    dist = cv.distanceTransform(mb, cv.DIST_L2, 3)
    # 2、归一化函数normalize:把需要处理的数据通过某种算法处理后,限制在需要的一定范围内
    dis_output = cv.normalize(dist, 0, 1.0, cv.NORM_MINMAX)
    cv.imshow('distance_t', dis_output * 50)

    # 四、确定未知区域
    # 1、生成Marker
    ret, surface = cv.threshold(dist, dist.max() * 0.6, 255, cv.THRESH_BINARY)
    cv.imshow('surface_bin', surface)
    # 2、获取图像前景F
    surface_fg = np.uint8(surface)
    # 3、确定未知区域UN=图像O-确定背景B-确定前景F
    unknown = cv.subtract(sure_bg, surface_fg)
    
    # 五、connectedComponents:对前景图像进行标注
    """
    connectedComponents(image, labels=None, connectivity=None, ltype=None)
        image:8位单通道的待标注图像
        labels:输出的标记图像,背景index=0
        connectivity:连通域,默认是8连通
        ltype:输出的labels类型,默认是CV_32S
        ret:返回的标注的数量
        markers:标注的结果图像
    """
    ret, markers = cv.connectedComponents(surface_fg)
    print(ret)

    # 六、watershed transform:对预处理图像进行分割
    # 1、将标注的结果都加上1,数值1表示背景区域,从数值2开始的值,代表不同的前景区域
    markers = markers + 1
    #2、 将已经计算出来的未知区域标注为0
    markers[unknown == 255] = 0
    """
    watershed(image, markers)
        image:输入图像,必须是8位三通道的图像
        markers:32位单通道的标注结果。在markers中,一个像素要么被设置为初期的“种子值”,要么被设置为“-1”表示边界
    """
    # 3、图像分割
    markers = cv.watershed(src, markers=markers)
    # 4、给边界涂色
    src[markers == -1] = [0, 0, 255]
    cv.imshow('watershed_demo', src)

你可能感兴趣的:(opencv,python,图像处理)