基于OpenCv的图像分割(分水岭算法)

news2025/3/1 18:50:57

文章目录

  • 图像分割
    • distanceTransform()
    • connectedComponents()
    • watershed()
    • 查看图像的矩阵

图像分割

图像分割对于图像处理和计算机视觉领域非常重要,可以用于对象识别、图像分析、图像压缩等应用。
注意:通常我们把前景目标的灰度值设为255,即白色,背景的灰度值设为0,即黑色。所以定义中的非零像素点即为前景目标,零像素点即为背景。
所以图像中前景目标中的像素点距离背景越远,那么距离就越大,如果我们用这个距离值替换像素值,那么新生成的图像中这个点越亮。

distanceTransform()

cv.distanceTransform()是OpenCV中的一个函数,用于计算二值图像中每个像素与离它最近的零像素之间的距离。dst = cv.distanceTransform(src, distanceType, maskSize)

其中,参数src是输入的二值图像,distanceType是距离类型,maskSize是距离计算模板的大小,dst是输出的距离变换图像。 distanceType参数指定了距离计算的类型,包括以下几种取值:

  • cv.DIST_L1: L1距离,也称曼哈顿距离。
  • cv.DIST_L2: L2距离,也称欧几里得距离。
  • cv.DIST_C: C距离,也称棋盘距离。
  • cv.DIST_L12: L1-L2混合距离,即先使用L1距离,再使用L2距离。
  • cv.DIST_FAIR: Fair距离。
  • cv.DIST_WELSCH: Welsch距离。
  • cv.DIST_HUBER: Huber距离。 maskSize参数指定了距离计算模板的大小,可以取3、5或者cv.CV_DIST_MASK_PRECISE。当maskSize为3或者5时,距离计算模板为3x3或5x5的矩形;当maskSize为cv.CV_DIST_MASK_PRECISE时,距离计算模板为精确的距离变换模板。

connectedComponents()

cv.connectedComponents()是OpenCV中的一个函数,用于对二值图像进行连通组件标记。该函数会将具有相同像素值的像素标记为同一个连通组件,并给每个连通组件分配一个唯一的标记。
num_labels, labels = cv.connectedComponents(image[, connectivity[, ltype]])

其中,参数image是输入的二值图像,connectivity是连通性,ltype是输出标签图像的数据类型,num_labels是标签的数量,labels是输出的标签图像。 connectivity参数指定了像素之间的连通规则,可以取4或8。当connectivity为4时,只考虑上下左右四个方向的像素;当connectivity为8时,还考虑对角线方向的像素。 ltype参数指定了输出标签图像的数据类型,可以取cv.CV_32S或cv.CV_16U。当标签数量很大时,应该使用cv.CV_32S类型,否则可以使用cv.CV_16U类型。 使用cv.connectedComponents()函数可以对二值图像进行连通组件标记,得到每个连通组件的标签,并可以根据标签提取连通组件。这个函数在图像分割、对象检测和跟踪等领域中广泛应用。

watershed()

cv.watershed()是OpenCV中的一个函数,用于实现分水岭算法,即对图像进行分割。该函数将图像看做一个地形图,将图像中的亮度值看做高度,然后在该地形图上进行分水岭分割。
markers = cv.watershed(image, markers)

其中,参数image是输入的待分割图像,markers是标记图像,表示原始图像中的每个像素所属的初始标记。初始标记可以是-1或0,-1表示不确定区域,0表示背景区域。函数执行完毕后,markers会被更新为分割后的标记图像,即表示原始图像中每个像素所属的分割区域。 使用cv.watershed()函数实现分水岭算法需要经过以下几个步骤:

  1. 对原始图像进行预处理,如去噪、平滑等。
  2. 对预处理后的图像进行二值化处理,得到二值图像。
  3. 对二值图像进行距离变换,得到距离变换图像。
  4. 对距离变换图像进行阈值处理,得到初始标记图像。
  5. 对初始标记图像进行分水岭分割,得到分割结果。
  6. 对分割结果进行后处理,如去除小区域、填充空洞等。 cv.watershed()函数可以用于图像分割、对象检测和跟踪等领域中,该函数的分割结果通常比较准确,但是容易受到噪声的影响,需要经过一定的调试才能得到较好的分割结果。

基于OpenCV的图像分割流程图

在这里插入图片描述

完整代码:

