分水岭算法源代码及其分析和注释

合集下载

分水岭分割算法原理

分水岭分割算法原理

分水岭分割算法原理
嘿,朋友!今天咱就来聊聊这神奇的分水岭分割算法原理。

你知道吗,这分水岭分割算法就像是一个超级侦探,能把复杂的图像分割得清清楚楚!比如说,咱看一张有好多物体混合在一起的图片,就像一个乱糟糟的房间。

而分水岭算法呢,就是那个能把房间里的东西一一整理清楚,区分开来的厉害角色!
它是怎么做到的呢?哎呀,就好像它在图像上慢慢行走,根据不同区域的特点来划分边界。

就拿山脉来类比吧,分水岭不就是那些把水流分开的山脊嘛!这算法也是在找那些能把图像区域分开的“山脊线”呢!
想象一下,图像中的不同区域就像是不同的群体,而分水岭算法能精准地把它们区分开,这多牛啊!比如说有张照片,里面有个红苹果和一个绿梨子,那分水岭算法就能清楚地把苹果和梨子各自归为一类,从不会搞混。

咱再想想,如果没有这个算法,那我们要处理图像得多麻烦呀!那简直就像在黑暗中摸索,不知所措。

但有了它,就像是打开了一盏明灯,一下子就把路给照亮了!
这分水岭分割算法原理啊,真的是太神奇、太有用了!它让我们能更轻松地处理图像,让图像变得更清晰、更有条理。

难道你不想更深入地了解它吗?反正我觉得它真的是超级棒的!它就是图像处理领域的一颗耀眼明星啊!。

分水岭算法(完整版)

分水岭算法(完整版)
分水岭分割算法的实现 与分析
青 衣
11053413 李小泷
• 分水岭算法实现步骤:先把图片转化为灰度梯度级图像, 在图像梯度空间内逐渐增加一个灰度阈值,每当它大于一 个局部极大值时,就把当时的二值图像(只区分陆地和水 域,即大于灰度阈值和小于灰度阈值两部分)与前一个时 刻(即灰度阈值上一个值的时刻)的二值图像进行逻辑异或 (XOR)操作,从而确定出灰度局部极大值的位置 。根据所 有灰度局部极大值的位置集合就可确定分水岭。
Lrgb = label2rgb(L, 'jet', 'w', 'shuffle');%转 化为伪彩色图像 subplot(122); imshow(Lrgb)%显示伪彩色图 像 title('分水岭伪彩色图像') 青 衣
figure; imshow(I), hold on himage = imshow(Lrgb);%在原图上显示 伪彩色图像 set(himage, 'AlphaData', 0.3); title('原图像上的Lrgb处理')
imcomplement(Iobr));%形态学重建 Iobrcbr = imcomplement(Iobrcbr);%图像求反 subplot(122); imshow(Iobrcbr), %显示重建求反后的 图像 title('重建求反后的图像(Iobrcbr)')
fgm = imregionalmax(Iobrcbr);%局部极大值 figure; imshow(fgm), %显示重建后局部极大值图像 title('重建后局部极大值图像(fgm)')
此时再进行分水岭变换并显示得到的效果。

分水岭 算法

分水岭 算法

分水岭算法1. 简介分水岭算法(Watershed algorithm)是一种图像分割算法,可以将图像中的不同区域进行分离和标记。

它基于图像的灰度值和梯度信息,将图像看作一个地形地貌,并从低处向高处逐渐充满水,直到不同区域之间的水汇聚形成分割线。

该算法最初是由Belknap和Hoggan在1979年提出的,后来被广泛应用于计算机视觉领域,特别是在医学图像处理、目标检测和图像分析等方面。

2. 原理2.1 灰度变换在进行分水岭算法之前,需要对原始图像进行灰度变换。

这可以通过将彩色图像转换为灰度图像来实现。

灰度图像中的每个像素点都代表了原始彩色图像中相应位置的亮度值。

2.2 梯度计算接下来,需要计算灰度图像中每个像素点的梯度值。

梯度表示了亮度变化的速率,可以帮助我们找到不同区域之间的边界。

常用的梯度计算方法有Sobel、Prewitt和Scharr等算子。

