OpenCV—Python 分水岭算法图像分割「建议收藏」

OpenCV—Python 分水岭算法图像分割「建议收藏」文章目录一、前言二、cv2.distanceTransform(src,distanceType,maskSize)三、基于标记的分水岭分割功能四、示例代码一、前言分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征。其他图像分割方法,如阈…

大家好,又见面了,我是你们的朋友全栈君。

一、功能与函数介绍

分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近的像素点互相连接起来构成一个封闭的轮廓,封闭性是分水岭算法的一个重要特征
其他图像分割方法,如阈值,边缘检测等都不会考虑像素在空间关系上的相似性和封闭性这一概念,彼此像素间互相独立,没有统一性。分水岭算法较其他分割方法更具有思想性,更符合人眼对图像的印象。
在这里插入图片描述
任意的灰度图像可以被看做是地质学表面,高亮度的地方是山峰,低亮度的地方是山谷。给每个孤立的山谷(局部最小值)不同颜色的水(标签),当水涨起来,根据周围的山峰(梯度),不同的山谷也就是不同的颜色会开始合并,要避免这个,你可以在水要合并的地方建立障碍,直到所有山峰都被淹没。你所创建的障碍就是分割结果,这个就是分水岭的原理,但是这个方法会分割过度,因为有噪点,或者其他图像上的错误。所以OpenCV实现了一个基于掩模的分水岭算法,你可以指定哪些是要合并的点,哪些不是,这是一个交互式的图像分割,我们要做的是给不同的标签。给我们知道是前景或者是目标用一种颜色加上标签,给我们知道是背景或者非目标加上另一个颜色,最后不知道是什么的区域标记为0. 然后使用分水岭算法。

1.1 cv2.distanceTransform(src, distanceType, maskSize)

距离变换的基本含义是计算一个图像中非零像素点到最近的零像素点的距离,也就是到零像素点的最短距离个最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心呗Ⅵ像素点的距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换

参数:

distanceType – 距离类型:cv2.DIST_L1, cv2.DIST_L2 , cv2.DIST_C

maskSize – 距离变换蒙版的大小:取值3,5 或 CV_DIST_MASK_PRECISE(后一个选项仅由第一个函数支持)。在CV_DIST_L1或CV_DIST_C距离类型的情况下,参数被强制为3。

cv2.distanceTransformWithLabels()额外参数

labels – 可选输出2D标签数组(离散Voronoi图): 它的类型为CV_32SC1,大小与src相同

labelType – 构建标签数组的类型:
若为 DIST_LABEL_CCOMP,则src中每个连接的零组件(以及最接近连接组件的所有非零像素)将被分配相同的标签。
若为DIST_LABEL_PIXEL,那么每个零像素(以及最接近它的所有非零像素)都会获得自己的标签。

1.2 基于标记的分水岭分割功能
img = np.zeros((400, 400), np.uint8)
cv2.circle(img, (150, 150), 100, 255, -1)
cv2.circle(img, (250, 250), 100, 255, -1)

dist = cv2.distanceTransform(img, cv2.cv.CV_DIST_L2, cv2.cv.CV_DIST_MASK_PRECISE)
dist3 = np.zeros((dist.shape[0], dist.shape[1], 3), dtype = np.uint8)
dist3[:, :, 0] = dist
dist3[:, :, 1] = dist
dist3[:, :, 2] = dist

markers = np.zeros(img.shape, np.int32)
markers[150,150] = 1  # seed for circle one
markers[250, 250] = 2 # seed for circle two
markers[50,50] =  3   # seeds for background

cv2.watershed(dist3, markers)
1.3 示例代码
import numpy as np
import cv2


def watershed(imgpath):
    img = cv2.imread(imgpath)
    gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    ret0, thresh0 = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

    kernel = np.ones((3,3),np.uint8)
    opening = cv2.morphologyEx(thresh0,cv2.MORPH_OPEN,kernel, iterations = 2)

    # 确定背景区域
    sure_bg = cv2.dilate(opening,kernel,iterations=3)

    # 确定前景区域
    dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
    ret1, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

    # 查找未知区域
    sure_fg = np.uint8(sure_fg)
    unknown = cv2.subtract(sure_bg,sure_fg)

    # 标记标签
    ret2, markers1 = cv2.connectedComponents(sure_fg)
    markers = markers1+1
    markers[unknown==255] = 0

    markers3 = cv2.watershed(img,markers)
    img[markers3 == -1] = [0,255,0]
    return thresh0,sure_bg,sure_fg,img

