OpenCV学习(二十) :分水岭算法:watershed()

OpenCV学习(二十) :分水岭算法:watershed()

参考博客:
OpenCV—分水岭算法
图像处理——分水岭算法
OpenCV学习(7) 分水岭算法(1)
Opencv分水岭算法——watershed自动图像分割用法 -牧野-

分水岭算法是一种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从而将在空间位置上相近并且灰度值相近(求梯度)的像素点互相连接起来构成一个封闭的轮廓。分水岭算法常用的操作步骤:彩色图像灰度化,然后再求梯度图,最后在梯度图的基础上进行分水岭算法,求得分段图像的边缘线。

1、watershed()函数

void watershed( 
InputArray image, 	          // 必须是一个8bit 3通道彩色图像矩阵序列
InputOutputArray markers      // markers必须包含了种子点信息:算法会根据markers传入的轮廓作为种子(也就是所谓的注水点),
//对图像上其他的像素点根据分水岭算法规则进行判断,并对每个像素点的区域归属进行划定,
//直到处理完图像上所有像素点。而区域与区域之间的分界处的值被置为“-1”,以做区分。==markers==
在将图像传递给函数之前,您必须粗略地勾勒出索引为正(>0)的图像标记中的所需区域。
因此,每个区域都表示为一个或多个具有像素值1,2,3的连接组件,以此类推。
可以使用findcontours()drawcontours()从二进制掩码中检索这些标记。这些标记是未来图像区域的“种子”。
标记中的所有其他像素,如果它们与轮廓区域的关系未知,应该由算法定义,则应该设置为0。
在函数输出中,标记中的每个像素被设置为“seed”组件的值,或者在区域之间的边界处设置为-1); 

2、示例一:手动添加 markers

watershed图像自动分割的实现步骤:
1)图像灰度化、滤波、Canny边缘检测
2)查找轮廓,并且把轮廓信息按照不同的编号绘制到watershed的第二个入参merkers上,相当于标记注水点。
3)watershed分水岭运算
4)绘制分割出来的区域,视觉控还可以使用随机颜色填充,或者跟原始图像融合以下,以得到更好的显示效果。

#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;#define WINDOW_NAME1 "【程序窗口1】"        //为窗口标题定义的宏
#define WINDOW_NAME2 "【分水岭算法效果图】"        //为窗口标题定义的宏Mat g_maskImage, g_srcImage;
Point prevPt(-1, -1);int main()
{//输出一些帮助信息printf(  "\n\n\n\t欢迎来到【分水岭算法】示例程序~\n\n");printf(  "\t请先用鼠标在图片窗口中标记出大致的区域,\n\n\t然后再按键【1】或者【SPACE】启动算法。""\n\n\t按键操作说明: \n\n""\t\t键盘按键【1】或者【SPACE】- 运行的分水岭分割算法\n""\t\t键盘按键【2】- 恢复原始图片\n""\t\t键盘按键【ESC】- 退出程序\n\n\n");//【1】载入原图并显示,初始化掩膜和灰度图g_srcImage = imread("F:/C++/2. OPENCV 3.1.0/TEST/1.jpg", 1);imshow( WINDOW_NAME1, 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_NAME1, 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);elsewatershedImage.at<Vec3b>(i,j) = colorTab[index - 1];}//混合灰度图和分水岭效果图并显示最终的窗口watershedImage = watershedImage*0.5 + grayImage*0.5;imshow( WINDOW_NAME2, watershedImage );}}waitKey(0);return 0;
}

鼠标回调函数:

static void on_Mouse( int event, int x, int y, int flags, void* )
{// 1)处理鼠标不在窗口中的情况if( x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows )return;// 2)处理鼠标左键相关消息if( event == CV_EVENT_LBUTTONUP || !(flags & CV_EVENT_FLAG_LBUTTON) )prevPt = Point(-1,-1);else if( event == CV_EVENT_LBUTTONDOWN )prevPt = Point(x,y);// 3)鼠标左键按下并移动,绘制出白色线条else if( event == CV_EVENT_MOUSEMOVE && (flags & CV_EVENT_FLAG_LBUTTON) ){Point pt(x, y); // 当前坐标值if( prevPt.x < 0 )prevPt = pt;line( g_maskImage, prevPt, pt, Scalar::all(200), 5, 8, 0 );  // 掩模图line( g_srcImage, prevPt, pt, Scalar::all(200), 5, 8, 0 );      //prevPt = pt;imshow(WINDOW_NAME1, g_srcImage);}
}

