c++视觉处理----分水岭算法

news2024/11/29 12:47:45

分水岭算法

分水岭算法是一种图像处理和分割算法,通常用于分离数字图像中的不同对象或区域。该算法的名称来自地理学中的"分水岭"概念,其中高地图上的山脊分割了不同的水流方向,类似地,分水岭算法可以分割图像中的不同区域。

这一算法的基本思想是将图像视为地形地貌,其中亮度或颜色表示高度,然后寻找图像中的潜在分水岭,即潜在的分隔线。分水岭算法通常在图像中选择种子点(种子像素),然后通过模拟水流汇聚的方式,确定哪些像素属于不同的区域。

分水岭算法在图像分割、边缘检测和物体识别等领域被广泛使用,但它也有一些挑战,如过度分割和需要精确的初始化。因此,通常需要结合其他图像处理技术来改进分割结果。

分水岭算法用来进行图像分割。分水岭算法是一种常用的图像分割方法,它基于图像中像素值的梯度信息以及用户指定的标记(markers)来分割图像中的不同对象或区域。

以下是 cv::watershed() 函数的典型用法:

cv::watershed(image, markers);
  • image: 输入的图像,通常是灰度图像。
  • markers: 用于指定分割的标记图像,其中包含了用户标记的区域。标记图像应该是一个单通道图像,使用整数值来标记不同的区域。通常,用户需要在标记图像中指定种子点,以表示不同的对象或区域。

cv::watershed() 函数执行以下步骤:

  1. 基于输入图像的梯度信息,找到图像中的局部最小值点,这些点被视为潜在的区域分水岭。
  2. 在标记图像中以不同的整数值标记这些潜在的分水岭点。
  3. 模拟水从分水岭点流入低梯度区域,以此确定不同区域之间的边界。

分水岭算法的结果是一个标记图像,其中不同的区域使用不同的整数值标记。分割线(分水岭)使用 -1 标记。分割后的图像可以通过分析标记图像来获得。

分水岭算法在图像分割、边缘检测和对象识别等应用中非常有用,尤其是当需要区分并分割不同的对象或区域时。