这些算子对图像进行卷积操作,将每个像素点的梯度计算为其周围像素点的亮度差值。

2.3 标记初始化在进行分水岭算法之前,需要为每个像素点初始化一个标记值。

通常情况下,我们可以将背景区域标记为0,前景区域标记为正整数。

2.4 梯度图像处理接下来,我们将梯度图像中的每个像素点看作一个地形地貌中的一个位置,并将其灌满水。

初始时,所有像素点的水位都是0。

2.5 水汇聚从灰度最小值开始,逐渐增加水位直到灰度最大值。

在每次增加水位时,会发生以下情况: - 当前水位高于某个位置的梯度值时,该位置被认为是不同区域之间的边界。

- 如果两个不同区域之间存在连接路径,则会发生水汇聚现象。

此时需要将这两个区域合并,并更新合并后区域的标记值。

2.6 分割结果当水位达到最大值时,分割过程结束。

此时所有不同区域之间都有了明确的边界,并且每个区域都有了唯一的标记值。

3. 算法优缺点3.1 优点•分水岭算法是一种无监督学习方法,不需要依赖任何先验知识或训练数据。

•可以对图像中的任意区域进行分割,不受形状、大小和数量的限制。

分水岭算法——MATLAB

分水岭算法——MATLAB
% These operations will create flat maxima inside each object that can be located using imregionalmax.
% 有多种方法可以应用在这里来获得前景标记,这些标记必须是前景对象内部的连接斑点像素。这个例子中,将使用形态学技术“基于开的重建”和“基于闭的重建”来清理图像。
% 接下来,通过腐蚀后重建来做基于开的重建计算。
Ie = imerode(I, se);
Iobr = imreconstruct(Ie, I);
figure('units', 'normalized', 'position', [0 0 1 1]);
subplot(1, 2, 1); imshow(I, []); title('灰度图像');
% 使用MATLAB图像处理工具箱
% 注:期间用到了很多图像处理工具箱的函数,例如fspecial、imfilter、watershed、label2rgb、imopen、
% imclose、imreconstruct、imcomplement、imregionalmax、bwareaopen、graythresh和imimposemin函数等。
% The gradient is high at the borders of the objects and low (mostly) inside the objects.
% 使用Sobel边缘算子对图像进行水平和垂直方向的滤波,然后求取模值,sobel算子滤波后的图像在边界处会显示比较大的值,在没有边界处的值会很小。
figure('units', 'normalized', 'position', [0 0 1 1]);

C++中实现OpenCV图像分割与分水岭算法

C++中实现OpenCV图像分割与分水岭算法

C++中实现OpenCV图像分割与分⽔岭算法分⽔岭算法是⼀种图像区域分割法,在分割的过程中,它会把跟临近像素间的相似性作为重要的参考依据,从⽽将在空间位置上相近并且灰度值相近的像素点互相连接起来构成⼀个封闭的轮廓,封闭性是分⽔岭算法的⼀个重要特征。

API介绍void watershed( InputArray image, InputOutputArray markers );参数说明:image: 必须是⼀个8bit 3通道彩⾊图像矩阵序列markers: 在执⾏分⽔岭函数watershed之前,必须对第⼆个参数markers进⾏处理,它应该包含不同区域的轮廓,每个轮廓有⼀个⾃⼰唯⼀的编号,轮廓的定位可以通过Opencv中findContours⽅法实现,这个是执⾏分⽔岭之前的要求。

算法会根据markers传⼊的轮廓作为种⼦(也就是所谓的注⽔点),对图像上其他的像素点根据分⽔岭算法规则进⾏判断,并对每个像素点的区域归属进⾏划定,直到处理完图像上所有像素点。

⽽区域与区域之间的分界处的值被置为“-1”,以做区分。

我们将⼀个如何使⽤距离变换和分⽔岭分割相互接触的物体的例⼦。

考虑⼀下下⾯的硬币图像,这些硬币相互接触。

即使你去阈值化它,它也会互相碰触。

我们从找到硬币的⼤概估计值开始。

为此,我们可以利⽤⼤津的⼆值化。