结果:
在这里插入图片描述

3、示例二:自动添加 markers

int main()
{//1、载入原图并显示,初始化掩膜和灰度图Mat image = imread("F:/C++/2. OPENCV 3.1.0/TEST/1.jpg", 1);imshow("Source Image",image);// 2、灰度化,滤波,Canny边缘检测Mat imageGray;cvtColor(image,imageGray,CV_RGB2GRAY);//灰度转换GaussianBlur(imageGray,imageGray,Size(5,5),2);   //高斯滤波imshow("Gray Image",imageGray);Canny(imageGray,imageGray,80,150);imshow("Canny Image",imageGray);// 3、查找轮廓vector<vector<Point>> contours;vector<Vec4i> hierarchy;findContours(imageGray,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());Mat imageContours=Mat::zeros(image.size(),CV_8UC1);  //轮廓Mat marks(image.size(),CV_32S);   //Opencv分水岭第二个矩阵参数marks=Scalar::all(0);int index = 0;int compCount = 0;for( ; index >= 0; index = hierarchy[index][0], compCount++ ){// 4、对marks进行标记,对不同区域的轮廓进行编号,相当于设置注水点,有多少轮廓,就有多少注水点drawContours(marks, contours, index, Scalar::all(compCount+1), 1, 8, hierarchy);     // 每个轮廓的标记点不一样drawContours(imageContours,contours,index,Scalar(255),1,8,hierarchy);}//我们来看一下传入的矩阵marks里是什么东西Mat marksShow;convertScaleAbs(marks,marksShow);  // 转换前的 marker 图imshow("marksBefore",marksShow);imshow("imageContours 轮廓",imageContours);// 5、分水岭算法watershed(image,marks);// 6、我们再来看一下分水岭算法之后的矩阵marks里是什么东西Mat afterWatershed;convertScaleAbs(marks,afterWatershed);   // 转换后的 marker 图imshow("After Watershed",afterWatershed);// 7、对每一个区域进行颜色填充Mat PerspectiveImage=Mat::zeros(image.size(),CV_8UC3);for(int i=0;i<marks.rows;i++){for(int j=0;j<marks.cols;j++){int index=marks.at<int>(i,j);if(marks.at<int>(i,j)==-1){PerspectiveImage.at<Vec3b>(i,j)=Vec3b(255,255,255);}else{PerspectiveImage.at<Vec3b>(i,j) =RandomColor(index);}}}imshow("After ColorFill",PerspectiveImage);//分割并填充颜色的结果跟原始图像融合Mat wshed;addWeighted(image,0.4,PerspectiveImage,0.6,0,wshed);imshow("AddWeighted Image",wshed);waitKey(0);return 0;
}
Vec3b RandomColor(int value) //生成随机颜色函数
{value=value%255;  //生成0~255的随机数RNG rng;int aa=rng.uniform(0,value);int bb=rng.uniform(0,value);int cc=rng.uniform(0,value);return Vec3b(aa,bb,cc);
}

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

3、基于距离的分水岭算法

使用分水岭算法进行图像分割:

(一)获取灰度图像,二值化图像,进行形态学操作,消除噪点
  (二)在距离变换前加上一步操作:通过对上面形态学去噪点后的图像,进行膨胀操作,可以得到大部分都是背景的区域(原黑色不是我们需要的部分是背景)
  (三)使用距离变换distanceTransform获取确定的前景色
