当前位置: 首页 > news >正文

OpenCV学习 基础图像操作(十七):泛洪与分水岭算法

原理

泛洪填充算法和分水岭算法是图像处理中的两种重要算法,主要用于区域分割,但它们的原理和应用场景有所不同,但是他们的基础思想都是基于区域迭代实现的区域之间的划分

泛洪算法

泛洪填充算法(Flood Fill)是一种经典的图像处理算法,用于确定和标记与给定点连接的区域,通常在图像填充、分割、边界检测等方面应用广泛。为了更直观地理解泛洪填充算法,我们可以通过一系列生动的图像和步骤来介绍其工作原理。

假设我们有一个二维图像,每个像素可以有不同的颜色或灰度值。泛洪填充算法的目标是从某个起始像素开始,填充所有与其相连且具有相同颜色的像素。常见的应用包括图像编辑中的填充工具(如油漆桶工具)和迷宫求解等。

算法流程

以下是泛洪填充算法的基本步骤,配合图像说明:

  1. 选择起始点和目标颜色

    1. 选择图像中的一个起始像素点(如鼠标点击的位置),记作 (x, y)。
    2. 确定要填充的目标颜色。
  2. 初始化队列

    • 将起始点 (x, y) 加入队列。
  3. 处理队列

    当队列不为空时,重复以下步骤:
    • 从队列中取出一个像素点 (cx, cy)。
    • 如果 (cx, cy) 的颜色等于目标颜色,则进行填充。
    • 将 (cx, cy) 的四个邻居(上、下、左、右)加入队列(如果这些邻居还没有被处理过且颜色等于目标颜色)。

分水岭算法

分水岭算法是一种基于形态学和拓扑学的图像分割技术。它将图像视为一个拓扑地形,通过标记图像的不同区域(例如山脉和盆地)进行分割。分水岭算法的基本思想是通过模拟雨水从山顶流向盆地的过程,确定图像中不同区域的边界。

分水岭迭代过程:

  1. 把梯度图像中的所有像素按照灰度值进行分类,并设定一个测地距离阈值。
  2. 找到灰度值最小的像素点(默认标记为灰度值最低点),让threshold从最小值开始增长,这些点为起始点。
  3. 水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
  4. 随着水平面越来越高,会设置更多更高的大坝,直到灰度值的最大值,所有区域都在分水岭线上相遇,这些大坝就对整个图像像素的进行了分区。

实际应用时常结合其他预处理,来实现前后景的分割:

算法流程

  1. 梯度计算: 首先计算图像的梯度,梯度可以使用 Sobel 算子或其他方法计算。梯度图像反映了图像中像素值变化的幅度。

    G(x,y)=\sqrt{(\frac{\partial I}{\partial x})^2+(\frac{\partial I}{\partial y})^2}

    其中,𝐼 是原始图像,𝐺是梯度图像。

  2. 标记区域: 对图像进行标记,将前景对象和背景标记出来。可以使用形态学操作来获取这些标记。

    • 确定前景:使用距离变换和阈值化来确定前景区域。

      D(x,y)=distance\_tranform(I)
      foreground(x,y)=\begin{cases} 1 & \text{ if } D(x,y) > 1 \\ 0 & \text{ if } othersize \end{cases}

    • 确定背景:通过膨胀操作扩展前景区域,从而确定背景区域。

      background(x,y)=dilate(foreground,kernel)

  3. 确定未知区域: 未知区域是背景和前景的差集。

    unknown=background-foreground

  4. 连接组件标记: 对前景区域进行连通组件标记,每个连通组件代表一个独立的前景对象。

    markers=connected\_components(foreground)

  5. 分水岭变换: 使用分水岭变换对梯度图像进行处理,分割图像中的不同区域。

    markers=watershed(G,markers)

    分水岭变换后,标记图像的边界区域将被标记为 -1。

API介绍

floodfill

