分水岭分割方法(Watershed Segmentation),是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭。分水岭的概念和形成可以通过模拟浸入过程来说明。在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭。

分水岭的计算过程是一个迭代标注过程。分水岭比较经典的计算方法是L. Vincent提出的。在该算法中,分水岭计算分两个步骤,一个是排序过程,一个是淹没过程。首先对每个像素的灰度级进行从低到高排序,然后在从低到高实现淹没过程中,对每一个局部极小值在h阶高度的影响域采用先进先出(FIFO)结构进行判断及标注。

分水岭变换得到的是输入图像的集水盆图像,集水盆之间的边界点,即为分水岭。显然,分水岭表示的是输入图像极大值点。因此,为得到图像的边缘信息,通常把梯度图像作为输入图像,即:

grad(f(x,y))=((f(x-1,y)-f(x+1,y))^2 + (f(x,y-1)-f(x,y+1))^2)^0.5

式中,f(x,y)表示原始图像,grad(.)表示梯度运算。

分水岭算法对微弱边缘具有良好的响应,图像中的噪声、物体表面细微的灰度变化,都会产生过度分割的现象。但同时应当看出,分水岭算法对微弱边缘具有良好的响应,是得到封闭连续边缘的保证的。另外,分水岭算法所得到的封闭的集水盆,为分析图像的区域特征提供了可能。

为消除分水岭算法产生的过度分割,通常可以采用两种处理方法,一是利用先验知识去除无关边缘信息。二是修改梯度函数使得集水盆只响应想要探测的目标。

为降低分水岭算法产生的过度分割,通常要对梯度函数进行修改,一个简单的方法是对梯度图像进行阈值处理,以消除灰度的微小变化产生的过度分割。即:

g(x,y)=max(grad(f(x,y)),gθ)

式中,gθ表示阈值。

程序可采用方法:用阈值限制梯度图像以达到消除灰度值的微小变化产生的过度分割,获得适量的区域,再对这些区域的边缘点的灰度级进行从低到高排序,然后在从低到高实现淹没的过程,梯度图像用Sobel算子计算获得。对梯度图像进行阈值处理时,选取合适的阈值对最终分割的图像有很大影响,因此阈值的选取是图像分割效果好坏的一个关键。缺点:实际图像中可能含有微弱的边缘,灰度变化的数值差别不是特别明显,选取阈值过大可能会消去这些微弱边缘。

下面用C++实现分水岭算法:

#define _USE_MATH_DEFINES

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

using namespace std;

typedef void GVVoid;

typedef bool GVBoolean;

typedef char GVChar;

typedef unsigned char GVByte;

typedef short GVInt16;

typedef unsigned short GVUInt16;

typedef int GVInt32;

typedef unsigned int GVUInt32;

typedef long long GVInt64;

typedef unsigned long long GVUInt64;

typedef float GVFloat32;

typedef double GVFloat64;

const GVBoolean GV_TRUE = true;

const GVBoolean GV_FALSE = false;

const GVByte GV_BYTE_MAX = UCHAR_MAX;

const GVInt32 GV_INT32_MAX = INT_MAX;

const GVInt32 GV_INT32_MIX = INT_MIN;

const GVInt64 GV_INT64_MAX = LLONG_MAX;

const GVInt64 GV_INT64_MIN = LLONG_MIN;

const GVFloat32 GV_FLOAT32_MAX = FLT_MAX;

const GVFloat32 GV_FLOAT32_MIN = FLT_MIN;

const GVFloat64 GV_FLOAT64_MAX = DBL_MAX;

const GVFloat64 GV_FLOAT64_MIN = DBL_MIN;

class GVPoint;

class GVPoint {

public:

GVInt32 x;

GVInt32 y;

public:

GVPoint() : x(0), y(0) { }

GVPoint(const GVPoint &obj) : x(obj.x), y(obj.y) { }

GVPoint(GVInt32 x, GVInt32 y) : x(x), y(y) { }

public:

GVBoolean operator ==(const GVPoint &right) const {

return ((x == right.x) && (y == right.y));

}

GVBoolean operator !=(const GVPoint &right) const {

return (!(x == right.x) || !(y == right.y));

}

};

/*

*

* image data;

* image width;

* image height;

* image of labeled watersheds.

*/