#include<iostream>#include<opencv2\opencv.hpp>using namespace std;using namespace cv;int main() {Mat gray, thresh;Mat img = imread("coins.jpg");cvtColor(img, gray, COLOR_BGR2GRAY);threshold(gray, thresh, 0, 255, THRESH_BINARY_INV+CV_THRESH_OTSU);imshow("Otst阈值图像", thresh);waitKey(0);return 0;}阈值后的图像如下所⽰:现在需要去除图像中任何微⼩的⽩⾊噪声。

【谷速软件】matlab源码-标记分水岭分割算法

【谷速软件】matlab源码-标记分水岭分割算法

Step 1: Read in the Color Image and Convert it to Grayscale第一步:读入彩色图像,将其转化成灰度图像clc; clear all; close all;rgb = imread('pears.png');if ndims(rgb) == 3I = rgb2gray(rgb);elseI = rgb;endfigure('units', 'normalized', 'position', [0 0 1 1]);subplot(1, 2, 1); imshow(rgb); title('原图');subplot(1, 2, 2); imshow(I); title('灰度图');Step 2: Use the Gradient Magnitude as the Segmentation Function第2步:将梯度幅值作为分割函数Use the Sobel edge masks, imfilter, and some simple arithmetic to compute the gradient magnitude. The gradient is high at the borders of the objects and low (mostly) inside the objects.使用Sobel边缘算子对图像进行水平和垂直方向的滤波,然后求取模值,sobel算子滤波后的图像在边界处会显示比较大的值,在没有边界处的值会很小。

hy = fspecial('sobel');hx = hy';Iy = imfilter(double(I), hy, 'replicate');Ix = imfilter(double(I), hx, 'replicate');gradmag = sqrt(Ix.^2 + Iy.^2);figure('units', 'normalized', 'position', [0 0 1 1]);subplot(1, 2, 1); imshow(I,[]), title('灰度图像')subplot(1, 2, 2); imshow(gradmag,[]), title('梯度幅值图像')Can you segment the image by using the watershed transform directly on the gradient magnitude?可否直接对梯度幅值图像使用分水岭算法?L = watershed(gradmag);Lrgb = label2rgb(L);figure('units', 'normalized', 'position', [0 0 1 1]);subplot(1, 2, 1); imshow(gradmag,[]), title('梯度幅值图像')subplot(1, 2, 2); imshow(Lrgb); title('梯度幅值做分水岭变换')No. Without additional preprocessing such as the marker computations below, using the watershed transform directly often results in "oversegmentation."直接使用梯度模值图像进行分水岭算法得到的结果往往会存在过度分割的现象。

3种不同的分水岭分割方法以及三种方法的比较

3种不同的分水岭分割方法以及三种方法的比较