#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace std;
using namespace cv;
#include <iostream>
#include <fstream>
using namespace cv; //包含cv命名空间
#include <opencv2/core/core.hpp>
//-- -------------------------【宏定义部分】---------------------------
// 描述:定义一些辅助宏
#define WINDOW_NAME "【程序窗口1】" //为窗口标题定义的宏
//-------------------------【全局函变量声明部分】---------------------
// 描述: 全局变量的声明
//- ------------------------ -------
Mat g_maskImage, g_srcImage;
Point prevPt(-1, -1);
//-----------------------------------------【全局函数声明部分】------------
// 描述:全局函数的声明
// ----- ----
static void ShowHelpText();
static void on_Mouse(int event, int x, int y, int flags, void*);
//---------------------------【main()函数】-------------------------
// 描述: 控制台应用程序的入口函数, 我们的程序从这里开始执行
int main(int argc, char** argv)
{
	//【1】截入原图并显示,初始化掩膜和灰度图
	g_srcImage = imread("1.jpg", 1);
	imshow(WINDOW_NAME, g_srcImage);
	Mat srcImage, grayImage;
	g_srcImage.copyTo(srcImage);
	cvtColor(g_srcImage, g_maskImage, COLOR_BGR2GRAY);
	cvtColor(g_maskImage, grayImage, COLOR_GRAY2BGR);
	g_maskImage = Scalar::all(0);
	//【2】设置鼠标回调函数
	setMouseCallback(WINDOW_NAME, on_Mouse, 0);
	//【3】轮询按键, 进行处理
	while (1)
	{
		//获取键值
		int c = waitKey(0);
		//若按键键值为 ESC时, 退出
		if ((char)c == 27)
			break;
		//按键键值为2时,恢复源图
		if ((char)c == '2')
		{
			g_maskImage = Scalar::all(0);
			srcImage.copyTo(g_srcImage);
			imshow("image", g_srcImage);
		}
		//若检测到按键值为1或者空格, 则进行处理
		if ((char)c == '1' || (char)c == ' ')
		{
			//定义一些参数
			int i, j, compCount = 0;
			vector<vector<Point> > contours;
			vector<Vec4i> hierarchy;
			//寻找轮廓
			findContours(g_maskImage, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
			//轮廓为空时的处理
			if (contours.empty())
				continue;
			//复制掩膜
			Mat maskImage(g_maskImage.size(), CV_32S);
			maskImage = Scalar::all(0);
			//循环绘制出轮廓
			for (int index = 0; index >= 0; index = hierarchy[index][0], compCount++)
				drawContours(maskImage, contours, index,
					Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX);
			//compCount为零时的处理
			if (compCount== 0)
				continue;
			//生成随机颜色
			vector<Vec3b> colorTab;
			for (i = 0; i < compCount; i++)
			{
				int b = theRNG().uniform(0, 255);
				int g = theRNG().uniform(0, 255);
				int r = theRNG().uniform(0, 255);
				colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
			}
			//计算处理时间并输出到窗口中
			double dTime = (double)getTickCount();
			watershed(srcImage, maskImage);
			dTime = (double)getTickCount() - dTime;
			printf("\t处理时间 = %gms\n",
				dTime * 1000. / getTickFrequency());
			//双层循环,将分水岭图像遍历存入watershedImage中
			Mat watershedImage(maskImage.size(), CV_8UC3);
			for (i = 0; i < maskImage.rows; i++)
				for (j = 0; j < maskImage.cols; j++)
				{
					int index = maskImage.at<int>(i, j);
					if (index == -1)
						watershedImage.at<Vec3b>(i, j) = Vec3b(255, 255, 255);
					else if (index <= 0 || index > compCount)
						watershedImage.at<Vec3b>(i, j) - Vec3b(0, 0, 0);
					else
						watershedImage.at<Vec3b>(i, j) = colorTab[index - 1];
				}
			//混合灰度图和分水岭效果图并显示最终的窗口
			watershedImage = watershedImage * 0.5 + grayImage * 0.5;
			imshow("watershed transform", watershedImage);
		}
	}
	return 0;
}
//--【onMouse()函数】--
// 描述: 鼠标消息回调函数
static void on_Mouse(int event, int x, int y, int flags, void*)
{
	//处理鼠标不在窗口中的情况
	if (x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows)return;
	//处理鼠标左键相关消息
	if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
		prevPt = Point(-1, -1);
	else if (event== EVENT_LBUTTONDOWN)
		prevPt = Point(x, y);
	//鼠标左键按下并移动,绘制出白色线条
	else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
	{
		Point pt(x, y);
		if (prevPt.x < 0)
			prevPt = pt;
		line(g_maskImage, prevPt, pt, Scalar::all(255), 5, 8, 0);
		line(g_srcImage, prevPt, pt, Scalar::all(255), 5, 8, 0);
		prevPt = pt;
		imshow(WINDOW_NAME, g_srcImage);
	}
}

在这里插入图片描述

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

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

相关文章

Ai_drive _103_重新思考图像融合策略和自监督对比学习

近先进的无监督学习方法使用类似连体的框架来比较来自同一图像的两个“视图”以进行学习表示。使这两种观点与众不同的是保证无监督方法可以学习有意义信息核心。但是&#xff0c;如果用于生成两个视图的增强不够强&#xff0c;则此类框架有时会在过度拟合方面变得脆弱&#xf…

VL53L5CX驱动开发(4)----运动指示器

VL53L5CX驱动开发----4.运动指示器 概述视频教学样品申请源码下载生成STM32CUBEMX选择MCU串口配置IIC配置 INT设置配置使能与复位X-CUBE-TOF1串口重定向代码配置检测流程TOF代码配置主程序演示结果 概述 VL53L5CX传感器内置了一个固件功能&#xff0c;可以检测场景中的运动。这…

【算法|动态规划No.21】leetcode494. 目标和

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

Redis的五大基础数据类型

String 字符串类型&#xff0c;通过set关键字和get关键字来设置字符串键值对和获取字符串键值对。 hash 哈希类型&#xff0c;结构和Map<String,Map<String,stirng>>类似。 使用hset来设置哈希&#xff0c;使用hget来获取哈希&#xff0c;hget要精确到第二个key…

【深度学习 | Transformer】释放注意力的力量:探索深度学习中的 变形金刚,一文带你读通各个模块 —— Positional Encoding(一)

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

Python深度学习实践代码实现

线性模型 课程 代码 import numpy as np import matplotlib.pyplot as plt x_data[1.0,2.0,3.0] y_data[2.0,4.0,6.0] #前馈函数 def forward(x):return x*w #损失函数 def loss(x,y):y_predforward(x)return (y_pred-y)*(y_pred-y) w_list[] mse_list[] for w in np.arange…

2.Javaweb模块基本

1.1web基本 session 和 cookie 有什么区别&#xff1f; 存储位置不同&#xff1a;session 存储在服务器端&#xff1b;cookie 存储在浏览器端。 安全性不同&#xff1a;cookie 安全性一般&#xff0c;在浏览器存储&#xff0c;可以被伪造和修改。 容量和个数限制&#xff1a;…

浅讲make/makefile【linux】

浅讲make/makefile【linux】 一. 什么是make/makefile&#xff1f;二. makefile2.1 依赖关系与依赖方法2.2 浅用make2.2.1 make test2.2.2 clean 2.2 make一次执行多步2.3 部分修饰符号2.3.1 .PHONY(伪目标)2.3.2 2.3.3 $ $^ 一. 什么是make/makefile&#xff1f; make/makefi…

uml知识点学习

https://zhuanlan.zhihu.com/p/659911315https://zhuanlan.zhihu.com/p/659911315软件工程分析设计图库目录 - 知乎一、结构化绘图1. 结构化——数据流图Chilan Yuk&#xff1a;1. 结构化——数据流图2. 结构化——数据字典Chilan Yuk&#xff1a;2. 结构化——数据字典3. 结构…

“理解梯度下降:直觉、数学公式和推导”

一、说明 梯度下降是机器学习中使用的一种流行的优化算法&#xff0c;通过迭代调整函数的参数来最小化函数。基本思想是将函数的参数沿函数梯度最陡峭下降的方向移动。 二、关于梯度的叙述 简单来说&#xff0c;想象一下你在山顶&#xff0c;你想尽快到达山脚下。你可以开始下坡…

流程图规范

文章目录 1.符号概览2.要求2.1 从上至下&#xff0c;从左至右的流向顺序2.2 开始符号只能有一个出口2.3 进程符号不做逻辑校验2.4 相同流程图&#xff0c;符号大小应为一致2.5 引用流程&#xff0c;而不是重复绘制2.6 路径符号应尽量避免相互交叉2.7 同一路径&#xff0c;箭头只…

【Python】Python语言基础(下)

目录 第十一章 控制结构 for语句 if语句 while语句 第十二章 函数 函数介绍 函数的定义 函数的调用 函数的传参 函数的传参方式 位置实参 关键字实参 默认值实参 函数的返回值 函数传递未知数量的实参 函数的模块调用 调用整个模块 调用模块中特定功能 第十…

业财融合潮流下,构建国有企业全面预算管理体系

近年来&#xff0c;在我国快速发展的变革过程中&#xff0c;国有企业改革的持续深入需要积极结合市场环境和自身发展需求&#xff0c;然而其传统的财务管理模式难以适应企业提出的新要求&#xff0c;预算管理与经营销售之间不断出现隔阂。为确保全面预算管理在国有企业内部的良…

部署个人静态网站到阿里云服务器(含域名解析)

使用前提&#xff1a; 您目前已经有一个静态网站&#xff0c;可以在本地通过html进行访问。 1、购买阿里云服务器 该步骤最详细的教程来自官方文档 具体到从注册开始每一个鼠标点击都有图片介绍。 你可以按照他的步骤完成整个部署过程&#xff0c;当然可以自己选择服务器的…

【实用调试技巧】总是找不到Bug?手把手教你在vs2022中调试程序

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:程序调试及报错解决 ⚙️操作环境:Visual Studio 2022 目录 什么是Bug? 1947年9月9日:第一个"Bug"被发现 什么是调试? 调试是什么? 调试的基本步骤 Debug和Relese的区别 1.调试的区别 2.文件大小的…

13 | 如何正确使用 @Entity 里面的回调方法

Java Persistence API 里面规定的回调方法有哪些&#xff1f; JPA 协议里面规定&#xff0c;可以通过一些注解&#xff0c;为其监听回调事件、指定回调方法。下面我整理了一个回调事件注解表&#xff0c;分别列举了 PrePersist、PostPersist、PreRemove、PostRemove、PreUpdat…

线性排序:如何根据年龄给100万用户数据排序?

文章来源于极客时间前google工程师−王争专栏。 桶排序、计数排序、基数排序时间复杂度是O(n)&#xff0c;所以这类排序算法叫作线性排序。 线性的原因&#xff1a;三个算法是非基于比较的排序算法&#xff0c;都不涉及元素之间的比较操作。 三种排序对排序的数据要求苛刻&am…

19 | 如何搞清楚事务、连接池的关系?正确配置是怎样的

事务的基本原理 在学习 Spring 的事务之前&#xff0c;你首先要了解数据库的事务原理&#xff0c;我们以 MySQL 5.7 为例&#xff0c;讲解一下数据库事务的基础知识。 我们都知道 当 MySQL 使用 InnoDB 数据库引擎的时候&#xff0c;数据库是对事务有支持的。而事务最主要的作…

(转)富文本编辑器——Vue2Editor

介绍 Vue2Editor是一个简单易用且功能强大的Vue版本的富文本编辑器&#xff0c;其基于Quill.js和Vuejs构建&#xff01; 简单易用、功能强大的富文本编辑器——Vue2Editor Github https://github.com/davidroyer/vue2-editor 特性 简单易用&#xff1b;基于Vue.js & Quil…

【Golang】Go的并发和并行性解释。谁说Go不是并行语言?

偶然发现百度上有很多"师出同门"的"go是并发语言&#xff0c;而不是并行语言"的说法。让我顿感奇怪&#xff0c;"并行"说白了就是对CPU多核的利用&#xff0c;这年头不能利用多核的编译语言还有的混&#xff1f;而且还混的这么好&#xff1f;并且…