分水岭算法(学习笔记)

分水岭算法watershed

  • 进行图像分割
  • 基本的步骤
    • 通过形态学开运算对原图像O去噪
    • 通过膨胀操作获取“确定背景B”
    • 利用距离变换函数对图像进行运算,并对其进行阈值处理,得到“确定前景F”
    • 计算未知区域UN(UN = O – B – F )
    • 利用函数connecedComponents对原图像O进行标注
    • 对函数connecedComponents的标注结果进行修正
    • 使用分水岭函数watershed完成对图像的分割

操作小记

代码
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

img = cv.imread('coins.jpg')
if img is None:
    print('Could not open or find the image ')
    exit(0)
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)
# cv.imshow("threshold", thresh)    #阈值处理后会有紧挨着(粘连)的情况
# 去噪处理
kernel = np.ones((3, 3), np.uint8)
opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)  # 开运算
# sure background area
sure_bg = cv.dilate(opening, kernel, iterations=3)  # 膨胀操作

# Finding sure foreground area
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)  # 距离背景点足够远的点认为是确定前景

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)  # 确定未知区域:减法运算
# Marker labelling
ret, markers = cv.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 = cv.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
plt.imshow(img)
plt.show()
效果

在这里插入图片描述

代码分析

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

  • 函数的作用是进行阈值处理
  • 返回参数:ret为阈值,thresh为处理结果
  • 输入参数中
    • gray为输入图像的灰度图像,上一行代码cv.cvtColor(img, cv.COLOR_BGR2GRAY)进行了色彩空间的转换
    • 0为设定的阈值
    • 255代表图像最大值
    • cv.THRESH_BINARY_INV + cv.THRESH_OTSU二值化的方式,THRESH_BINARY_INV表示采取反二进制阈值化,而`THRESH_OTSU``代表采用自适应图像的二值化Otsu
      • 说明:反二进制阈值化:小于阈值取255,大于阈值取0
  • 测试中,ret=162.0thresh的效果如下:
    在这里插入图片描述
  • 相关资料:滤波和卷积

opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations=2)

  • 函数的作用是去除噪声
  • 输入参数中
    • thresh是进行阈值处理的图像
    • cv.MORPH_OPEN表示进行开运算,开运算就是对图像先腐蚀再膨胀
    • kernel为形态学运算的内核,上一句kernel = np.ones((3, 3), np.uint8)设置了参考点位于中心3x3的核
    • iterations用于设置迭代次数,这里设置为2
  • opening为处理结果,效果如下:
    在这里插入图片描述
  • 相关资料:More Morphology Transformations

sure_bg = cv.dilate(opening, kernel, iterations=3)

  • 作用:用膨胀的方式获取背景
  • sure_bg为得到的结果,效果如下:
    在这里插入图片描述

# Finding sure foreground area
dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)
ret, sure_fg = cv.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)  # 距离背景点足够远的点认为是确定前景

通过函数cv.distanceTransform(...)进行距离变换,cv.DIST_L2代表采用欧几里得的距离计算公式,5代表掩膜尺寸,用来确定前景,然后通过阈值处理得到核心的区域,超过最大值的70%才留下来

dst = cv2.distanceTransform( src, distanceType, maskSize[, dst[, dstType]] )
  • src:8位单通道的二值图像
  • distanceType:距离类型参数
  • maskSize:掩膜尺寸
  • dstType:目标图像的类型,默认值为cv_32F
  • dst :计算得到的目标图像

distanceType取值
在这里插入图片描述
maskSize说明
在这里插入图片描述

得到效果如下:
在这里插入图片描述

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv.subtract(sure_bg, sure_fg)  # 确定未知区域:减法运算

通过做减法来获取到未知区域,确定的背景-确定的前景

确定未知区域

对确定的前景F进行膨胀放大——得到——确定的背景B
未知区域UN = 原图像O—确定的背景B — 确定前景F
减法运算
在这里插入图片描述

unknown的效果如下:
在这里插入图片描述


# # Marker labelling
ret, markers = cv.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

用来设置水坝来分割背景和前景,将未知区域标记为0

标注确定的前景图像函数connectedComponents

cv2. connectedComponents中:背景标注为0,其他对象使用从1开始的正整数标注

  • 数值0代表背景区域
  • 从数值1开始的值,代表不同的前景区域

在分水岭算法中,标注0代表未知区域,所以需要对上面的标注结果进行调整

  • 数值1代表背景区域
  • 从数值2开始的值,代表不同的前景区域
  • 对未知区域进行标注,将计算出的未知区域标注为0

retval, labels = cv2. connectedComponents(image )

  • images:8位单通道的待标注图像
  • retval :返回标注的数量
  • labels :标注的结果图像

markers = cv.watershed(img, markers)
进行分水岭算法

Markers = cv2.watershed(image, markers )

Image: 输入图像,必须是一个8bit 3通道的图像

  • 在处理之前必须用正数大致勾画出图像中的期望分割区域。
  • 每个区域被标注为1、2、3等。对尚未确定的区域,需要将它们标注为0.
  • 标注区域可以理解为进行分水岭算法分割的“种子”区域

markers: 32位单通道的标注结果,和image大小相同

  • 算法会根据markers传入的轮廓作为种子(也就是所谓的注水点),对图像上其他的像素点根据分水岭算法规则进行判断,并对每个像素点的区域归属进行划定
  • 每个像素要么要么被设置为初期的“种子值”,要么为“-1”
  • 区域与区域之间的分界处的值被置为“-1”
附录

官方文档:The Watershed Transformation

距离变换函数distanceTransform
提取前景对象
如果前景对象的中心(质心)距离值为0的像素点距离较远,会得到一个较大的值
如果前景对象的边缘距离值为0的像素点较近,会得到一个较小的值
在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章