if __name__ == '__main__':
    imgpath = './gggg/fenshuiling.png'
    thresh0, sure_bg, sure_fg, img = watershed(imgpath)

    cv2.imshow('thresh0',thresh0)
    cv2.imshow('sure_bg', sure_bg)
    cv2.imshow('sure_fg', sure_fg)
    cv2.imshow('result_img', img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

在这里插入图片描述

二、分水岭方法

在下面的例子中,需要将两个重叠的圆分开。我们先计算圆上的这些白色像素点到黑色背景像素点的距离变换,选出距离变换中的最大值作为初始标记点(如果是反色的话,则是取最小值),从这些标记点开始的两个汇水盆越集越大,最后相交于分山岭。从分山岭处断开,我们就得到了两个分离的圆。

示例:基于距离变换的分山岭图像分割

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage import morphology,feature

#创建两个带有重叠圆的图像
x, y = np.indices((80, 80))
x1, y1, x2, y2 = 28, 28, 44, 52
r1, r2 = 16, 20
mask_circle1 = (x - x1)**2 + (y - y1)**2 < r1**2
mask_circle2 = (x - x2)**2 + (y - y2)**2 < r2**2
image = np.logical_or(mask_circle1, mask_circle2)

#现在我们用分水岭算法分离两个圆
distance = ndi.distance_transform_edt(image) #距离变换
local_maxi =feature.peak_local_max(distance, indices=False, footprint=np.ones((3, 3)),labels=image)   #寻找峰值
markers = ndi.label(local_maxi)[0]           #初始标记点
labels =morphology.watershed(-distance, markers, mask=image) #基于距离变换的分水岭算法
# kimage.segmentation.watershed

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8, 8))
axes = axes.ravel()
ax0, ax1, ax2, ax3 = axes

ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax0.set_title("Original")
ax1.imshow(-distance, cmap=plt.cm.jet, interpolation='nearest')
ax1.set_title("Distance")
ax2.imshow(markers, cmap=plt.cm.gray, interpolation='nearest')
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.gray, interpolation='nearest')
ax3.set_title("Segmented")

for ax in axes:
    ax.axis('off')

fig.tight_layout()
plt.show()

在这里插入图片描述
分水岭算法也可以和梯度相结合,来实现图像分割。一般梯度图像在边缘处有较高的像素值,而在其它地方则有较低的像素值,理想情况 下,分山岭恰好在边缘。因此,我们可以根据梯度来寻找分山岭。

基于梯度的分水岭图像分割

import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage import morphology,color,data,filters

image =color.rgb2gray(data.camera())
denoised = filters.rank.median(image, morphology.disk(2)) #过滤噪声

#将梯度值低于10的作为开始标记点
markers = filters.rank.gradient(denoised, morphology.disk(5)) <10
markers = ndi.label(markers)[0]

gradient = filters.rank.gradient(denoised, morphology.disk(2)) #计算梯度
labels =morphology.watershed(gradient, markers, mask=image) #基于梯度的分水岭算法

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(6, 6))
axes = axes.ravel()
ax0, ax1, ax2, ax3 = axes

ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax0.set_title("Original")
ax1.imshow(gradient, cmap=plt.cm.gray, interpolation='nearest')
ax1.set_title("Gradient")
ax2.imshow(markers, cmap=plt.cm.gray, interpolation='nearest')
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.gray, interpolation='nearest')
ax3.set_title("Segmented")

for ax in axes:
    ax.axis('off')

fig.tight_layout()
plt.show()

在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150408.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 大数据云计算和物联网之间的区别和联系_云计算和大数据的区别

    大数据云计算和物联网之间的区别和联系_云计算和大数据的区别一、概念1.云计算“云”指通过计算机池提供资源,也就是说,不是构建一两台机器的问题,而是要构建一定规模的集群,并且对该集群统一管理,形成”资源池“,才能满足云计算业务的需求。简单地说,**云计算就是基于互联网将规模化资源池的计算、存储、平台开发和软件能力提供给用户,实现自动化、低成本、快速提供和灵活伸缩的IT服务。**云计算代表了以虚拟化技术为核心、以低成本为目标的、动态可扩展的…

    2022年10月7日
    1
  • 钱包地址 私钥_eth私钥就是收款地址吗

    钱包地址 私钥_eth私钥就是收款地址吗网上看到一个对比,很形象,可以用来加强理解:地址=银行卡卡号密码=银行卡密码keystore=银行卡助记词=私钥=银行卡+银行卡密码Keystore+密码=银

    2022年8月1日
    6
  • centos7安装python3.6_centos7一键安装python3

    centos7安装python3.6_centos7一键安装python3centos7安装Python3安装Python3安装Python31.安装wget(如已经存在,忽略此步)yum-yinstallwget2.下载python3源码包wgethttps://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz3.下载python3编译的依赖包yuminstall-ygccpatchlibffi-develpython-develzlib-develbzip2-develope

    2022年9月24日
    0
  • PLSQL操作Oracle创建用户和表

    PLSQL操作Oracle创建用户和表1、打开PLSQL,填写用户名和密码(初始有两个用户sys和system,密码是自己安装oracle数据库时定的),Database选择ORCL(默认数据库,oracle中创建的用户就像是mysql中建的数据库,两者有异曲同工之妙)2、登陆成功后在界面的头部可以看到一下信息,最上面的system@ORCL就表示是用户system在登录状态,其中菜单栏的session可以登录、退出…

    2022年5月19日
    43
  • mock测试概念「建议收藏」

    mock测试概念「建议收藏」mock测试概念:mock是在测试过程中,对于一些不容易构造/获取的对象,创建啊一个mock对象来模拟对象的行为mock对象使用范畴真实对象具有不可确定的行为。真实对象很难被创建。真实对象的某些行为很难触发。真实情况令程序运行速度很难。真实对象实际上并不存在。测试隔离的实现。mock有什么用?解除一些依赖关系,当测试部分接口实现,需要依赖于与其他接口与,而其他接口没完…

    2022年6月20日
    22
  • 大数据_03【大数据基础知识】

    大数据_03【大数据基础知识】大数据_0301大数据概述02什么是大数据?(BigData)03传统数据与大数据的对比04大数据的特点4.1传统数据与大数据处理服务器系统安装对比4.2大数据下服务器系统安装![在这里插入图片描述](https://img-blog.csdnimg.cn/20201006090915426.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV

    2022年5月4日
    42

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号