import numpy as np
import cv2 as cv
import matplotlib.pyplot as  plt
img = cv.imread('img/iron.png')
print(img.shape)# (393, 320, 3)
# 对图像颜色进行转换
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
# 阈值分割,将图像分为黑白两部分
ret,thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
# 去除图像中的任何白点噪声,使用形态学扩张,
kernel = np.ones((3,3),np.uint8)# 定义卷积核
# 对图像进行开运算:先腐蚀,再膨胀
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel,iterations=2)
# 注意:靠近对象中心的区域是前景目标,而离对象中心很远的区域是背景
# 确定背景区域:对开运算的结果进行膨胀,得到大部分都是背景的区域
sure_bg = cv.dilate(opening,kernel,iterations=2)# 膨胀操
# 距离变换,寻找前景区域:通过distanceTransform
dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)
print(dist_transform.max())# 30个像素点
# 获取边界
ret,sure_fg = cv.threshold(dist_transform,0.5*dist_transform.max(),255,0)
# 获得边界区域,找到未知区域
sure_fg = np.uint8(sure_fg)
unknow = cv.subtract(sure_bg,sure_fg)
# 类别标记,将具有相同像素值的像素标记为同一个连通组件,ret对连同区域进行标号
ret,markers = cv.connectedComponents(sure_fg)
print(markers.shape)# (393, 320)
# 将图像矩阵保存为文件
np.savetxt("image.txt", markers)
print(markers==1)
# 为所有的标记加1,保证背景是0而不是1
markers = markers+1
# 让所有的未知区域为0
markers[unknow==255] = 0
# 实施分水岭算法,标签图将会被修改,边界区域的标记将变为-1
markers = cv.watershed(img,markers)
img[markers == -1] = [255,0,0]
# 图片展示
plt.subplot(241), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)),
plt.title('Original'), plt.axis('off')
plt.subplot(242), plt.imshow(thresh, cmap='gray'),
plt.title('Threshold'), plt.axis('off')
plt.subplot(243), plt.imshow(sure_bg, cmap='gray'),
plt.title('Dilate'), plt.axis('off')
plt.subplot(244), plt.imshow(dist_transform, cmap='gray'),
plt.title('Dist Transform'), plt.axis('off')
plt.subplot(245), plt.imshow(sure_fg, cmap='gray'),
plt.title('Threshold'), plt.axis('off')
plt.subplot(246), plt.imshow(unknow, cmap='gray'),
plt.title('Unknow'), plt.axis('off')
plt.subplot(247), plt.imshow(np.abs(markers), cmap='jet'),
plt.title('Markers'), plt.axis('off')
plt.subplot(248), plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB)),
plt.title('Result'), plt.axis('off')
plt.show()

在这里插入图片描述

查看图像的矩阵

方式一: 将图像矩阵保存为文件

# 将图像矩阵保存为文件
np.savetxt("image.txt", markers)

方式二:通过DeBug进行查看

在需要查看数据代码的左边,点击进行断点,然后点击debug模式启动,当运行完该行之后,需要的数据会出现在Variables中,我们可以点击查看,但是这样往往是从整体上进行查看,而不能查看具体的矩阵内容,我们可以进行如下操作:
在这里插入图片描述
操作后,可以看到VciView中可以看到
在这里插入图片描述

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

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

相关文章

网络原理与网络通信

目录 网络互连原理 网络通信 IP地址和端口号 网络协议 五元组 协议分层 OSI七层模型 TCP/IP五层模型 封装和分用 网络互连原理 计算机在最开始的时候是没有网络的,每个计算机之间相互独立。这样处理信息就非常的麻烦,为了能够更高效的利用计算…

一个基于Java线程池管理的开源框架Hippo4j实践

文章目录概述定义线程池痛点功能框架概览架构部署Docker安装二进制安装运行模式依赖配置中心接入流程个性化配置线程池监控无中间件依赖接入流程服务端配置三方框架线程池适配拒绝策略自定义概述 定义 Hippo4j 官网地址 https://hippo4j.cn/ 最新版本1.5.0 Hippo4j 官网文档地…

硬件系统工程师宝典(17)-----你的PCB符合工艺要求吗?

各位同学大家好,欢迎继续做客电子工程学习圈,今天我们继续来讲这本书,硬件系统工程师宝典。上篇我们说到PCB设计中板子要符合EMC,信号的走线要平顺,信号回流阻抗尽量小。今天我们开始看看板子在生产制造时的工艺问题。…

【安全防御】防火墙(二)

目录 1、防火墙如何处理双通道协议 2、防火墙如何处理nat 3、防火墙支持哪些NAT,主要应用的场景是什么? 4、当内网PC通过公网域名解析访问内网服务器的时候,会存在什么问题,如何解决?请详细说明 5.防火墙使用VRRP…

面试题总结-JS

文章目录一、JS 系列1、原型、原型链2、闭包3、this指向4、call、 apply、 bind 的作用与区别?5、数组扁平化6、var、let、const 区别7、对称加密和不对称加密的区别8、js 的栈和堆9、对象的深拷贝和浅拷贝10、浏览器的事件循环机制11、宏任务和微任务12、script 标…

StringBuilder、StringBuffer、String的区别

StringBuilder与StringBuffer的append方法源码分析 #mermaid-svg-N8145OzAyMWzlewt {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-N8145OzAyMWzlewt .error-icon{fill:#552222;}#mermaid-svg-N8145OzAyMWzlewt .er…

C#基础学习--泛型

