【OpenCV-Python】教程:3-15 分水岭图像分割

news2024/9/20 9:12:18

OpenCV Python 分水岭图像分割

【目标】

  • 学习使用分水岭方法进行基于标记的图像分割
  • cv2.watershed()

【理论】

任何灰度图像都可以被视为地形表面,其中高强度表示山峰和丘陵,而低强度表示山谷,。你开始用不同颜色的水(标签)填充每个孤立的山谷(局部最小值)。随着水的上升,根据附近山峰(梯度),来自不同山谷的水,显然具有不同的颜色,将开始融合。为了避免这种情况,你需要在水汇合的地方建造障碍物,你继续注水和建造屏障,直到所有山峰都淹没在水下,然后,您创建的障碍会给出分割结果。这就是分水岭别后的“哲学”,您可以访问分水岭上的网页看动画,如下:

在这里插入图片描述

但是,由于图像中的噪声或任何其他不规则性,这种方法会产生过度分段的结果,因此,OpenCV实现了一种基于标记的分水岭算法,您可以制定哪些是要合并的所有谷点,哪些不是,这是一种交互式图像分割,我们所做的是为我们所知道的对象赋予不同的标签,用一种颜色标记我们确定是前景或对象的区域。用另一种颜色标记我们确定为背景或非对象的区域。最后,用0标记我们不确定的区域,这是我们的标记,然后应用分水岭算法,然后,我们的标记将使用我们给出的标签进行更新,对象的边界将为-1。

  • 分割的流程图

在这里插入图片描述

  1. 找到标记和分割标准(标准或函数常用于分离区域,常常是对比度或梯度,但不是必要的。
  2. 执行标记控制的分水岭算法。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

【代码】

利用距离变换和分水岭分割黏在一起的目标。

在这里插入图片描述

在这里插入图片描述

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

# 读入图像
img = cv2.imread('assets/water_coins.jpg')
gray = cv2.imread('assets/water_coins.jpg', 0)

# 阈值化
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)

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

# 通过距离变换,然后阈值化找前景
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
# 这个地方的阈值(0.5 * dist_transform.max())调节很重要,直接关系到后面的分割效果
ret, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, cv2.THRESH_BINARY)

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

# 标记连通区域
ret, markers = cv2.connectedComponents(sure_fg)

# 所有的标记+1,背景改为1,而不是0
markers = markers + 1

# # 标记不确定区域为0
markers[unknown==255] = 0

# 用分水岭方法找到标记,如果标记为 -1,则该位置设置蓝色,即边缘颜色
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]

# 显示分割的图像
image2 = np.uint8(img)
cv2.imshow("img2", image2)

# 显示各阶段的图像
plt.subplot(231), plt.imshow(gray, 'gray'), plt.title(
    'Original'), plt.xticks([]), plt.yticks([])
plt.subplot(232), plt.imshow(sure_bg, 'gray'), plt.title(
    'sure_bg'), plt.xticks([]), plt.yticks([])
plt.subplot(233), plt.imshow(sure_fg, 'gray'), plt.title(
    'sure_fg'), plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(dist_transform), plt.title(
    'dist_transform'), plt.xticks([]), plt.yticks([])
plt.subplot(235), plt.imshow(markers), plt.title(
    'markers'), plt.xticks([]), plt.yticks([])
plt.subplot(236), plt.imshow(img), plt.title(
    'img'), plt.xticks([]), plt.yticks([])
plt.show()

cv2.waitKey(0)
cv2.destroyAllWindows()

如果不进行 markers = markers + 1,则结果为:

在这里插入图片描述

如果不进行 markers[unknown==255] = 0,则结果为:

在这里插入图片描述

所以种子点 0 值 生成和选择很重要,直接影响到最终结果。

【接口】

  • distanceTransform
cv.distanceTransform(	src, distanceType, maskSize[, dst[, dstType]]	) ->	dst
cv.distanceTransformWithLabels(	src, distanceType, maskSize[, dst[, labels[, labelType]]]	) ->	dst, labels

计算图像中每个像素到最近0像素的精确或近似距离。如果为零值图像,那么距离当然为0。当 maskSize == DIST_MASK_PRECISEdistanceType == DIST_L2 , 运行算法 [73],函数已经用 TBB 进行了并行化优化了。其他情况下,使用算法[29]。这就是说寻找最近零像素的路径可以是 水平,垂直,对角 ,Knight’s Move(骑士运动?),整体的距离是通过一系列基础距离算出来的。水平垂直用 a 表示,对角用 b 表示,骑士移动用 c 表示

DIST_L1: a = 1, b=2