程序代码:(代码标记[code]...[/code] )clear,clc%三种方法进行分水岭分割%读入图像filename='Fig1021(a)(small-blobs).tif';f=imread(filename);Info=imfinfo(filename);if Info.BitDepth>8f=rgb2gray(f);endfigure,mesh(double(f));%显示图像,类似集水盆地%方法1:一般分水岭分割,从结果可以看出存在过分割问题b=im2bw(f,graythresh(f));%二值化,注意应保证集水盆地的值较低(为0),否则就要对b取反d=bwdist(b); %求零值到最近非零值的距离,即集水盆地到分水岭的距离l=watershed(-d); %matlab自带分水岭算法,l中的零值即为风水岭w=l==0; %取出边缘g=b&~w; %用w作为mask从二值图像中取值figuresubplot(2,3,1),imshow(f);subplot(2,3,2),imshow(b);subplot(2,3,3),imshow(d);subplot(2,3,4),imshow(l);subplot(2,3,5),imshow(w);subplot(2,3,6),imshow(g);%方法2:使用梯度的两次分水岭分割,从结果可以看出还存在过分割问题(在方法1的基础上改进)h=fspecial('sobel');%获得纵方向的sobel算子fd=double(f);g=sqrt(imfilter(fd,h,'replicate').^2+imfilter(fd,h','replicate').^2);%使用sobel算子进行梯度运算l=watershed(g);%分水岭运算wr=l==0;g2=imclose(imopen(g,ones(3,3)),ones(3,3));%进行开闭运算对图像进行平滑l2=watershed(g2);%再次进行分水岭运算wr2=l2==0;f2=f;f2(wr2)=255;figuresubplot(2,3,1),imshow(f);subplot(2,3,2),imshow(g);subplot(2,3,3),imshow(l);subplot(2,3,4),imshow(g2);subplot(2,3,5),imshow(l2);subplot(2,3,6),imshow(f2);%方法3:使用梯度加掩模的三次分水岭算法(在方法2的基础上改进)h=fspecial('sobel');%获得纵方向的sobel算子fd=double(f);g=sqrt(imfilter(fd,h,'replicate').^2+imfilter(fd,h','replicate').^2);%使用sobel算子进行梯度运算l=watershed(g);%分水岭运算wr=l==0;rm=imregionalmin(g); %计算图像的区域最小值定位,该函数仅仅是用来观察为何分水岭算法产生这么多集水盆地im=imextendedmin(f,2);%上面仅是产生最小值点,而该函数则是得到最小值附近的区域,此处的附近是相差2的区域fim=f;fim(im)=175; %将im在原图上标识出,用以观察lim=watershed(bwdist(im));%再次分水岭计算em=lim==0;g2=imimposemin(g,im|em);%在梯度图上标出im和em,im是集水盆地的中心,em是分水岭l2=watershed(g2); %第三次分水岭计算f2=f;f2(l2==0)=255; %从原图对分水岭进行观察figuresubplot(3,3,1),imshow(f);subplot(3,3,2),imshow(g);subplot(3,3,3),imshow(l);subplot(3,3,4),imshow(im);subplot(3,3,5),imshow(fim);subplot(3,3,6),imshow(lim);subplot(3,3,7),imshow(g2);subplot(3,3,8),imshow(l2)subplot(3,3,9),imshow(f2);。

分水岭分割算法-watershed工具箱

分水岭分割算法-watershed工具箱
• 过分割现象: 对微弱边缘具有良好的响应,图像中的噪 声、物体表面细微的灰度变化,都会产生过度分割的现象;
• 为消除分水岭算法产生的过度分割,通常可以采用两种处 理方法: 一是利用先验知识去除无关边缘信息。 二是修改梯度函数使得集水盆只响应想要探测的目标。
3. Matlab演示
• 代码: • clear; close all; clc; • rgb = imread('forest.png'); • • f = rgb2gray( rgb ); • figure(1); • imshow(rgb); • title('原始图像'); • • fgm = imregionalmax(f); • D = bwdist(fgm);%¼ÆËã¾àÀë • DL = watershed(D);%·ÖË®Áë±ä»» • bgm = DL == 0;%ÇóÈ¡·Ö¸î±ß½ç • f0 = f; • f0(bgm) = 255; • • figure(2); • imshow(f0); • title('»ùÓÚ¾àÀë±ä»»µÄ·ÖË®Áë·Ö¸î');
• b. 为得到图像的边缘信息,通常把梯度图像作为输入图像 进行处理。
分水岭脊线
汇水盆地
a
b
c
1. a中红色箭头指示区域为谷底,代表低亮度像素;黄色 箭头所示为山脊,代表高亮度像素;
2. b中灰色部分表示水从谷底逐渐涨高后的状态; 3. C中表示水面到达一定程度后留下的分水岭(最高点)
3. 不足
• f1 = f;
• f1(wr) = 255;

• figure(3);
• imshow(f1);
• title('»ùÓÚÌݶȵķÖË®Áë·Ö¸î');

pythonopencv之分水岭算法示例

pythonopencv之分水岭算法示例

pythonopencv之分⽔岭算法⽰例本⽂介绍了python opencv之分⽔岭算法⽰例,分享给⼤家,具体如下:⽬标1. 使⽤分⽔岭算法对基于标记的图像进⾏分割2. 使⽤函数cv2.watershed()原理:灰度图像可以被看成拓扑平⾯,灰度值⾼的区域可以看出⼭峰,灰度值低的区域可以看成是⼭⾕。

向每⼀个⼭⾕当中灌不同颜⾊的⽔。

⽔位升⾼,不同⼭⾕的⽔会汇合,为防⽌不同⼭⾕的⽔汇合,⼩在汇合处建⽴起堤坝。

