python 图像分割_opencv python 基于分水岭算法的图像分割

理论

任何灰度图像都可以看作是地形表面,其中高强度表示山峰和丘陵,而低强度表示山谷.用不同颜色的水(标签)填充每个孤立的山谷(局部最小值),随着水的上升,明显具有不同的颜色的水将开始融合.为避免这种情况,需要在水合并的位置建立障碍,在所有的山峰都被水淹没之前,要继续填满水和建造栅栏的工作然后你创建的障碍会给你分割的结果,这就是分水岭背后的“哲学”.

可以访问我了解更多相关内容.

这种方法会导致由于噪声或图像中任何其他不正常的情况而导致的结果过于分散, 因此,OpenCV实现了一个基于标记的分水岭算法,可以在其中指定要合并的和不合并的谷点.这是一个交互式的图像分割,我们所做的就是给我们所知道的对象提供不同的标签,用一种颜色(或强度)标记我们确定为前景或对象的区域,用另一种颜色标记我们确定为背景或非对象的区域,最后标记我们不确定的区域为0,然后应用分水岭算法,我们的标记将会随着我们所给出的标签进行更新,对象的边界将值为-1.

应用

我们将看到一个关于如何使用距离变换和分水岭来分割相互触摸的物体的例子.

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

bVbdZHA?w=252&h=312

我们使用Otsu的二值化找到硬币的近似估计值.

import cv2

import numpy as np

from matplotlib import pyplot as plt

img = cv2.imread('img4.jpg')

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

cv2.imshow('show',thresh)

cv2.waitKey(0)

cv2.destroyAllWindows()

bVbdZI3?w=264&h=346

现在我们需要去除图像中的任何小的白噪声,因此我们要使用形态学开运算,为了去除物体上的小洞,我们要使用形态学闭运算,所以,现在我们可以确定,靠近物体中心的区域是前景,远离物体的区域是背景,只有硬币的边界区域是我们不确定的区域.

我们需要提取出我们确信它们是硬币的区域,腐蚀边界像素,不管剩下的是什么,我们都可以确定它是硬币.如果它们不相互接触还可以继续,如果它们相互接触,另一个好的选择是找到距离变换并应用一个合适的阈值.

为此,我们对结果进行了扩张,扩张将对象边界增加为背景,通过这种方法,我们可以确保背景中的任何区域都是真正的背景,因为边界区域被移除.

bVbdZPY?w=448&h=292

剩下的区域是我们不知道的区域,无论是硬币还是背景.分水岭算法应该找到它, 这些区域通常围绕着前景和背景相遇的硬币边界(甚至两个不同的硬币相遇),它可以从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,cv.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)

bVbdZQ4?w=445&h=281

现在我们可以确定哪些是硬币的区域,哪些是背景,哪些是背景.因此,我们创建标记(它是一个与原始图像相同大小的数组,但使用int32数据类型)并对其内部的区域进行标记.

cv2.connectedComponents()

将图像的背景标记为0,然后其他对象从1开始标记为整数.

我们知道,如果背景是0,那么分水岭将会被认为是未知的区域, 所以我们用不同的整数来标记它,用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

深蓝色区域显示未知区域,硬币的颜色是不同的,与未知区域相比,确定背景的剩余区域以较浅的蓝色显示.

bVbdZSg?w=384&h=478

标记已经准备好了,现在是最后一步的时候了,应用分水岭.

markers = cv2.watershed(img,markers)

img[markers == -1] = [255,0,0]

bVbdZSD?w=445&h=292

代码:

import numpy as np

import cv2

from matplotlib import pyplot as plt

img = cv2.imread('img4.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()

bVbdZV8?w=269&h=351

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于分水岭算法图像分割是一种常用的图像处理技术,可以将图像分割成多个区域,每个区域内的像素具有相似的特征。在 OpenCV 中,可以使用 cv2.watershed() 函数实现基于分水岭算法图像分割。 下面是一个简单的 Python 示例,演示如何使用基于分水岭算法图像分割: ```python import cv2 import numpy as np # 读取图像 img = cv2.imread('image.jpg') # 转换为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 阈值分割 ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU) # 形态学操作 kernel = np.ones((3,3),np.uint8) opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2) # 距离变换 dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.1*dist_transform.max(),255,0) # 背景区域 sure_bg = cv2.dilate(opening,kernel,iterations=3) # 不确定区域 sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg,sure_fg) # 标记连通区域 ret, markers = cv2.connectedComponents(sure_fg) markers = markers + 1 markers[unknown==255] = 0 # 应用分水岭算法 markers = cv2.watershed(img,markers) img[markers == -1] = [255,0,0] # 显示结果 cv2.imshow('image', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 在上面的示例中,首先读取一张图像,并将其转换为灰度图像。然后使用阈值分割算法图像二值化。接下来,进行形态学操作,以去除图像中的噪声。然后使用距离变换算法计算前景区域,并将其阈值化。接着,使用形态学操作计算背景区域。最后,使用 cv2.connectedComponents() 函数计算不确定区域,并使用标记连通区域的方法生成分水岭算法的输入标记图像。最后,应用 cv2.watershed() 函数进行图像分割,并在窗口中显示结果。 需要注意的是,分水岭算法的结果依赖于输入标记图像的质量,因此需要根据具体情况进行调整,比如阈值分割的参数、形态学操作的参数、距离变换的参数等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值