DIST_L2:
3 x 3: a=0.955, b=1.3693
5 x 5: a=1, b=1.4, c=2.1969
DIST_C: a = 1, b = 1
通常,对于快速的粗略距离估计用 DIST_L2 3x3 mask,如果精确的话用 DIST_L2 5x5 mask。不管怎么样,所有这些精确或近似的距离都是像素数量的线性函数。

  • src: 8位单通道二值图像
  • dst: 距离计算结果的图像,可以是8位或32位浮点单通道图像,图像尺寸与源图像一致;
  • labels: 输出的2D标签(也是 Voronoi 图-泰森多边形图),32位单通道。
  • distanceType: 距离类型
  • maskSize: 距离变换的Mask
  • labelType: 标签类型 see DistanceTransformLabelTypes.
  • distanceType 距离类型

在这里插入图片描述

  • DistanceTransformMasks 距离变换mask

在这里插入图片描述

  • DistanceTransformLabelTypes 距离变换标签类型

在这里插入图片描述

  • connectedComponents
cv.connectedComponents(	image[, labels[, connectivity[, ltype]]]	) ->	retval, labels

cv.connectedComponentsWithAlgorithm(	image, connectivity, ltype, ccltype[, labels]	) ->	retval, labels

计算二值图像中连通域标签
支持 Bolelli (Spaghetti) [26], Grana (BBDT) [97] and Wu’s (SAUF) [278] 算法;

  • image: 8位单通道图像
  • labels: 目标图像的标签
  • connectivity: 4 邻域或 8 邻域
  • ltype: 输出图像标签类型 支持 CV_32S, CV_16U
  • ccltype: 连通域算法类型 ConnectedComponentsAlgorithmsTypes
  • ConnectedComponentsAlgorithmsTypes

在这里插入图片描述

  • watershed
cv2.watershed(	image, markers	) ->	markers

执行基于标记图像的分割,利用分水岭的算法。 [171] .
在将图像传递给函数之前,必须在具有正(>0)索引的图像标记中大致勾勒出所需的区域。因此,每个区域都表示为一个或多个像素值为1、2、3等的连接组件。可以使用findContours和drawContours从二进制掩码中检索此类标记(请参见watershed.cpp演示)。标记是未来图像区域的“种子”。标记中的所有其他像素(其与轮廓区域的关系未知,应由算法定义)应设置为0。在函数输出中,标记中的每个像素都设置为“种子”分量的值,或在区域之间的边界处设置为-1。

  • image: 8位3通道图像
  • markers: 输入输出的32位单通道标记图像;

【参考】

  1. OpenCV 官方文档
  2. CMM page on Watershed Transformation
  3. Pedro Felzenszwalb and Daniel Huttenlocher. Distance transforms of sampled functions. Technical report, Cornell University, 2004.
  4. Gunilla Borgefors. Distance transformations in digital images. Computer vision, graphics, and image processing, 34(3):344–371, 1986.
  5. Federico Bolelli, Stefano Allegretti, Lorenzo Baraldi, and Costantino Grana. Spaghetti Labeling: Directed Acyclic Graphs for Block-Based Connected Components Labeling. IEEE Transactions on Image Processing, 29(1):1999–2012, 2019.
  6. Costantino Grana, Daniele Borghesani, and Rita Cucchiara. Optimized Block-Based Connected Components Labeling With Decision Trees. IEEE Transactions on Image Processing, 19(6):1596–1609, 2010.
  7. Kesheng Wu, Ekow Otoo, and Kenji Suzuki. Optimizing two-pass connected-component labeling algorithms. Pattern Analysis and Applications, 12(2):117–135, Jun 2009.
  8. Fernand Meyer. Color image segmentation. In Image Processing and its Applications, 1992., International Conference on, pages 303–306. IET, 1992.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/58376.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

耗时4个月,阿里架构师打造Java面试突击文档,10位朋友已拿offer

不论是校招还是社招都避免不了各种面试、笔试,如何去准备这些东西就显得格外重要。不论是笔试还是面试都是有章可循的,我这个有章可循”说的意思只是说应对技术面试是可以提前准备。运筹帷幄之后,决胜千里之外!不打毫无准备的仗 …

数据结构与算法(六) 贪心算法

这篇文章来讲贪心算法(Greedy Algorithm),这是一种特殊的动态规划算法 1、本质 我们在之前的文章中讲过,动态规划可以解决一类具有最优子结构和重叠子问题特征的问题 贪心算法本质上是一种特殊的动态规划算法,因此在…

微前端:qiankun的五种通信方式

背景 今天盘点一下 qiankun 父子应用的通信方式都有哪些,我发现了 5 种。 1、localStorage/sessionStorage 2、通过路由参数共享 3、官方提供的 props 4、官方提供的 actions 5、使用vuex或redux管理状态,通过shared分享 接下来我们一个一个进行说明 …

S/4HANA(本地部署或云版)跟 SAP 家族系统以及非SAP系统的集成,到底什么是推荐的方式?

笔者的知识星球,有朋友提问: S4HANA(本地部署或云版)跟SAP家族系统以及非SAP系统的集成,sap的标准/推荐做法是通过BTP还是直接连接,或者是根据目标系统分别选择?有参考链接最好了。 首先 SAP S/4HANA 的技术栈&#xf…