然后继续灌⽔,然后再建⽴堤坝,直到⼭峰都掩模。

构建好的堤坝就是图像的分割。

此⽅法通常会得到过渡分割的结果,因为图像中的噪声以及其他因素。

为了减少此影响,opencv使⽤基于标记的分⽔岭算法,此算法要设置哪些⼭⾕中的汇合点,哪些不是。

这是⼀种交互式的图像分割算法那。

我们要给已知对象打上不同表情。

如果某个区域肯定是前景或对象,就使⽤某个颜⾊或灰度值标签标记它。

如果是背景那么使⽤其他颜⾊进⾏标记,其余不能确定的部分⽤0标记。

然后使⽤分⽔岭算法,每次灌⽔,标签会被更新,当两个不同颜⾊的标签相遇就会构建堤坝,知道所有⼭峰掩模,最后得到的边界对象值是-1。

代码:对挨在⼀起的对象进⾏分割。

使⽤Otsu's ⼆值化后的结果为要出去图像中的⽩噪声。

可以使⽤形态学运算,使⽤闭运算去除对象中的空洞。

靠近对象中⼼的区域是前景,离对象远的区域是背景,不确定的区域是边界。

⾸先提取硬币区域,使⽤腐蚀操作去掉边缘,剩下的就是硬币。

但硬币没有接触时,此⽅法有效,但是由于硬币相互接触,就要使⽤另外⼀种有效的⽅法:距离变换加上合适的阈值。

之后,要寻找不确定是否是硬币的区域。

这⾥需要膨胀操作。

膨胀操作会将对象边界延伸到背景当中。

由于边界区域被去除,现在就能知道哪些区域是前景,哪些是背景。

余下的区域不知道如何区分,那么使⽤分⽔岭算法。

这些区域通常是前景与背景的交界处。

从能否确认是否是背景的区域中减去确定是前景的区域就得到了边界。

分水岭分割算法matlab -回复

分水岭分割算法matlab -回复

分水岭分割算法matlab -回复标题:分水岭分割算法在MATLAB环境中的实现与解析一、引言分水岭分割算法是一种基于图像拓扑特性的图像分割方法,其基本思想源于地理学中的分水岭概念。

在图像处理中,我们可以将图像看作是一个地形图,每个像素的灰度值视为该点的高度,然后通过寻找局部极小值并将其作为汇水盆地,进而扩展到相邻的高地区域,形成分水岭,最终实现图像的分割。

本文将详细阐述如何在MATLAB环境中实现分水岭分割算法。

二、分水岭分割算法的基本原理分水岭分割算法主要包括以下几个步骤:1. 检测局部极小值:在图像中找到灰度值小于其所有邻域像素的点,这些点被视为分水岭的起点,即汇水盆地。

2. 扩展种子点:从每个局部极小值开始,向周围灰度值较高的区域扩张,直到遇到另一个局部极小值或者图像边缘。

3. 分割图像:当所有的局部极小值都被扩展后,图像就被分割成多个互不相连的区域,每个区域对应一个汇水盆地。

三、在MATLAB中实现分水岭分割算法以下是在MATLAB中实现分水岭分割算法的步骤:1. 导入图像:首先,我们需要导入需要进行分割的图像。

可以使用imread 函数来读取图像。

matlabimg = imread('your_image_file.jpg');2. 转换为灰度图像:如果原始图像为彩色图像,需要将其转换为灰度图像。

matlabgray_img = rgb2gray(img);3. 高斯滤波:为了消除图像中的噪声,可以对灰度图像进行高斯滤波。

matlabfiltered_img = imgaussfilt(gray_img, 2);4. 检测局部极小值:使用MATLAB的imregionalmin函数可以检测图像中的局部极小值。

matlabmarkers = imregionalmin(filtered_img);5. 扩展种子点:使用MATLAB的watershed函数进行分水岭分割。

分水岭算法(理论+opencv实现)

分水岭算法(理论+opencv实现)

分水岭算法(理论+opencv实现)
把图像用一维坐标表示,二维和三维不好画,必须用matlab了,我不会用,意思可以表述到位
第一步:找到图像的局部最低点,这个方法很多了,可以用一个内核去找,也可以一个一个比较,实现起来不难。