相关知识补充(重点)
  (四)在获取了背景区域和前景区域(其实前景区域是我们的种子,我们将从这里进行灌水,向四周涨水,但是这个需要在markers中表示)后,这两个区域中有未重合部分(注1)怎么办?首先确定这些区域(寻找种子)
   开始获取未知区域unknown(栅栏会创建在这一区域),为下一步获取种子做准备
   (五)获取了这些区域,我们可以获取种子,这是通过connectedComponents实现,获取masker标签,确定的前景区域会在其中显示为以1开始的数据,这就是我们的种子,会从这里开始漫水
  重点:
  (六)根据未知区域unknown在markers中设置栅栏,并将背景区域加入种子区域,一起漫水
  (七)根据种子开始漫水,让水漫起来找到最后的漫出点(栅栏边界),越过这个点后各个山谷中水开始合并。注意watershed会将找到的栅栏在markers中设置为-1

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

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

相关文章

numpy将ndarray数据拼接合并

np.vstack((a, b)) 假设a是[100,10]大小的ndarray数据&#xff0c;b也是[100,10]大小的ndarray数据&#xff0c;则np.vstack((a, b))会产生一个[200,10]大小的ndarray数据。

人工智能的下一个道德挑战:如何对待动物

来源&#xff1a;爱范儿去年 11 月份&#xff0c;一段关于母熊和它幼崽的视频在网络上传播开来。根据画面中显示&#xff0c;在一片被白雪覆盖的陡峭斜坡上&#xff0c;一头雌性棕熊正带着它的幼崽艰难的攀爬。虽然因为陡峭的坡度和积雪导致小熊一直在打滑&#xff0c;但最终还…

SQLite的使用(二):数据增删改查

SQLiteDatabase 用来管理SQLite数据库的类。SQLiteDatabase新增、修改、删除和查询数据库数据的方法&#xff0c;还可以执行其他常见的数据库管理任务。 方法 描述 (void) execSQL(String sql) 执行一个SQL语句的方法 (long) insert(String table,String nullColumnHack,Co…

OpenCV学习(二十一) :计算图像连通分量:connectedComponents(),connectedComponentsWithStats()

OpenCV学习(二十一) &#xff1a;计算图像连通分量:connectedComponents(),connectedComponentsWithStats() 1、connectedComponents()函数 Connected Components即连通体算法用id标注图中每个连通体&#xff0c;将连通体中序号最小的顶点的id作为连通体的id。如果在图G中&am…

github上只下载部分文件

有时候我们不想在github上下载整个压缩包&#xff0c;因为压缩包可能比较大&#xff0c;而我们只想要其中的代码文件&#xff0c;也就是只想下载部分文件&#xff0c;例如下面这个网页我们只想下载后缀名为py的文件&#xff0c;这可以通过tortoisesvn来完成 https://github.co…

【机器视觉】机器视觉产业链

来源&#xff1a;产业智能官机器视觉&#xff08;Machine Vision&#xff09;指的是通过光学的装置和非接触的传感器自动的接收和处理真实物体的图像&#xff0c;以获得所需信息或控制机器人运动的装置&#xff0c;通俗的说就是应用在工业领域的视觉应用。▲机器视觉系统组成另…

OpenCV学习笔记(十七):图像修补:inpaint()

OpenCV学习笔记&#xff08;十七&#xff09;&#xff1a;图像修补&#xff1a;inpaint() inpaint()函数 使用区域邻域在图像中还原选定区域。 void inpaint( InputArray src, // 表示要修复的图像,8位三通道或三通道 InputArray inpaintMask, // 表示修复模板(掩模)&a…

plt.errorbar画误差曲线

plt.errorbar(x, y, yerrNone, xerrNone, fmt, ecolorNone, elinewidthNone, capsizeNone, capthickNone ) 功能&#xff1a;画误差曲线&#xff0c;也可以用于画置信区间/标准差/方差参数&#xff1a;x&#xff1a;横坐标的值&#xff0c;y&#xff1a;纵坐标的值&#xff0c…

oracle数据库卸载(需要完全卸载oracl才能重装)

1、 开始&#xff0d;>设置&#xff0d;>控制面板&#xff0d;>管理工具&#xff0d;>服务 停止所有Oracle服务。 2、 开始&#xff0d;>程序&#xff0d;>Oracle - OraHome81&#xff0d;>Oracle Installation Products&#xff0d;> Universal Insta…

