图像处理之基于标记的分水岭算法(C++)

图像处理之基于标记的分水岭算法(C++)


文章目录

  • 图像处理之基于标记的分水岭算法(C++)
  • 前言
  • 一、基于标记点的分水岭算法应用
    • 1.实现步骤:
    • 2.代码实现
  • 总结


前言

传统分水岭算法存在过分割的不足,OpenCV提供了一种改进的分水岭算法,使用一系列预定义标记来引导图像分割的定义方式。使用OpenCV的分水岭算法cv::wathershed,需要输入一个标记图像,图像的像素值为32位有符号正数(CV_32S类型),每个非零像素代表一个标签。**它的原理是对图像中部分像素做标记,表明它的所属区域是已知的。分水岭算法可以根据这个初始标签确定其他像素所属的区域。**传统的基于梯度的分水岭算法和改进后基于标记的分水岭算法示意图如下图所示。
对比图
从上图可以看出,传统基于梯度的分水岭算法由于局部最小值过多造成分割后的分水岭较多。而基于标记的分水岭算法,水淹过程从预先定义好的标记图像(像素)开始,较好的克服了过度分割的不足。本质上讲,基于标记点的改进算法是利用先验知识来帮助分割的一种方法。因此,改进算法的关键在于如何获得准确的标记图像,即如何将前景物体与背景准确的标记出来。


一、基于标记点的分水岭算法应用

1.实现步骤:

  1. 封装分水岭算法
  2. 获取标记图像(在标记图中前景设置为255,背景像素设置为128,未知像素设置为0)
  3. 将原图和标记图输入分水岭算法
  4. 显示结果

2.代码实现