第二步:从最低点开始注水,水开始网上满(图像的说法就是梯度法),其中那些最低点已经被标记,不会被淹没,那些中间点是被淹没的。

第三步:找到局部最高点,就是图中3位置对应的两个点。

第四步:这样基于局部最小值,和找到的局部最大值,就可以分割图像了。

分类图
模拟结果图
是不是感觉上面的方法很好,也很简单?接着看下面的图:
利用上面的步骤,第一步找到了三个点,然后第二步开始漫水,这三个点都被记录下来了,又找到两个局部最大值。

这是我们想要的吗?
回答是否定的!其中中间那个最小值我们不需要,因为只是一个很少并且很小的噪点而已,我们不需要图像分割的那么细致。

缺陷显露出来了吧?没关系,下面我们的opencv把这个问题解决了。

模拟分类图
模拟结果图
opencv改进的分水岭算法:。

分水岭算法解析

分水岭算法解析

分水岭算法解析下载温馨提示:该文档是我店铺精心编制而成,希望大家下载以后,能够帮助大家解决实际的问题。

文档下载后可定制随意修改,请根据实际需要进行相应的调整和使用,谢谢!并且,本店铺为大家提供各种各样类型的实用资料,如教育随笔、日记赏析、句子摘抄、古诗大全、经典美文、话题作文、工作总结、词语解析、文案摘录、其他资料等等,如想了解不同资料格式和写法,敬请关注!Download tips: This document is carefully compiled by the editor. I hope that after you download them, they can help yousolve practical problems. The document can be customized and modified after downloading, please adjust and use it according to actual needs, thank you!In addition, our shop provides you with various types of practical materials, such as educational essays, diary appreciation, sentence excerpts, ancient poems, classic articles, topic composition, work summary, word parsing, copy excerpts,other materials and so on, want to know different data formats and writing methods, please pay attention!分水岭算法是一种用于图像分割的经典算法,它能够有效地将图像分成不同的区域,并且在边界清晰明确的情况下进行分割。

分水岭算法源代码及其分析和注释

分水岭算法源代码及其分析和注释

