使用OpenCV的分水岭算法

《使用OpenCV的分水岭算法》

  之前利用watershed想对相对前背景较为明显的图像进行图像语义分割的预打标,因为虽然前景明显,但是边缘打标也是很困难的,可以用该方法对大部分的边缘进行获取,然后用pixel Annotation进行标注即可。

Key Words:分水岭算法、OpenCV、 图像分割


Beijing, 2020

作者:RaySue

Code:

Agile Pioneer  

分水岭算法原理

算法步骤:

  1. 构建图像梯度图像(构造边缘)。
  2. 通过一定规则生成 n 个最初的注水区域(先验知识或局部梯度最小值,种子)。
  3. 往注水区域内加水,当两注水区域即将合并时,记录下此时的边界。
  4. 当图像边缘彻底被分割成 n 个独立区域是算法结束。

OpenCV函数

void watershed( InputArray image, InputOutputArray markers ); 
cv2.watershed(image, markers)

使用流程

使用分水岭算法的通用步
  • 自动生成种子

    • 输入图像 -> 灰度 -> 二值化(二值化之后注意一下前景是 255 还是 0) -> 距离变换 -> 寻找种子 -> 生成Marker -> 分水岭变换 -> 输出图像
  • 手动指定已经确定的前景(2)和背景(1)作为种子

分割鸡蛋为例
  • 代码

import cv2
import numpy as np
import matplotlib.pyplot as plt


def watershed(image_path):

    image_name = image_path.split("/")[-1]
    image = cv2.imread(image_path)
    # image = multiScaleSharpen(image, 5)
    # 前提:降噪
    # blurred = cv2.pyrMeanShiftFiltering(image, 25, 100)
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 第一步:灰度处理

    # 第二步:二值化处理 + 反色处理 255 -> 0 | 0 -> 255
    # ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)
    ret, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)

    # 对二值化的结果执行开运算

    # noise removal
    kernel = np.ones((3, 3), np.uint8)
    opening = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel, iterations=2)

    # sure background area
    sure_bg = cv2.dilate(opening, kernel, iterations=3)

    # Finding sure foreground area
    dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
    # 通过距离变换的结果取二值化,得到前景
    ret, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(),
                                 255, 0)

    # Finding unknown region
    sure_fg = np.uint8(sure_fg)
    unknown = cv2.subtract(sure_bg, sure_fg)

    # Marker labelling
    ret, markers = cv2.connectedComponents(sure_fg)

    # Add one to all labels so that sure background is not 0, but 1
    markers = markers + 1

    # Now, mark the region of unknown with zero
    markers[unknown == 255] = 0
    sure_bg[unknown == 255] = 0
    sure_bg[sure_bg == 255] = 2
    sure_bg = sure_bg.astype(np.int32)

    # plt.figure(1)
    # plt.title("sure_bg")
    # plt.imshow(sure_bg)

    # 分水岭只是对0的位置进行分割 1-背景 0-待分割 2-前景
    result = cv2.watershed(image, markers=markers)

    # 分水岭结果标记轮廓为红色
    image[result == -1] = [255, 0, 0]
    # cv2.imwrite("./watershed_res.jpg", result)

    plt.figure(0)

    plt.subplot(231)
    plt.title("binary")
    plt.imshow(binary)

    plt.subplot(232)
    plt.title("seed new")
    plt.imshow(sure_bg)

    plt.subplot(233)
    plt.title("distance")
    plt.imshow(dist_transform * 50)

    plt.subplot(234)
    plt.title("seed ori")
    plt.imshow(markers)

    plt.subplot(235)
    plt.title("result markers")
    plt.imshow(result)

    plt.subplot(236)
    plt.title("watershed")
    plt.imshow(image)

    # plt.savefig(os.path.join(output_dir, "watershed_" + image_name))
    plt.show()


watershed("/Users/i/Desktop/Screenshot 2020-10-23_17-48-13-153.jpg")


参考

https://blog.csdn.net/HXG2006/article/details/80019736

https://blog.csdn.net/weixin_40647819/article/details/90231477

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值