int cv::floodFill	(	InputOutputArray 	image,   //输入图像InputOutputArray 	mask,                        //输入输出的maksPoint 	seedPoint,                               //种子点Scalar 	newVal,                                  //信的Rect * 	r    ect = , 0                           // 存储填充区域的边界Scalar 	loDiff = , Scalar()                      // 允许填充的像素值差的下届Scalar 	upDiff = , Scalar()                      // 允许填充的像素值差的上届int 	flags = 4                                // 4联通或8联通
)	
import cv2
import numpy as np
import matplotlib.pyplot as plt
def main():# 加载图像image_path = 'D:\code\src\code\lena.jpg'  # 替换为你的图像路径image = cv2.imread(image_path)if image is None:print("Error: Unable to load image.")return# 定义种子点和新颜色seed_point = (30, 30)  # 替换为你希望的种子点 (x, y)new_color = (0, 0, 255)  # 新颜色为绿色 (B, G, R)# 创建掩码,比原图多出两行两列mask = np.zeros((image.shape[0] + 2, image.shape[1] + 2), np.uint8)# 设置差值范围lo_diff = (10, 10, 10)up_diff = (10, 10, 10)image_src = image.copy()# 执行泛洪填充flags = 4  # 4-连通num, im, mask, rect = cv2.floodFill(image, mask, seed_point, new_color, lo_diff, up_diff, flags)# 显示填充后的图像plt.subplot(131),plt.imshow(image_src[...,::-1]),plt.title('Source Image'), plt.xticks([]), plt.yticks([])plt.subplot(132),plt.imshow(mask[...,::-1]),plt.title('Mask Image'), plt.xticks([]), plt.yticks([])plt.subplot(133),plt.imshow(image[...,::-1]),plt.title('Filled Image'), plt.xticks([]), plt.yticks([])plt.show()if __name__ == '__main__':main()

watermeshed

cv::watershed	(	InputArray 	image,  //输入图像
InputOutputArray 	markers             //输入出的标记
)	
//即根据传入的确信区域以及原图,经过分水岭迭代后,得到的确信区域
import cv2
import numpy as np
import matplotlib.pyplot as plt
import imageiodef plot_image(image, title, save_path):plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))plt.title(title)plt.axis('off')plt.savefig(save_path)plt.close()def save_gif(frames, filename, duration=0.5):imageio.mimsave(filename, frames, duration=duration)def watershed_segmentation(image_path):# Read the imageimage = cv2.imread(image_path)gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# Apply thresholdingret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# Noise removal with morphological operationskernel = np.ones((3, 3), np.uint8)opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)# Sure background areasure_bg = cv2.dilate(opening, kernel, iterations=3)# Finding sure foreground areadist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)# Finding unknown regionsure_fg = np.uint8(sure_fg)unknown = cv2.subtract(sure_bg, sure_fg)# Marker labellingret, markers = cv2.connectedComponents(sure_fg)# Add one to all labels so that sure background is not 0, but 1markers = markers + 1# Now, mark the region of unknown with zeromarkers[unknown == 255] = 0# Apply watershedmarkers = cv2.watershed(image, markers)image[markers == -1] = [255, 0, 0]  # Mark boundaries with red color# Collect frames for GIFframes = []for step in ['Original', 'Threshold', 'Morph Open', 'Sure BG', 'Sure FG', 'Unknown', 'Markers', 'Watershed']:if step == 'Original':frame = image.copy()elif step == 'Threshold':frame = cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR)elif step == 'Morph Open':frame = cv2.cvtColor(opening, cv2.COLOR_GRAY2BGR)elif step == 'Sure BG':frame = cv2.cvtColor(sure_bg, cv2.COLOR_GRAY2BGR)elif step == 'Sure FG':frame = cv2.cvtColor(sure_fg, cv2.COLOR_GRAY2BGR)elif step == 'Unknown':frame = cv2.cvtColor(unknown, cv2.COLOR_GRAY2BGR)elif step == 'Markers':frame = np.zeros_like(image)for i in range(1, ret + 1):frame[markers == i] = np.random.randint(0, 255, size=3)elif step == 'Watershed':frame = image.copy()frame_path = f"{step.lower().replace(' ', '_')}.png"plot_image(frame, step, frame_path)frames.append(imageio.imread(frame_path))return frames# Main execution
image_path = 'D:\code\src\code\R-C.png'  # Replace with your image path
frames = watershed_segmentation(image_path)
save_gif(frames, 'watershed.gif', duration=1000)

参考链接

OpenCV(26)图像分割 -- 距离变换与分水岭算法(硬币检测、扑克牌检测、车道检测)_分水岭算法分割咖啡豆-CSDN博客

图像处理之漫水填充算法(flood fill algorithm)-腾讯云开发者社区-腾讯云 (tencent.com)