/*====================================================================函数名: Watershed功能:用标记-分水岭算法对输入图像进行分割算法实现:无输入参数说明: OriginalImage --输入图像(灰度图,0~255)SeedImage --标记图像(二值图,0-非标记,1-标记)LabelImage --输出图像(1-第一个分割区域,2-第二个分割区域,...)row --图像行数col --图像列数返回值说明:无====================================================================*/void WINAPI CDib::Watershed(unsigned char **OriginalImage, char** SeedImage, int **LabelImage, int row, int col){// using namespace std;//标记区域标识号,从1开始int Num=0;int i,j;//保存每个队列种子个数的数组vector<int*> SeedCounts;//临时种子队列queue<POINT> quetem;//保存所有标记区域种子队列的数组,里面放的是种子队列的指针vector<queue<POINT>*> vque;int* array;//指向种子队列的指针queue<POINT> *pque;POINT temp;for(i=0;i<row;i++){for(j=0;j<col;j++)LabelImage[i][j]=0;}int m,n,k=0;BOOL up,down,right,left,upleft,upright,downleft,downright;//8 directions...//预处理,提取区分每个标记区域,并初始化每个标记的种子队列//种子是指标记区域边缘的点,他们可以在水位上升时向外淹没(或者说生长)//pan's words:我的理解是梯度值较小的象素点,或者是极小灰度值的点。

python数字图像处理之骨架提取与分水岭算法

python数字图像处理之骨架提取与分水岭算法

python 数字图像处理之⾻架提取与分⽔岭算法⾻架提取与分⽔岭算法也属于形态学处理范畴,都放在morphology ⼦模块内。

⾻架提取,也叫⼆值图像细化。

这种算法能将⼀个连通区域细化成⼀个像素的宽度,⽤于特征提取和⽬标拓扑表⽰。

morphology ⼦模块提供了两个函数⽤于⾻架提取,分别是Skeletonize ()函数和medial_axis ()函数。

我们先来看Skeletonize ()函数。

格式为:skimage.morphology.skeletonize (image )输⼊和输出都是⼀幅⼆值图像。

例1:123456789101112131415161718192021222324252627282930313233343536373839404142from skimage import morphology,draw import numpy as np import matplotlib.pyplot as plt #创建⼀个⼆值图像⽤于测试image = np.zeros((400, 400)) #⽣成⽬标对象1(⽩⾊U 型)image[10:-10, 10:100] = 1image[-100:-10, 10:-10] = 1image[10:-10, -100:-10] = 1#⽣成⽬标对象2(X 型)rs, cs = draw.line(250, 150, 10, 280)for i in range(10):image[rs + i, cs] = 1rs, cs = draw.line(10, 150, 250, 280)for i in range(20):image[rs + i, cs] = 1#⽣成⽬标对象3(O 型)ir, ic = np.indices(image.shape)circle1 = (ic - 135)**2 + (ir - 150)**2 < 30**2circle2 = (ic - 135)**2 + (ir - 150)**2 < 20**2image[circle1] = 1image[circle2] = 0#实施⾻架算法skeleton =morphology.skeletonize(image) #显⽰结果fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))ax1.imshow(image, cmap=plt.cm.gray)ax1.axis('off')ax1.set_title('original', fontsize=20) ax2.imshow(skeleton, cmap=plt.cm.gray)ax2.axis('off')ax2.set_title('skeleton', fontsize=20)fig.tight_layout()plt.show()⽣成⼀幅测试图像,上⾯有三个⽬标对象,分别进⾏⾻架提取,结果如下:例2:利⽤系统⾃带的马图⽚进⾏⾻架提取1234567891011121314151617181920from skimage import morphology,data,color import matplotlib.pyplot as plt image=color.rgb2gray(data.horse())image=1-image #反相#实施⾻架算法skeleton =morphology.skeletonize(image) #显⽰结果fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(8, 4)) ax1.imshow(image, cmap=plt.cm.gray)ax1.axis('off')ax1.set_title('original', fontsize=20)ax2.imshow(skeleton, cmap=plt.cm.gray)ax2.axis('off')ax2.set_title('skeleton', fontsize=20) fig.tight_layout()plt.show()medial_axis 就是中轴的意思,利⽤中轴变换⽅法计算前景(1值)⽬标对象的宽度,格式为:skimage.morphology.medial_axis (image ,mask=None ,return_distance=False )mask: 掩模。

Opencv实现用于图像分割分水岭算法

Opencv实现用于图像分割分水岭算法

Opencv实现⽤于图像分割分⽔岭算法⽬标• 使⽤分⽔岭算法基于掩模的图像分割• 学习函数: cv2.watershed()原理 任何⼀幅灰度图像都可以被看成拓扑平⾯,灰度值⾼的区域可以被看成是⼭峰,灰度值低的区域可以被看成是⼭⾕。

我们向每⼀个⼭⾕中灌不同颜⾊的⽔,随着⽔的位的升⾼,不同⼭⾕的⽔就会相遇汇合,为了防⽌不同⼭⾕的⽔汇合,我们需要在⽔汇合的地⽅构建起堤坝。

不停的灌⽔,不停的构建堤坝直到所有的⼭峰都被⽔淹没。

我们构建好的堤坝就是对图像的分割。

这就是分⽔岭算法的背后哲理。

但是这种⽅法通常都会得到过度分割的结果,这是由噪声或者图像中其他不规律的因素造成的。

为了减少这种影响,OpenCV 采⽤了基于掩模的分⽔岭算法,在这种算法中我们要设置哪些⼭⾕点会汇合,哪些不会,这是⼀种交互式的图像分割。

我们要做的就是给我们已知的对象打上不同的标签。

如果某个区域肯定是前景或对象,就使⽤某个颜⾊(或灰度值)标签标记它。

如果某个区域肯定不是对象⽽是背景就使⽤另外⼀个颜⾊标签标记。

⽽剩下的不能确定是前景还是背景的区域就⽤ 0 标记。

这就是我们的标签。

然后实施分⽔岭算法。

每⼀次灌⽔,我们的标签就会被更新,当两个不同颜⾊的标签相遇时就构建堤坝,直到将所有⼭峰淹没,最后我们得到的边界对象(堤坝)的值为 -1。

代码 下⾯的例⼦中我们将就和距离变换和分⽔岭算法对紧挨在⼀起的对象进⾏分割。

如下图所⽰,这些硬币紧挨在⼀起。

就算你使⽤阈值操作,它们任然是紧挨着的。

我们从找到这些硬币的近似估计值开始,我们使⽤Otsu's⼆值化。

import cv2import numpy as npfrom matplotlib import pyplot as pltimg = cv2.imread('image/coins.png')gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)ret,thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)结果图: 现在我们要去除图像中的所有的⽩噪声,这就需要使⽤形态学中的开运算。

