捕鱼平台 OpenCV中的分水岭算法

日期:2021-01-19 02:17:24 浏览量: 154

分水岭是一种基于地理形态分析的图像分割算法,它通过模仿地理结构(例如山脉,沟壑和盆地)来对不同的对象进行分类。

分水岭算法中使用了重要的概念-大地距离。

大地距离(大地距离)

测地距离是地球表面上两个点之间的最短路径(可执行路径)的距离。在图论中,测地距离是图中两个节点之间的最短路径的距离,通常与几何空间中的距离相同。欧氏距离是两点之间的最短距离之差。

在下图中,两个黑点的欧式距离是用虚线表示的线段的长度

,而测地距离是实际路径的最短距离,其距离应为沿实线线段的距离之和的最小值鸭脖娱乐 ,即

分水岭算法

图1

三维表面空间中两点之间的大地测量距离是沿着三维表面的两点之间的最短路径。

分水岭算法

图像的灰度空间与地球表面的整个地理结构非常相似,每个像素的灰度值代表高度。连接具有较大灰度值的像素的线可以被认为是脊,即分水岭。水是用于二值化的灰色阈值水平。二值化阈值可以理解为水平面。低于水平面的区域将被淹没。一开始分水岭算法,每个孤立的山谷(局部最小值)都充满了水。

当水位上升到一定高度时,水将溢出当前的山谷。您可以在分水岭上建坝,以避免在两个山谷中积水,以便将图像分为2个像素集,一个是水。淹没的山谷像素集之一是分水岭线像素集。最后,由这些水坝形成的线条将整个图像分割以实现图像分割。

分水岭算法

图2

在该算法中,空间上相邻且具有相似灰度值的像素被划分为一个区域。

分水岭算法的整个过程:

根据灰度值对渐变图像中的所有像素进行分类og真人厅AG体育 ,并设置测地线距离阈值。

找到具有最小灰度值的像素(默认情况下标记为最低灰度值),让阈值从最小值增加,这些点就是起点。

当水平面增大时百家乐APP ,它将遇到周围的邻域像素。测量从这些像素到起点(灰度值的最低点)的测地距离。如果小于设置的阈值,则这些像素将被淹没,否则将Dams放置在这些像素上,以便对这些邻域像素进行分类。

分水岭算法

图3

4.随着水位越来越高,将建立越来越多的水坝凤凰彩票app ,直到达到最大灰度值。所有区域在分水岭线上相遇。这些坝会影响分区的整个图像像素。

可以在下面的动画中查看整个过程:

分水岭算法

图4

使用上述算法对图像执行分水岭操作时,由于噪声点或其他因素的干扰,可能会获得密集的小区域,也就是说,图像被划分得过于精细(过度分割,过度分割,分段),因为图像上有很多局部最小点,每个点本身都会形成一个很小的区域。

解决方案:

对图像执行高斯平滑操作以擦除许多小的最小值分水岭算法,并且这些小的分区将被合并。不要从最小值开始增加,可以使用相对较高的灰度值像素作为起点(用户需要手动标记),然后从标记中淹没,然后许多小区域将合并为一个区域,这称为图像标记的分水岭算法研究。

以下三张图片是原始图片,分水岭过度分割图片和通过基于标记的分水岭算法获得的图片:

分水岭算法

图5

其中标记的每个点都等于分水岭中的注水点。从这些点注水会使水位上升,但是如上图所示,图像中需要分割的区域太多,并且手动标记也很麻烦。使用距离转换方法进行标记,这是OpenCV中使用的方法。

OpenCV中的分水岭算法

在OpenCV中,我们需要将不同的标签粘贴到不同的区域。使用大于1的整数表示我们确定为前景或对象的区域,使用1表示我们确定为背景或非对象的区域,最后使用0表示无法确定的区域。然后应用分水岭算法,对标记图像进行更新,标记图像的边界像素值为-1。

以下内容将距离变换和分水岭划分应用于彼此接触的硬币。

分水岭算法

图6

首先使用Otsu的二值化对图像进行二值化。