#include <iostream>
#include <opencv.hpp>class WatershedSegmenter {private:cv::Mat markers;		// 标记图public:/** @param const cv::Mat& markerImage 传入的标记图* @brief 将传入的标记图转换成CV_32S的标记图*/void setMarkers(const cv::Mat& markerImage) {// Convert to image of intsmarkerImage.convertTo(markers, CV_32S);}/** @param const cv::Mat& image 原图* @brief 对原图和标记图执行基于标记的分水岭分割*/cv::Mat process(const cv::Mat& image) {// Apply watershedcv::watershed(image, markers);return markers;}// Return result in the form of an image/** @brief 得到分割结果的标签*/cv::Mat getSegmentation() {cv::Mat tmp;// all segment with label higher than 255// will be assigned value 255markers.convertTo(tmp, CV_8U);return tmp;}// Return watershed in the form of an image以图像的形式返回分水岭cv::Mat getWatersheds() {cv::Mat tmp;//在变换前,把每个像素p转换为255p+255(在conertTo中实现)markers.convertTo(tmp, CV_8U, 255, 255);return tmp;}
};int main()
{// 读取图片std::string filepath = "F://work_study//algorithm_demo//watershedSeg.jpg";cv::Mat src = cv::imread(filepath);if (src.empty()){return -1;}imshow("src", src);// 高斯滤波平滑图像cv::Mat gaussImg;// 彩色图转换为灰度图cv::cvtColor(src, gaussImg, cv::COLOR_BGR2GRAY);cv::GaussianBlur(gaussImg, gaussImg,cv::Size(7,7),1.0);imshow("gaussImg", gaussImg);// 形态学梯度cv::Mat kernel = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(5, 5));cv::morphologyEx(gaussImg, gaussImg, cv::MORPH_GRADIENT,kernel);imshow("morphologyEx", gaussImg);// OTSU大津法阈值cv::threshold(gaussImg, gaussImg, 0, 255, cv::THRESH_OTSU | cv::THRESH_BINARY);imshow("threshold", gaussImg);// 形态学操作,生成确定的背景区域cv::Mat kernel_bg = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(7, 7)); 开运算(先腐蚀后膨胀)消除噪声点//cv::morphologyEx(gaussImg, gaussImg, cv::MORPH_OPEN, kernel1,cv::Point(-1,-1),2);// 生成确定的背景区域cv::Mat backgroundImg;cv::dilate(gaussImg, backgroundImg, kernel_bg);imshow("backgroundImg", backgroundImg);// 距离变换,生成确定的前景区域cv::Mat distanceImg,foregroundImg;cv::distanceTransform(gaussImg, distanceImg, cv::DIST_L1,5);double min, max;cv::minMaxLoc(distanceImg, &min, &max);cv::threshold(distanceImg, distanceImg, 0.1 * max, 255, cv::THRESH_BINARY);cv::normalize(distanceImg, foregroundImg, 0, 255, cv::NORM_MINMAX, CV_8U);imshow("foregroundImg", foregroundImg);// 去除连通域中的背景部分cv::Mat unknownImg;cv::subtract(backgroundImg, foregroundImg, unknownImg);	//待定区域,减去前景与背景的重合区域imshow("unknownImg", unknownImg);cv::Mat makers(gaussImg.size(),CV_8U,cv::Scalar(128));for (int i = 0; i < makers.rows; i++){for (int j = 0; j < makers.cols; j++){if (foregroundImg.at<uchar>(i, j) == 255){makers.at<uchar>(i, j) = 255;}else if (unknownImg.at<uchar>(i, j) == 255){makers.at<uchar>(i, j) = 0;}}}imshow("makers", makers);// 分水岭算法分割图像WatershedSegmenter seg;					// 实例化一个分水岭分割对象seg.setMarkers(makers);					// 设置算法的标记图像,使得水淹过程从这组预定义好的标记像素开始seg.process(src);						// 传入待分割的原图(要求为CV_8UC3)cv::Mat resultImg;resultImg = seg.getSegmentation();		// 将修改后的标记图makers转换为可显示的8位灰度图并返回分割结果(白色为前景,灰色为背景,0为边缘)cv::threshold(resultImg, resultImg, 250, 1, cv::THRESH_BINARY);cv::cvtColor(resultImg, resultImg, cv::COLOR_GRAY2BGR);resultImg = src.mul(resultImg);cv::cvtColor(resultImg, resultImg, cv::COLOR_BGR2GRAY);std::cout << resultImg.type() << std::endl;for(int i=0;i<resultImg.rows;i++)for (int j = 0; j < resultImg.cols; j++){if (resultImg.at<uchar>(i, j) == 0){resultImg.at<uchar>(i, j) = 255;}}imshow("resultImg", resultImg);cv::waitKey(0);return 0;}

过程图
在这里插入图片描述


总结

本文主要介绍了一种基于标记的分水岭算法的应用,关键在于如何巧妙地设计“标记图”,欢迎讨论交流。

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

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

相关文章

【C语言进阶】动态内存管理及柔性数组

动态内存的开辟在C语言中相当重要的知识 1、为什么会存在动态内存分配 内存的开辟方式&#xff1a; int a20;//在栈空间上开辟4个字节 int arr[10];//在栈空间上开辟40个字节的连续空间 这种开辟空间的方式有两个特点&#xff1a; 1、开辟的空间大小是固定的 2、数组在声明的…

二叉树创建和遍历

个人主页 &#xff1a;敲上瘾-CSDN博客二叉树介绍&#xff1a;二叉树(详解)-CSDN博客 目录 一、二叉树的创建 二、二叉树的遍历 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历 三、相关计算 1.总节点个数计算 2.叶子节点个数计算 3.深度计算 一、二叉树的创建 关于…

如何在路由器上安装代理服务:详细教程

如何在路由器上安装代理服务&#xff1a;详细教程 步骤一&#xff1a;通过漏洞进入路由器系统开启Telnet服务使用Telnet登录路由器系统查看系统信息和CPU信息步骤二&#xff1a;交叉编译MIPS程序 Go对MIPS的支持 安装TFTP Server使用BusyBox tftp传输文件在路由器系统中下载编译…

❤机器学习正则化算法的总结。耗时10个小时完成。❤

❤纯 干 货~❤ 目录 纯干货 1、L1 正则化&#xff08;Lasso 正则化&#xff09; 2、L2 正则化&#xff08;岭正则化&#xff09; 3、弹性网络正则化&#xff08;Elastic Net 正则化&#xff09; 4、Dropout 正则化&#xff08;用于神经网络&#xff09; 5、贝叶斯Rid…

海外盲盒小程序:跨文化营销的利器

在全球化的浪潮下&#xff0c;跨境电商正迎来前所未有的发展机遇。作为这一领域中的新兴力量&#xff0c;海外盲盒小程序凭借其独特的魅力和优势&#xff0c;正逐渐崭露头角&#xff0c;成为跨文化营销的利器。本文将探讨海外盲盒小程序在跨文化营销中的应用及其带来的价值。 一…

【30天精通Prometheus:一站式监控实战指南】第16天:snmp_exporter从入门到实战:安装、配置详解与生产环境搭建指南,超详细

亲爱的读者们&#x1f44b;   欢迎加入【30天精通Prometheus】专栏&#xff01;&#x1f4da; 在这里&#xff0c;我们将探索Prometheus的强大功能&#xff0c;并将其应用于实际监控中。这个专栏都将为你提供宝贵的实战经验。&#x1f680;   Prometheus是云原生和DevOps的…

ldap协议(常用于统一身份认证)与dict协议(在线词典)

文章目录 LDAPDICT LDAP LDAP&#xff08;Light Directory Access Portocol&#xff09;&#xff0c;轻量目录访问协议。 目录是一个为查询、浏览和搜索而优化的数据库&#xff0c;它成树状结构组织数据&#xff0c;类似文件目录一样。 目录数据库和关系数据库不同&#xff0c…

Docker安装极简版(三分钟搞定)

什么是Docker? Docker是一个开源的应用容器引擎&#xff0c;它允许开发者打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之间不会有任何接口。 化。容器是…

简易图像处理器的设计

1 概述 Python是一种高级、通用、解释型的编程语言&#xff0c;由Guido van Rossum于1991年创造。它被设计为易读易写的语言&#xff0c;具有简洁而清晰的语法&#xff0c;使得它成为许多领域的首选语言&#xff0c;如Web开发、科学计算、人工智能、数据分析等。结合本科阶段以…

三维地图校内导航系统解决方案

在如今的数字化时代&#xff0c;越来越多的学校开始实施智慧校园计划&#xff0c;旨在为学生和教师提供更高效、便捷的学习和教学环境。智慧校园运用互联网、大数据、人工智能等技术&#xff0c;对校园内各信息进行收集、整合、分析和应用&#xff0c;实现教学、管理、服务等多…

【matlab】绘图插入并放大/缩小子图

参考链接 代码分为两个&#xff1a;绘图代码与magnify.m 绘图代码就是普通的绘图代码&#xff0c;以下为例 %https://zhuanlan.zhihu.com/p/655767542 clc clear close all x 0:pi/100:2*pi; y1 sin(x); plot(x,y1,r-o); hold on y2sin(x)-0.05; y3sin(x)0.05; xlim([0 2*…

eclipse-向Console控制台输出信息

首先这里主要用到的是org.eclipse.ui.console这个包&#xff0c;所以现在顺道先来了解一下&#xff1a; org.eclipse.ui.console是一个可扩展的console视图插件&#xff0c;利用它可以实现各种console&#xff0c;并把它们显示出来。该插件本身就实现了一个Message Console&…

本地 Java API 访问云上 HDFS 集群的问题与解决

前言 这篇文章默认是已经在云上配置好了 Haoop 集群&#xff0c;因此本文主要是记录一些可能会出现错误的地方。 如果还不会配置 Hadoop 集群&#xff0c;那么可以参考本专栏的另一篇文章&#xff1a;云上配置 Hadoop 集群详解 另外在进行本文的学习之前也建议先看看该文章&…

边缘计算的AI小板——OrangePi AI Pro

简介 OrangePi AI Pro是一款基于Allwinner H6处理器的嵌入式AI计算设备&#xff0c;适用于物联网和边缘计算。它具有强大的性能、低功耗、多接口和小尺寸。 本文分为三个部分&#xff1a; 一、对该板进行简单的开箱介绍。 二、 将SD卡中的系统迁移到由于该板支持SD卡、SSD…

必看——怎么让网站实现HTTPS访问?

让网站实现HTTPS访问的步骤可以简化为以下几个基本步骤&#xff0c;非常适合非技术背景人士理解&#xff1a; 1. 申请SSL证书&#xff1a; - SSL证书是实现HTTPS的关键&#xff0c;它能加密网站数据&#xff0c;保证用户信息的安全。你可以从一些提供免费SSL证书的机构&#xf…

Spring boot集成mybatis

Spring boot集成mybatis maven依赖 我的spring boot版本是2.5.0&#xff0c;集成mybatis&#xff0c;首先需要数据库的支持&#xff0c;这里我选择mysql数据库&#xff0c;版本是8.0.11&#xff0c;然后使用druid连接池&#xff0c;其次就需要加上mybatis的依赖。 <!--mys…

[ue5]建模场景学习笔记(2)——用vectornoise降低重复率

1.问题分析&#xff1a; 利用改uv的方式降低重复率并不理想&#xff0c;在一定程度上的确能够达到降低重复率的效果&#xff0c;但远看仍然有较清晰的重复效果&#xff0c;尝试优化一下。 2.操作实现&#xff1a; 1.首先先看一下修改后的效果&#xff1a; 这是未修改前&#…

【Web API DOM02】如何获取、操作DOM元素

一&#xff1a;获取DOM元素 1 根据CSS选择器获取 语法格式如下&#xff1a; &#xff08;1&#xff09;选中一个DOM元素 document.querySeletor(CSS选择器) <ul><li>1</li><li>2</li><li>3</li> </ul> document.querySel…

Github上一款开源、简洁、强大的任务管理工具:Condution

Condution 是一款开源任务管理工具&#xff0c;它以简洁易用、功能强大著称。它旨在为用户提供一个简单高效的平台&#xff0c;帮助他们管理日常任务、提高工作效率。 1. Condution 的诞生背景 现如今&#xff0c;市面上存在着许多任务管理软件&#xff0c;但它们往往价格昂贵…

如何不用口吐莲花,照样成为社交达人

一、教程描述 每个人的一生&#xff0c;70%的时候都在沟通&#xff0c;与老板沟通、与家人沟通、与朋友沟通、与陌生人沟通&#xff0c;等等&#xff0c;但是你真的会沟通么&#xff1f;不论是工作上跟上司、同事和客户间的沟通&#xff0c;还是生活中与家人、朋友、伴侣间的沟…