分水岭算法(WatershedAlgorithm)-拔剑齐的世界-搜狐博客

分水岭算法(WatershedAlgorithm)-拔剑齐的世界-搜狐博客

分水岭算法(WatershedAlgorithm)-拔剑齐的世界-搜狐博客所谓分水岭算法有好多种实现算法,拓扑学,形态学,浸水模拟和降水模拟等方式。

要搞懂就不容易了。

Watershed Algorithm(分水岭算法),顾名思义,就是根据分水岭的构成来考虑图像的分割。

现实中我们可以或者说可以想象有山有湖的景象,那么那一定是水绕山,山围水的情形。

而区分高山(plateaus)与水的界线,以及湖与湖之间的间隔或都是连通的关系,就是我们可爱的分水岭(watershed)。

为了得到一个相对集中的集水盆,那么让水涨到都接近周围的最高的山顶就可以了,再涨就要漏水到邻居了,而邻居,嘿嘿,水质不同诶,会混淆自我的。

那么这样的话,我们就可以用来获取边界高度大,中间灰阶小的物体区域了,它就是集水盆。

浸水法,就是先通过一个适当小的阈值得到起点,即集水盆的底;然后是向周围淹没也就是浸水的过程,直到得到分水岭。

当然如果我们要一直淹没到山顶,即是一直处理到图像灰阶最高片,那么,当中就会出现筑坝的情况,不同的集水盆在这里想相遇了,我们要洁身自爱,到这里为止,因为都碰到边界了。

不再上山。

构筑属于自己的分水岭。

在计算机图形学中,可利用灰度表征地貌高。

图像中我们可以利用灰度高与地貌高的相似性来研究图像的灰度在空间上的变化。

这是空域分析,比如还可以通过各种形式的梯度计算以得到算法的输入,进行浸水处理。

分水岭具有很强的边缘检测能力,对微弱的边缘也有较好的效果。

为会么这么说呢?为什么有很强的边缘检测能力,而又能得到相对集中的连通的集水盆?现实中很好办,我们在往凹地加水的时候,直到它涨到这一块紧凑的山岭边缘就不加了;但是如果有一条小山沟存在,那没办法,在初始阈值分割的时候,也就是山沟与集水盆有同样的极小值,而且它们之间是以这个高度一直连接的。

那没关系,我们将它连通。

在图像上呢?如何实现?看看算法,算法思想是这样的:首先准备好山和初始的水。

分水岭算法

分水岭算法
test();
waitKey(0);
return0;
}
效果图:
//寻找轮廓
findContours(maskImg, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
//轮廓为空时的处理
if(contours.empty())
continue;
//复制掩膜
Mat maskImg2(maskImg.size(), CV_32S);
dTime = (double)getTickCount() - dTime;
cout <<"\t处理时间为:"<< dTime*1000./ getTickFrequency();
//双层循坏,将分水岭图像遍历存入 watershedImg 中
Mat watershedImg(maskImg2.size(), CV_8UC3);
drawContours(drawing, vContours, i, color, 2, 8, vHierarchy, 0, Point());
}
imshow("ThreshWindow", drawing);
}
int main(){
test();
waitKey(0);
return 0;
}
效果图:
分水岭算法
1. 寻找轮廓
findContours() 函数用于在二值图像中寻找轮廓。常与 drawContours() 函数配合使用;findContours() 函数检测到图像的轮廓后,就可以用 drawContours() 函数将检测到的轮廓绘制出来。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
相关文档
最新文档