【OpenCV(C++)】分水岭算法_opencv分水岭c++-CSDN博客

相关文章:

OpenCV学习 基础图像操作(十七):泛洪与分水岭算法

原理 泛洪填充算法和分水岭算法是图像处理中的两种重要算法,主要用于区域分割,但它们的原理和应用场景有所不同,但是他们的基础思想都是基于区域迭代实现的区域之间的划分。 泛洪算法 泛洪填充算法(Flood Fill)是一…...

Docker基础命令(三)

同步docker容器中的时间和本地时间一致 背景: 在很多时候, 训练模型的时候, 记录的log日志中标记的时间和实际的时间不一致, 往往是容器时间和本地时间不一致照成的. 方案 场景一: 正在运行的容器,可以宿主机直接执行命令给某个容器同步时间 #方法1 直接在宿主机…...

Python的第三方库OS库

读者大大们好呀!!!☀️☀️☀️ 🔥 欢迎来到我的博客 👀期待大大的关注哦❗️❗️❗️ 🚀欢迎收看我的主页文章➡️寻至善的主页 文章目录 🔥前言🚀OS/SHUTIL 的方法描述🚀OS/SHUTIL…...

两个数相加减高级实现

不使用实现两数相加 #include <stdio.h> int plus(int a, int b) {int sum0,addication0;while(b!0){sum a^b;addication (a&b)<<1;a sum;b addication;}return a; }不使用-实现两数相减 #include <stdio.h> int sub(int a, int b) {int sum0,abdc…...

小白跟做江科大32单片机之对射式红外传感器计次

原理部分 1中断示意图&#xff0c;中断会打断主函数的执行&#xff0c;终端执行完成之后再返回主函数继续执行 2.STM32中断 这些灰色的是内核中断 这些白色的是普通中断 3.NVIC统一管理中断&#xff0c;每个中断通道都拥有16个可编程的优先等级&#xff0c;可对优先级进行分组…...

安装Kubernetes v3 ----以docker的方式部署

以docker的方式部署 docker run -d \ --restartunless-stopped \ --namekuboard \ -p 80:80/tcp \ -p 10081:10081/tcp \ -e KUBOARD_ENDPOINT"http://192.168.136.55:80" \ -e KUBOARD_AGENT_SERVER_TCP_PORT"10081" \ -v /root/kuboard-data:/data \ e…...

新游启航 失落的方舟台服注册指南 一文教会你方舟台服注册

新游启航&#xff01;失落的方舟台服注册指南&#xff01;一文教会你方舟台服注册 失落的方舟作为本月最受期待游戏之一&#xff0c;在上线之际许多玩家已经有点急不可待了。这款游戏是由开发商Smile gate开发的一款MMORPG类型游戏&#xff0c;这款游戏的基本玩法与其他MMORPG…...

运维开发详解

运维开发&#xff08;DevOps&#xff09;是开发&#xff08;Development&#xff09;和运维&#xff08;Operations&#xff09;的结合&#xff0c;旨在通过自动化和协作提高软件开发和交付的效率、速度和可靠性。DevOps强调文化、实践和工具的融合&#xff0c;以实现持续集成&…...

英伟达(NVIDIA)H100性能及应用场景

英伟达H100是一款性能强大的GPU芯片&#xff0c;其关键性能参数和应用领域可以归纳如下&#xff1a; 一、性能参数 架构&#xff1a;H100采用了新一代的Hopper架构&#xff0c;拥有高达1.8万亿次/秒的张量处理能力和高达840 TFLOPS的FP8张量性能。CUDA核心数&#xff1a;H100…...

充电宝怎么选?充电宝目前什么牌子质量好耐用?盘点好用充电宝

充电宝怎么选&#xff1f;是不是很多朋友在选充电宝上非常的纠结&#xff1f;在买充电宝上面还是非常有讲究的&#xff01;市面上的充电宝虽然多&#xff0c;但是不排除很多存在安全隐患的&#xff0c;如果稍微没有挑选好充电宝的话&#xff0c;买来的充电宝极大可能是存在非常…...

智能视频监控技术为游泳馆安全护航,助力安全管理新升级