目录 C#中的泛型 泛型类 声明泛型类 创建构造函数 创建变量和实例 类型参数的约束 Where 子句 泛型方法 声明泛型方法 ​编辑 调用泛型方法 扩展方法和泛型类 泛型结构 泛型委托 泛型接口 协变 逆变 接口的协变和逆变 C#中的泛型 泛型允许我们声明 类型参数化 的代码&…

Jetpack Compose大师乘势而上,创建引人入胜和直观的UI;实用技巧和技术

简述 Jetpack Compose 是 Android 上的一种全新的 UI 工具箱,旨在简化 Android UI 开发流程,提高开发效率和应用性能,并且提供更直观、更灵活、更强大的 UI 定义方式。 Jetpack Compose 提供了一套新的声明式 UI 编程模型,采用 …

【Redis】多级缓存(nginx缓存、redis缓存及tomcat缓存)

【Redis】多级缓存 文章目录【Redis】多级缓存1. 传统缓存的问题2. 多级缓存方案2.1 JVM进程缓存2.1.1 本地进程缓存2.1.2 Caffeine2.2 Nginx缓存2.2.1 准备工作2.2.2 请求参数处理2.2.3 nginx发送http请求tomcat2.2.3.1 封装http查询函数2.2.3.2 使用http函数查询数据2.2.4 ng…

Huffman 编码

1.Huffman编码 1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。 2.Huffman树 树是一种重要的非线性数据结构,它是数据元…

​2023年十大目标检测模型!

“目标检测是计算机视觉中最令人兴奋和具有挑战性的问题之一,深度学习已经成为解决该问题的强大工具。”—Dr. Liang-Chieh Chen目标检测是计算机视觉中的基础任务,它涉及在图像中识别和定位目标。深度学习已经革新了目标检测,使得在图像和视…

【CV大模型SAM(Segment-Anything)】真是太强大了,分割一切的SAM大模型使用方法:可通过不同的提示得到想要的分割目标

目录前言安装运行环境SAM模型的使用方法导入相关库并定义显示函数导入待分割图片使用不同提示方法进行目标分割方法一:使用单个提示点进行目标分割方法二:使用多个提示点进行目标分割方法三:用方框指定一个目标进行分割方式四:将点…

文件操作和IO—javaEE

文章目录1.文件1.1文件系统的结构1.2java中的文件操作(metadata的操作)2.io操作2.1定义2.2io划分2.3java的io流之输入流2.4java的io流之输出流1.文件 文件包含数据本身和文件的头信息(metadata),文件的头信息包括文件…

VSCode的C/C++编译调试环境搭建(亲测有效)

文章目录前言1.安装VSCode和mingw642.配置环境变量3.配置VSCode的运行环境3.1设置CodeRunner3.2设置C/C4.调试环境配置前言 这片博客挺早前就写好了,一直忘记发了,写这篇博客之前自己配的时候也试过很多博客,但无一例外,都各种js…

SpringBoot(4)整合数据源

SpringBoot整合数据源数据层解决方案数据源技术持久化技术数据库技术NoSQL整合Redis整合MongDB整合ES数据层解决方案 MySQL数据库与MyBatisPlus框架,后面又用了Druid数据源的配置,所以现在数据层解决方案可以说是MysqlDruidMyBatisPlus。而三个技术分别…

一文彻底了解派克Parker无铁芯/有铁芯直线电机及其应用

一、什么是直线电机? 直线电机是一种将电能直接转换成直线运动机械能,而不需要任何中间转换机构的传动装置。它可以看成是一台旋转电机按径向剖开,并展成平面而成。 二、直线电机的特点 直线电机类似于一台旋转电机解剖摊开来进行运转。在一…

9、DRF实战总结:过滤(filter)与排序,以及第三方库django-filter的使用(附源码)

在前面的DRF系列教程中,以博客为例介绍了序列化器(Serializer), 并使用基于类的视图APIView和ModelViewSet开发了针对文章资源进行增删查改的完整API接口,并详细对权限、认证(含jwt认证)和分页进行了总结与演示。在本篇文章中将向演示如何在Django REST …

Boost库在windows上的使用

今天要配置一个C环境,被Boost库困扰了一段时间,在这里记录一下解决的方法。 主要是打不开 libboost_iostreams-vc143-mt-gd-x64-1_82.lib这样的问题。 操作的步骤如下: 下载binary包: 链接: https://boostorg.jfrog.io/artifac…

ChatGPT有用到知识图谱吗?它自己是这样回答...

从搜索引擎到个人助手,我们每天都在使用问答系统。问答系统必须能够访问相关的知识并进行推理。通常,知识可以隐式地编码在大型语言模型(LLMs)中,例如ChatGPT、T5 和LaMDA 等大型语言模型,这些模型在未结构…

如何面对人生困境至暗时刻

北方春天伊始刚好想发表下另一种境遇就是当人生面临困境或者至暗怎么样走出来,如果有正面临这样的情况来分享下如何走出阴霾,拥有更多可能性的人生,现在回望过去一年的自己太过牵强失去自我。 对世界的应该思维:为什么我总看不清现…