opencv-用分水岭算法进行图像分割

参考:

1、http://docs.opencv.org/3.3.0/  官方文档api

2、http://docs.opencv.org/3.3.0/d6/d00/tutorial_py_root.html 官方英文教程

3、https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html

4、https://github.com/makelove/OpenCV-Python-Tutorial# 进阶教程

5、https://docs.opencv.org/3.3.0/index.html  官方英文教程

6、https://github.com/abidrahmank/OpenCV2-Python-Tutorials

7、https://www.learnopencv.com/

8、http://answers.opencv.org/questions/ OpenCV论坛

9、https://github.com/opencv/opencv   官方github

10、https://github.com/abidrahmank/OpenCV2-Python-Tutorials


注:安装的版本 opencv_python-3.3.0-cp36-cp36m-win_amd64.whl



参考:https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_tutorials.html



用分水岭算法进行图像分割

目标

In this chapter,
  • We will learn to use marker-based image segmentation using watershed algorithm
  • We will see: cv2.watershed()

代码

下面我们将看到一个关于如何使用距离变换和分水岭来分割相互接触的对象的例子。

考虑下面的硬币图像,硬币相互接触。 即使你的阈值,它会互相接触。

Coins

我们从硬币的近似估计开始。 为此,我们可以使用Otsu’s二值化。

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

img = cv2.imread('coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

cv2.imshow('ret',thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()


Thresholding

现在我们需要去除图像中的任何小的白色噪音。 为此,我们可以使用形态开放。 要删除物体中的任何小孔,我们可以使用形态关闭。 所以,现在我们知道,对象中心附近的区域是前景,远离对象的区域是背景。 只有我们不确定的地区是硬币的边界区域。

所以我们需要提取我们确定他们是硬币的区域。 侵蚀去除边界像素。 所以无论如何,我们可以肯定是硬币。 如果对象没有互相接触,那将会奏效。 但是由于他们互相接触,另一个好的选择是找到距离变换并应用适当的阈值。 接下来我们需要找到我们确定他们不是硬币的区域。 为此,我们扩大了结果。 扩张将对象边界增加到背景。 这样,我们可以确保结果背景中的任何区域都是真正的背景,因为边界区被删除。 见下图。

Foreground and Background

剩下的区域是我们没有任何想法的区域,无论是硬币还是背景。 流域算法应该找到它。 这些区域通常位于前景和背景相遇的硬币的边界(甚至两个不同的硬币相遇)。 我们称之为边界。 可以从sure_bg区域中减去sure_fg区域获得。

# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,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.7*dist_transform.max(),255,0)

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

看到结果。 在阈值图像中,我们得到一些硬币区域,我们确定硬币,现在它们已经分离。 (在某些情况下,您可能只对前景分割感兴趣,而不是分离相互接触的对象,在这种情况下,您不需要使用距离变换,只是侵蚀就足够了。侵蚀只是提取前景区域的另一种方法, 所有。)

Distance Transform

现在我们知道哪些是硬币区域,哪些是背景和全部。 所以我们创建标记(它是一个与原始图像大小相同的数组,但是使用int32数据类型),并标记它内部的区域。 我们知道的区域(无论是前景还是背景)都被标记为任何正整数,但是不同的整数,我们不知道的区域只能保持为零。 为此,我们使用cv2.connectedComponents()。 它用0标记图像的背景,然后其他对象用从1开始的整数标记。

但是我们知道如果背景被标记为0,则分水岭将其视为未知区域。 所以我们想用不同的整数来标记它。 相反,我们将用未知的区域标记未知区域。


# 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

现在我们的标记准备好了 现在是最后一步,应用流域的时候了。 然后标记图像将被修改。 边界区域将被标记为-1。

markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]

Result

Additional Resources

  1. CMM page on Watershed Tranformation
import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)


# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,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.7*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

markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]


cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值