GVVoid gvWatershed(

const GVByte *image,

GVInt32 width,

GVInt32 height,

GVInt32 *label)

{

// Local constants

const GVInt32 WSHD = 0;

const GVInt32 INIT = -1;

const GVInt32 MASK = -2;

const GVPoint FICT_PIXEL = GVPoint(~0, ~0);

// Image statistics and sorting

GVInt32 size = width * height;

GVInt32 *image_stat = new GVInt32[GV_BYTE_MAX + 1];

GVInt32 *image_space = new GVInt32[GV_BYTE_MAX + 1];

GVPoint *image_sort = new GVPoint[size];

::memset(image_stat, 0, sizeof (GVInt32) * (GV_BYTE_MAX + 1));

::memset(image_space, 0, sizeof (GVInt32) * (GV_BYTE_MAX + 1));

::memset(image_sort, 0, sizeof (GVPoint) * size);

for (GVInt32 i = 0; !(i == size); ++i) {

image_stat[image[i]]++;

}

for (GVInt32 i = 0; !(i == GV_BYTE_MAX); ++i) {

image_stat[i + 1] += image_stat[i];

}

for (GVInt32 i = 0; !(i == height); ++i) {

for (GVInt32 j = 0; !(j == width); ++j) {

GVByte space = image[i * width + j];

GVInt32 index = image_stat[space] - (++image_space[space]);

image_sort[index].x = j;

image_sort[index].y = i;

}

}

for (GVInt32 i = GV_BYTE_MAX; !(i == 0); --i) {

image_stat[i] -= image_stat[i - 1];

}

// Watershed algorithm

GVPoint *head = image_sort;

GVInt32 space = 0;

GVInt32 *dist = new GVInt32[size];

GVInt32 dist_cnt = 0;

GVInt32 label_cnt = 0;

std::queue queue;

::memset(dist, 0, sizeof (GVInt32) * size);

::memset(label, ~0, sizeof (GVInt32) * size);

for (GVInt32 h = 0; !(h == (GV_BYTE_MAX + 1)); ++h) {

head += space;

space = image_stat[h];

for (GVInt32 i = 0; !(i == space); ++i) {

GVInt32 index = head[i].y * width + head[i].x;

GVInt32 index_l = ((head[i].x - 1) < 0) ? -1 : ((head[i].x - 1) + head[i].y * width);

GVInt32 index_r = !((head[i].x + 1) > width) ? -1 : ((head[i].x + 1) + head[i].y * width);

GVInt32 index_t = ((head[i].y - 1) < 0) ? -1 : (head[i].x + (head[i].y - 1) * width);

GVInt32 index_b = !((head[i].y + 1) > height) ? -1 : (head[i].x + (head[i].y + 1) * width);

label[index] = MASK;

if ( (!(index_l < 0) && !(label[index_l] < WSHD))

|| (!(index_r < 0) && !(label[index_r] < WSHD))

|| (!(index_t < 0) && !(label[index_t] < WSHD))

|| (!(index_b < 0) && !(label[index_b] < WSHD))) {

dist[index] = 1;

queue.push(head[i]);

}

}

dist_cnt = 1;

queue.push(FICT_PIXEL);

while (GV_TRUE) {

GVPoint top = queue.front();

GVInt32 index = top.y * width + top.x;

GVInt32 index_l = ((top.x - 1) < 0) ? -1 : ((top.x - 1) + top.y * width);

GVInt32 index_r = !((top.x + 1) > width) ? -1 : ((top.x + 1) + top.y * width);

GVInt32 index_t = ((top.y - 1) < 0) ? -1 : (top.x + (top.y - 1) * width);

GVInt32 index_b = !((top.y + 1) > height) ? -1 : (top.x + (top.y + 1) * width);

queue.pop();

if (top == FICT_PIXEL) {

if (queue.empty()) break;

else {

++dist_cnt;

queue.push(FICT_PIXEL);

top = queue.front();

queue.pop();

}

}

if (!(index_l < 0)) {

if ((dist[index_l] < dist_cnt) && !(label[index_l] < WSHD)) {

if (label[index_l] > WSHD) {

if ((label[index] == MASK) || (label[index] = WSHD)) label[index] = label[index_l];

else if (!(label[index] == label[index_l])) label[index] = WSHD;

} else if (label[index] == MASK) {

label[index] = WSHD;

}

} else if ((label[index_l] == MASK) && (dist[index_l] == 0)) {

dist[index_l] = dist_cnt + 1;

queue.push(GVPoint(top.x - 1, top.y));

}

}

if (!(index_r < 0)) {

if ((dist[index_r] < dist_cnt) && !(label[index_r] < WSHD)) {

if (label[index_r] > WSHD) {

if ((label[index] == MASK) || (label[index] = WSHD)) label[index] = label[index_r];

else if (!(label[index] == label[index_r])) label[index] = WSHD;

} else if (label[index] == MASK) {

label[index] = WSHD;

}

} else if ((label[index_r] == MASK) && (dist[index_r] == 0)) {

dist[index_r] = dist_cnt + 1;

queue.push(GVPoint(top.x + 1, top.y));

}

}

if (!(index_t < 0)) {

if ((dist[index_t] < dist_cnt) && !(label[index_t] < WSHD)) {

if (label[index_t] > WSHD) {

if ((label[index] == MASK) || (label[index] = WSHD)) label[index] = label[index_t];

else if (!(label[index] == label[index_t])) label[index] = WSHD;

} else if (label[index] == MASK) {

label[index] = WSHD;

}

} else if ((label[index_t] == MASK) && (dist[index_t] == 0)) {

dist[index_t] = dist_cnt + 1;

queue.push(GVPoint(top.x, top.y - 1));

}

}

if (!(index_b < 0)) {

if ((dist[index_b] < dist_cnt) && !(label[index_b] < WSHD)) {

if (label[index_b] > WSHD) {

if ((label[index] == MASK) || (label[index] = WSHD)) label[index] = label[index_b];

else if (!(label[index] == label[index_b])) label[index] = WSHD;

} else if (label[index] == MASK) {

label[index] = WSHD;

}

} else if ((label[index_b] == MASK) && (dist[index_b] == 0)) {

dist[index_b] = dist_cnt + 1;

queue.push(GVPoint(top.x, top.y + 1));

}

}

}

for (GVInt32 i = 0; !(i == space); ++i) {

GVInt32 index = head[i].y * width + head[i].x;

dist[index] = 0;

if (label[index] == MASK) {

label_cnt++;

label[index] = label_cnt;

queue.push(head[i]);

while (!queue.empty()) {

GVPoint top = queue.front();

GVInt32 index_l = ((top.x - 1) < 0) ? -1 : ((top.x - 1) + top.y * width);

GVInt32 index_r = !((top.x + 1) > width) ? -1 : ((top.x + 1) + top.y * width);

GVInt32 index_t = ((top.y - 1) < 0) ? -1 : (top.x + (top.y - 1) * width);

GVInt32 index_b = !((top.y + 1) > height) ? -1 : (top.x + (top.y + 1) * width);

queue.pop();

if (!(index_l < 0) && (label[index_l] == MASK)) {

queue.push(GVPoint(top.x - 1, top.y));

label[index_l] = label_cnt;

}

if (!(index_r < 0) && (label[index_r] == MASK)) {

queue.push(GVPoint(top.x + 1, top.y));

label[index_r] = label_cnt;

}

if (!(index_t < 0) && (label[index_t] == MASK)) {

queue.push(GVPoint(top.x, top.y - 1));

label[index_t] = label_cnt;

}

if (!(index_b < 0) && (label[index_b] == MASK)) {

queue.push(GVPoint(top.x, top.y + 1));

label[index_b] = label_cnt;

}

}

}

}

}

// Release resources

delete[] image_stat;

delete[] image_space;

delete[] image_sort;

delete[] dist;

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

分水岭算法java,C++实现分水岭算法(Watershed Algorithm)相关推荐

  1. Python+OpenCV:基于分水岭算法的图像分割(Image Segmentation with Watershed Algorithm)

    Python+OpenCV:基于分水岭算法的图像分割(Image Segmentation with Watershed Algorithm) ############################ ...

  2. 蚁群算法画图java_[转载]简单蚁群算法 + JAVA实现蚁群算法

    一 引言 蚁群算法(ant colony optimization,ACO),又称蚂蚁算法,是一种用来在图中寻找优化路径的机率型技术.它由Marco Dorigo于1992年在他的博士论文中引入,其灵 ...

  3. 蚁群算法java实现_简单蚁群算法 + JAVA实现蚁群算法

    一 引言 蚁群算法(ant colony optimization,ACO),又称蚂蚁算法,是一种用来在图中寻找优化路径的机率型技术.它由Marco Dorigo于1992年在他的博士论文中引入,其灵 ...

  4. l bfgs算法java代码_优化算法——拟牛顿法之L-BFGS算法

    一.BFGS算法 BFGS算法的校正公式: 利用Sherman-Morrison公式可对上式进行变换,得到 令 ,则得到: 二.BGFS算法存在的问题 在BFGS算法中.每次都要存储近似Hesse矩阵 ...

  5. 排序算法java源代码_排序算法汇总(java实现,附源代码)

    整理系统的时候发现了原来写的各种算法的总结,看了一下,大吃一惊,那时候的我还如此用心,具体的算法,有的已经模糊甚至忘记了,看的时候就把内容整理出来,顺便在熟悉一下,以后需要的时候就可以直接过来摘抄了. ...

  6. 排序算法java快速排序_快速排序算法--Java实现

    标签(空格分隔): 数据结构与算法 原理: 对于任意一个无序数组,我们随机的选一个元素作为基准元素(例如:数组中的最后一个或者第一个元素, 然后我们将数组中的剩余元素分别与基准元素进行比较,将小于或等 ...

  7. 匈牙利算法java实现_匈牙利算法(Hungarian Algorithm)

    匈牙利算法是一种在多项式时间内求解任务分配问题的组合优化算法.换句话说就是,在可以接受的时间内去做匹配. 1. 描述问题 给定2个集合A和B,然后将AB中的元素完成一个连线.(这不就是小时候的连线题么 ...

  8. adaboost算法java代码_04-04 AdaBoost算法代码(鸢尾花分类)

    [TOC] 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:https://www.cnblogs.com/nickchen121/p ...

  9. java资源分配算法,java - 资源分配与动态规划算法 - 堆栈内存溢出

    给定一组函数f1 ... fn(离散时间)和时间限制(int),应找到最大输出,即在不同函数之间分配时间以最大化所用函数输出的总和. 对于任何函数,任何时候的值表示如果用于所述时间的函数的总输出. 即 ...

最新文章

  1. 网页失去焦点事件 visibilitychange
  2. c语言中合法的字符型常量是,C语言习题库(带答案)-排版.doc
  3. 名片DIY官方认证代码_【教程】DIYQQ动态名片
  4. Linux内核网络数据包发送(三)——IP协议层分析
  5. SAP开源的持续集成-持续交付的解决方案
  6. GitHub 贡献第一的微软开源软件列表
  7. LeetCode 1456. 定长子串中元音的最大数目(滑动窗口)
  8. 【Flink】Flink SQL Cannot instantiate user function cannot assign instance LinkedMap FlinkKafkaConsum
  9. 关于进程句柄 窗口句柄的关系
  10. Uniswap 24h交易量约11亿美元涨10.66%
  11. header manipulation 漏洞_【资讯】HPE 修补了两个关键的远程可利用漏洞
  12. Eclipse调字体
  13. CVPR 2021奖项出炉:最佳论文花落马普所,何恺明获提名,首届黄煦涛纪念奖颁布
  14. 技嘉 B85-HD3 4590 OC 引导文件 基本完美
  15. icom对讲机写频线定义_ICOM对讲机的常见故障和使用中的问题
  16. N卡驱动安装闪退,安装程序无反应,重装无效,不重装系统解决方法
  17. 程序物语(八):我心戚戚
  18. 4个角度教你选小程序开发工具?
  19. PyCharm设置中文(官方插件版)
  20. 键盘没有小键盘怎么办?怎么打开屏幕软键盘?

热门文章

  1. 转:乱谈Dotnet之武林秘籍
  2. 一款仿网易云音乐的App
  3. 语义分割介绍和FCN
  4. 厉害了隔壁老王,带你入坑腾讯联机对战引擎!
  5. MySQL中主键和unique的区别
  6. 练习---打印出电影天堂中电影的下载链接
  7. 7、【WebGIS实战】专题篇——API key
  8. w 命令 和 who 命令
  9. 【php基础入门】小白整理PHP常用的字符串函数使用总结分析(推荐)
  10. vue专题之vue项目端口号修改【四】