import cv2
import numpy as np
img = cv2.imread('coins.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

分水岭算法

图7

首先使用打开操作去除图像中的小白噪声,然后通过腐蚀操作去除边界像素。获得的图像中的白色区域必须是真实前景,即硬币中心附近的区域(图像左下方);计算使背景的一部分成为对象的边界,并且获得的图像中的黑色区域必须是真实背景,即远离硬币的区域(下图为中间图像)。

不能将剩余区域(硬币边界附近)确定为前景或背景。可以通过从膨胀图中减去腐蚀图来获得。下图的白色部分是不确定区域(右下图)。

# noise removal
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
sure_bg = cv2.dilate(opening, kernel, iterations=2)  # sure background area
sure_fg = cv2.erode(opening, kernel, iterations=2)  # sure foreground area
unknown = cv2.subtract(sure_bg, sure_fg)  # unknown area

分水岭算法

图8

剩余区域不确定是硬币还是背景。这些区域通常位于前景和背景接触的区域(或两个不同硬币接触的区域),我们称之为边界。确定边界应通过分水岭算法找到。

由于硬币彼此接触,所以我们使用另一种方法来确定前景,这是阈值距离变换。

左下方的图像是获得的距离转换图像,其中每个像素的值是到最近的背景像素的距离(灰度值为0))。可以看出,硬币的中心像素值最大(中心距离背景像素最远)。经过二进制处理后,获得了分离的前景图像(下面的中间图像)。白色区域必须是硬币区域,并且它们彼此分开。下面的右图是上一个扩展图减去中间的图。此图显示了前景。

# Perform the distance transform algorithm
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# Normalize the distance image for range = {0.0, 1.0}
cv2.normalize(dist_transform, dist_transform, 0, 1.0, cv2.NORM_MINMAX)
# Finding sure foreground area
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)

分水岭算法

图9

现在我们可以确定哪些是硬币区域,哪些是背景区域。然后创建一个标记(标记,它是与原始图像大小相同的矩阵,int32数据类型)以表示每个区域。分水岭算法将标记为0的区域作为不确定区域,标记为1的区域作为背景区域,标记大于1的正整数表示我们想要的前景。

我们可以使用cv2.connectedComponents()实现此功能,该功能使用0标记图像的背景,并使用大于0的整数标记其他对象。因此,我们需要为其添加一个,并使用1标记图像的背景。

cv2.connectedComponents()将传入图像中的白色区域视为分量(前景)。

# 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

注意:获得的标记矩阵的元素类型为int32。要使用imshow()进行显示,您需要将其转换为uint8类型(markers = np.uint8(markers))。

我们显示获得的标记:

markers_copy = markers.copy()
markers_copy[markers==0] = 150  # 灰色表示背景
markers_copy[markers==1] = 0    # 黑色表示背景
markers_copy[markers>1] = 255   # 白色表示前景
markers_copy = np.uint8(markers_copy)

分水岭算法

图10

标记图像已完成,最后应用了分水岭算法。然后,将修改标记的图像,并将边框区域标记为-1。

# 使用分水岭算法执行基于标记的图像分割,将图像中的对象与背景分离
markers = cv2.watershed(img, markers)
img[markers==-1] = [0,0,255]  # 将边界标记为红色

通过分水岭算法获得的新标记图像和分割图像如下图所示:

分水岭算法

图11

任何两个相邻的连接分量不一定要用分水岭边界(-1个像素)分开;例如,传递给分水岭功能的初始标记图像中的对象会相互接触。

摘要

我们通过一个示例介绍了分水岭算法的整个过程,该过程主要分为以下几个步骤:

对图像进行灰度和二值化以通过扩展获得确定的二值图像背景区域,并通过距离转换获得确定的前景区域。其余部分是不确定区域。所确定的前景图像通过连接组件进行处理。获取标记图像,并根据标记图像对原始图像进行分水岭算法更新标记图像

参考:

OpenCV分水岭算法

图像分割和数学形态学

经典分水岭

OpenCV中基于标记的分水岭分割算法/距离转换

剪刀手/分水岭分割方法

分水岭变换

将分水岭应用于扑克牌的示例

如果您觉得有用,请喜欢(ง•̀_•́)ง。