OpenCV学习(二十) :直方图匹配、对比:calcHist(),minMaxLoc(),compareHist()

直方图匹配、对比:calcHist ,minMaxLoc,compareHist1、calcHist()函数2、归一化&#xff1a;normalize()函数3、minMaxLoc()函数4、compareHist()函数5、示例一&#xff1a;H-S彩色图像的色调、饱和度二维直方图绘制6、示例二&#xff1a;灰度值一维直方图绘制7、示例三&#x…

Intel和IBM押重注的神经模态计算,会给行业带来什么样的变化

Intel发布的Pohoiki Beach加速卡&#xff0c;含有64块Loihi芯片来源&#xff1a; 半导体行业观察上周&#xff0c;Intel发布了基于其神经模态&#xff08;neuromorphic&#xff09;计算芯片Loihi的加速卡Pohoiki Beach&#xff0c;该加速卡包含了64块Loihi芯片&#xff0c;共含…

python求散点曲线下方面积

假设y[1,2,3,4,2,3,1,4,2,3]是一条散点曲线&#xff0c;求y下方的面积&#xff1a; import numpy as npy[1,2,3,4,2,3,1,4,2,3] np.trapz(y)

sql语句变量定义和样例

变量和与常量 1.定义和使用局部变量说明&#xff1a;局部变量是用户可自定义的变量&#xff0c;它的作用范围仅在程序内部。局部变量的名称是用户自定义的&#xff0c;命名的局部变量名要符合SQL Server 2000标识符命名规则&#xff0c;必须以开头。 本实例在图书信息表中声明3…

OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()

OpenCV学习(二十二) &#xff1a;反向投影:calcHist(),minMaxLoc(),compareHist() 参考博客&#xff1a; 反向投影backproject的直观理解 opencv 反向投影 颜色直方图的计算、显示、处理、对比及反向投影 一、概述 1、官方解释&#xff1a;反向投影是一种记录给定图像中的像…

Elsevier LaTeX模板下载

https://www.elsevier.com/authors/author-schemas/latex-instructions

美国正式宣告将在月球建立永久存在基地

来源&#xff1a;凤凰新闻央视网消息&#xff1a;7月20号是人类首次载人登陆月球50周年纪念日&#xff0c;美国公布了“阿尔忒弥斯计划”的官方标志图案&#xff0c;正式宣告将在月球建立永久存在基地。美国媒体直呼&#xff0c;美国要“占领”月球了。1969年&#xff0c;美国的…

我的随笔

我叫白天涯&#xff0c;来自计科13-1班。 首次使用这个博客园发表随笔&#xff0c;请大家多多关照。 本次软件工程课我希望能好好听讲&#xff0c;认真做课堂记录&#xff0c;不会的及时问老师&#xff0c;以及跟同学沟通&#xff0c;尽管我计算机这方面不是太精通&#xff0c;…

for的穷举和迭代

for的穷举 把所有可能的情况都走一遍&#xff0c;使用if条件筛选出来满足条件的情况。 例&#xff1a; 单位给发了一张150元购物卡&#xff0c; 拿着到超市买三类洗化用品。 洗发水15元&#xff0c;香皂2元&#xff0c;牙刷5元。 求刚好花完150元&#xff0c;有多少种买法&…

一文看懂5G芯片背后的明争暗斗

来源&#xff1a;鲜枣课堂6月6日工信部正式发放5G商用牌照之后&#xff0c;国内5G网络建设的步伐大幅加快了。越来越多的城市出现了5G基站和5G信号&#xff0c;5G离我们的距离更近了。面对激动人心的5G&#xff0c;我们普通用户最关心的问题&#xff0c;当然是什么时候才能用上…

各种文件格式转换

http://www.alltoall.net/ 在线文件转换导航是一款支持200多种格式的在线转换工具&#xff0c;并且完全免费。 它支持视频格式&#xff0c;音频格式&#xff0c;图片格式&#xff0c;常见文档&#xff0c;表格格式&#xff0c;演示用文档格式&#xff0c;电子书格式&#xff…