随着社会的进步和科技的发展&#xff0c;视频监控技术在各行各业的应用越来越广泛。游泳馆作为公共场所&#xff0c;每天都会有大量的游泳者进出。在这样的环境中&#xff0c;有时难免会发生一些意外事故&#xff0c;如溺水、摔倒等。因此&#xff0c;视频监控建设的必要性尤为…...

Windows通过cmd运行快速启动应用

Windows如何通过cmd运行快速启动应用&#xff1f; 在Windows操作系统中&#xff0c;可以通过配置环境变量的方式将文件的路径配置到环境变量的path中&#xff0c;配置完成后可以在cmd中输入对应的应用名称即可启动应用&#xff0c;具体操作如下&#xff1a; 1. 添加应用程序路径…...

271 基于matlab的可调Q因子小波变换故障诊断

基于matlab的可调Q因子小波变换故障诊断&#xff0c;可用在轴承、齿轮、活塞等故障诊断中&#xff0c;程序中包含了原始TQWT工具箱和轴承振动信号信号的谱包络的求取。通过仿真数据、实际轴承数据说明了方法的效果。程序已调通&#xff0c;可直接运行。 271 可调Q因子小波变换 …...

吴恩达深度学习个人笔记

1. 上一个视频提到的房地产领域,我们不就使用了一个普遍标准神经网络架构吗 而对于图像识别处理问题,我们则要使用卷积神经网络(Convolution Neural Network),即CNN。 对于序列数据,例如音频,有一个时间组件,随着时间的推移,音频被播放出来, 所以音频是最自然的表…...

Spring的依赖注入DI

调用构造器方法注入: 需要有对应匹配的构造器 不然出现异常No matching constructor Spring构造器注入有三种不同方式 name :按照参数名称 <bean id"stu" class"com.xja.bean.Student"> <constructor-arg name"name" value"rk&…...

Java 获取和修改期日与时间的各种操作方法

LocalDateTime获取当地日期和时间 import java.time.LocalDateTime; /*LocalDateTime.now() 获取当前时间*/ public class LocalDateTimeDemo {public static void main(String[] args) {LocalDateTime time1 LocalDateTime.now();System.out.println(time1);//2024-06-01T13…...

【ubuntu20】--- 定时同步文件

在编程的艺术世界里&#xff0c;代码和灵感需要寻找到最佳的交融点&#xff0c;才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里&#xff0c;我们将共同追寻这种完美结合&#xff0c;为未来的世界留下属于我们的独特印记。 【Linux命令】--- 多核压缩命令大全&…...

网吧|基于SprinBoot+vue的网吧管理系统(源码+数据库+文档)

网吧管理系统 目录 基于SprinBootvue的网吧管理系统 一、前言 二、系统设计 三、系统功能设计 1 管理员功能模块 2 网管功能模块 3 会员功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&#xff1a; 博主介绍&#…...

[C/C++] -- Libcurl开发

libcurl 是一个功能强大的 C 语言库&#xff0c;用于实现各种网络传输协议的客户端功能。它是 Curl 工具的核心&#xff0c;并提供了一个简单、灵活、高效的 API&#xff0c;允许开发人员在他们的应用程序中轻松地执行网络操作。 以下是 libcurl 的一些主要特点和功能&#xf…...

Streamsets-JDBC模式使用更新时间字段数据同步

StreamSets的开源地址&#xff1a;https://github.com/streamsets/datacollector-oss Streamsets官网地址&#xff1a;https://streamsets.com/ Streamsets文档地址&#xff1a;https://docs.streamsets.com/portal/datacollector/3.16.x/help/index.html 我又来写Streamsets了…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战

前言 现在我们有个如下的需求&#xff0c;设计一个邮件发奖的小系统&#xff0c; 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式&#xff08;Decorator Pattern&#xff09;允许向一个现有的对象添加新的功能&#xff0c;同时又不改变其…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

使用分级同态加密防御梯度泄漏

抽象 联邦学习 &#xff08;FL&#xff09; 支持跨分布式客户端进行协作模型训练&#xff0c;而无需共享原始数据&#xff0c;这使其成为在互联和自动驾驶汽车 &#xff08;CAV&#xff09; 等领域保护隐私的机器学习的一种很有前途的方法。然而&#xff0c;最近的研究表明&…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

Unit 1 深度强化学习简介

Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库&#xff0c;例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体&#xff0c;比如 SnowballFight、Huggy the Do…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...