java数组应用(栈和队列以及酒店模拟)

1.编写程序,使用一维数组,模拟栈数据结构 要求1.栈内可以存放任意数据2.栈内提供push方法模拟压栈3.栈内提供pop方法模拟出栈4.栈的大小默认为10 新建MyStack类 /*** author DeYou* date 2022/11/10 23:01*/ public class MyStack {Object[] element;int index;public MyStack…

blender Eevee渲染器

文章目录简介.采样.环境光遮蔽.辉光.景深.次表面散射.屏幕空间反射.间接光照明.阴影.体积.简介. 1 EV渲染器是实时渲染,类似于游戏引擎,效果差于Cycles 2 EV渲染器使用的设备是显卡 采样. 1 渲染和视图分别指渲染模式和视图模式的采样值,值越大&#…

Android Studio 中MotinLayout的简单使用

​ 一、什么是MotionLayout MotionLayout 是一种布局类型,可帮助您管理应用中的运动和微件动画。MotionLayout 是 ConstraintLayout 的子类,在其丰富的布局功能基础之上构建而成。 二、使用MotionLayout的准备 1.添加MotionLayout依赖项 要在项目中使用…

【菜鸡读论文】Face2Exp: Combating Data Biases for Facial Expression Recognition

【菜鸡读论文】Face2Exp: Combating Data Biases for Facial Expression Recognition 最近上海开始降温了,而且常常下雨,天气开始变得好冷啊!以前年轻的时候冬天经常穿的少,现在膝盖开始有点遭不住了,小伙伴们一定要保…

Go字符串拼接6种方式及其性能测试:strings.builder最快

Go字符串拼接常见的方式有加号、fmt.Sprintf、strings.Builder、bytes.Buffer、strings.join、切片。 package concat_stringimport ("bytes""fmt""strconv""strings""testing" )const numbers 100// func BenchmarkStri…

Kafka安装与配置

1、Java环境为前提 (1)上传jdk-8u261-linux-x64.rpm到服务器并安装: rpm -ivh jdk-8u261-linux-x64.rpm (2)配置环境变量: vim /etc/profile # 生效 source /etc/profile # 验证 java -version 2、Zook…

贝叶斯定理~~概率分布

还是搬来了基础自己学习用哦 ~~ 从最基础的概率论到各种概率分布全面梳理了基本的概率知识与概念,这些概念可能会帮助我们了解机器学习或开拓视野。这些概念是数据科学的核心,并经常出现在各种各样的话题上。重温基础知识总是有益的,这样我们…

适应性哈夫曼编码(Adaptive Huffman coding)

适应性哈夫曼编码适应性哈夫曼编码简介算法示例适应性哈夫曼编码 简介 适应性哈夫曼编码(Adaptive Huffman coding),又称动态哈夫曼编码(Dynamic Huffman coding),是基于哈夫曼编码的适自适应编码技术。它…

深度学习Day07

Recurrent Neural Network 智慧客服——Slot Filling 根据上 下文产生不同的output

Java搭建宝塔部署实战毕设项目WMS仓库管理系统源码

大家好啊,我是测评君,欢迎来到web测评。 本期给大家带来一套Java开发的毕业设计项目WMS仓库管理系统源码。 技术架构 技术框架:SpringMVC Mybatis Ehcache bootstrap jquery mysql5.7运行环境:jdk8 nginx1.20 tomcat9 In…

基于PSO粒子群算法的MPPT最大功率跟踪Simulink仿真,PSO采用S函数实现

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 MPPT控制器的全称是“最大功率点跟踪”(Maximum Power Point Tracking)太阳能控制器,是传统太阳能充放电控制器的升级换代产品。MPPT控制器能够实时侦测太阳能…

30岁自学Python转行靠谱吗?

前言 30岁自学Python转行靠谱吗?若啃学习任何时候都不晚,关键是学习完用来做什么。提高工作效率,写些脚本实现自动化办公这些完全没问题。如果学python是为了转开发,建议慎重考虑,程序开发转Python相对容易些&#xf…

[附源码]计算机毕业设计血库管理系统Springboot程序

项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…

计算机网络——运输层【重点】

运输层概述 概念 进程之间的通信 从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。当网络的边缘部分中的两个主机使用网络的核心部分的功能进行端到端的通信时&…

【SpingBoot拦截器】实现两个接口,配置拦截路径

文章目录SpingBoot拦截器拦截器与过滤器的区别:1.HandlerInterceptor接口2.WebMvcConfigurer接口3.示例:SpingBoot拦截器 【SpringWeb框架中的拦截器作用类似于过滤器,都可以对一个请求进行拦截处理。】 我们可以用拦截器做很多事情&#xf…

使用HTML制作静态网站作业——我的校园运动会(HTML+CSS)

🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…