文章目录

  • 1 原理
  • 2 算法改进
  • 3 API
  • 4 实例

1 原理

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


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

  • 把梯度图像中的像素按照灰度值进行分类,设定一个测地距离阈值(测地线距离(Geodesic Distance):地球表面两点之间的最短路径的距离)。
  • 找到灰度值最小的像素点,让 thresholdthresholdthreshold 从最小值开始增长,这些点为起始点。
  • 水平面在增长的过程中,会碰到周围的邻域像素,测量这些像素到起始点(灰度值最低点)的测地距离,如果小于设定阈值,则将这些像素淹没,否则在这些像素上设置大坝,这样就对这些邻域像素进行了分类。
  • 随着水平面越来越高,会设置更多更高的大坝,直到灰度值的最大值,所有区域都在分水岭线上相遇,这些大坝就对整个图像像素的进行了分区。

2 算法改进

  基于梯度图像的直接分水岭算法容易导致图像的过分割,产生这一现象的原因主要是由于输入的图像存在过多的极小区域而产生许多小的集水盆地,从而导致分割后的图像不能将图像中有意义的区域表示出来。


在 OpenCvOpenCvOpenCv 中算法不从最小值开始增长,可以将相对较高的灰度值像素作为起始点(需要用户手动标记),从标记处开始进行淹没,则很多小区域都会被合并为一个区域,这被称为基于图像标(mark)的分水岭算法。其中标记的每个点就相当于分水岭中的注水点,从这些点开始注水使得水平面上升。手动标记太麻烦,我们可是使用距离转换(cv2.distanceTransform函数)的方法进行标记。cv2.distanceTransform计算的是图像内非零值像素点到最近的零值像素点的距离,即计算二值图像中所有像素点距离其最近的值为 0 的像素点的距离。当然,如果像素点本身的值为 0,则这个距离也为 0。

3 API

cv2.watershed( InputArray image, InputOutputArray markers )
  • 第一个参数 imageimageimage,必须是一个8bit 3通道彩色图像矩阵序列。
  • 关键是第二个参数 markers:在执行分水岭函数watershed之前,必须对第二个参数 markersmarkersmarkers 进行处理,它应该包含不同区域的轮廓,每个轮廓有一个自己唯一的编号,轮廓的定位可以通过 OpencvOpencvOpencv 中 connectedComponents 方法实现,这个是执行分水岭之前的要求。

算法会根据markers传入的轮廓作为种子(也就是所谓的注水点),对图像上其他的像素点根据分水岭算法规则进行判断,并对每个像素点的区域归属进行划定,直到处理完图像上所有像素点。而区域与区域之间的分界处的值被置为“-1”,以做区分。

4 实例

目标是将下图中的硬币和背景分离:


在编程之前为了更好理解过程,要先介绍几个概念。

  • 背景:不感兴趣的区域,越远离目标图像中心的区域就越是背景
  • 前景:感兴趣的区域,越靠近目标图像中心就越是前景
  • 未知区域:即不确定区域,边界所在的区域

流程图:


代码:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as pltdef test_watershed() :image = cv.imread('images/coins.jpg')image_gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)#基于直方图的二值化处理_, thresh = cv.threshold(image_gray, 0, 255, cv.THRESH_BINARY_INV + cv.THRESH_OTSU)#做开操作,是为了除去白噪声kernel = np.ones((3, 3), dtype = np.uint8)opening = cv.morphologyEx(thresh, cv.MORPH_OPEN, kernel, iterations = 2)#做膨胀操作,是为了让前景漫延到背景,让确定的背景出现sure_bg = cv.dilate(opening, kernel, iterations = 2)#为了求得确定的前景,也就是注水处使用距离的方法转化dist_transform = cv.distanceTransform(opening, cv.DIST_L2, 5)#归一化所求的距离转换,转化范围是[0, 1]cv.normalize(dist_transform, dist_transform, 0, 1.0, cv.NORM_MINMAX)#再次做二值化,得到确定的前景_, sure_fg = cv.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)sure_fg = np.uint8(sure_fg)#得到不确定区域也就是边界所在区域,用确定的背景图减去确定的前景图unknow = cv.subtract(sure_bg, sure_fg)#给确定的注水位置进行标上标签,背景图标为0,其他的区域由1开始按顺序进行标_, markers = cv.connectedComponents(sure_fg)# cv.imshow('markers', markers.astype(np.uint8))# cv.waitKey(0)#让标签加1,这是因为在分水岭算法中,会将标签为0的区域当作边界区域(不确定区域)markers += 1#是上面所求的不确定区域标上0markers[unknow == 255] = 0# print(markers.dtype)  int32markers_copy = markers.copy()# 使用分水岭算法执行基于标记的图像分割,将图像中的对象与背景分离markers = cv.watershed(image, markers)#分水岭算法得到的边界点的像素值为-1image[markers == -1] = [0, 0, 255]images = [thresh, opening, sure_bg, dist_transform, sure_fg, unknow, markers_copy, image]titles = ['thresh', 'opening', 'sure_bg', 'dist_tranform', 'sure_fg', 'unknow', 'markers', 'image']plt.figure(figsize = (8, 6.1))for i in range(len(images)) :if i == 7 :plt.subplot(2, 4, i + 1)plt.imshow(cv.cvtColor(images[i], cv.COLOR_BGR2RGB))plt.title(titles[i])plt.axis('off')else :plt.subplot(2, 4, i + 1)plt.imshow(images[i], cmap = 'gray')plt.title(titles[i])plt.axis('off')plt.tight_layout()plt.savefig('figure.png')plt.show()if __name__ == '__main__':test_watershed()

效果:

从上面看来效果还是蛮好的。

【OpenCv】图像分割——分水岭算法相关推荐

  1. opencv 图像分割-分水岭算法

    任何灰度图都恶意被看作是一个地形面,高强度表示山峰和山丘,低强度则表示山谷.开始使用不同的水来填充每个孤立的山谷(局部最小值).随着水的上升,来自不同山谷的水,开始融合.为了避免这种情况,在水合并的地 ...

  2. pythonopencv算法_python opencv之分水岭算法示例

    本文介绍了python opencv之分水岭算法示例,分享给大家,具体如下: 目标 使用分水岭算法对基于标记的图像进行分割 使用函数cv2.watershed() 原理: 灰度图像可以被看成拓扑平面, ...

  3. 使用OpenCV的分水岭算法

    <使用OpenCV的分水岭算法>   之前利用watershed想对相对前背景较为明显的图像进行图像语义分割的预打标,因为虽然前景明显,但是边缘打标也是很困难的,可以用该方法对大部分的边缘 ...

  4. 【OpenCV】- 分水岭算法

    文章目录 什么是图像分割 分水岭算法 1.实现分水岭算法:watershed()函数 2.处理流程(视频) 3.示例程序(书中) 什么是图像分割 将图像中像素根据一定的规则分为若干个cluster集合 ...

  5. opencv实现分水岭算法

    opencv实现分水岭算法 // 分水岭算法原理 // IplImage* marker_mask = 0; IplImage* markers = 0; //IplImage* img0 = 0, ...

  6. OpenCV图像分割Grabcut算法

    前言 1.OpenCV图像分割Grabcut算法主要功能是分割和抠图,就是把框着的目标抠出来,比如要分割出一个证件照的人的图像,只需要在目标外面画一个框,把目标框住,它就可以完成良好的分割. 2.算法 ...

  7. 传统图像分割——分水岭算法(watershed)

    传统图像分割--分水岭算法(watershed) 文章目录 传统图像分割--分水岭算法(watershed) 前言 一.什么是分水岭算法? 二.经典的分水岭求解算法 1.定义 2.算法流程 总结 前言 ...

  8. 基于边缘的图像分割——分水岭算法(watershed)算法分析(附opencv源码分析)

    最近需要做一个图像分割的程序,查了opencv的源代码,发现opencv里实现的图像分割一共有两个方法,watershed和mean-shift算法.这两个算法的具体实现都在segmentation. ...

  9. 【python】【openCV】分水岭算法

    脑血管医学图像颅内分割尝试--分水岭算法 code 1.2 不分割颅内直接分割 code 2.0 实验版 code 3.0 批量处理版 code 3.1 加入孔洞填充 总结 本篇博客原目的同https ...

最新文章

  1. nodejs笔记-异步编程
  2. DataTable 数据去重复
  3. [译]NeHe教程 - 你的第一个多边形
  4. 《Vim实用技巧》阅读笔记 --- 移动及跳转
  5. B-Donut Drone(循环/分块/DP)
  6. 【HDU - 6567】Cotree(树形dp,思维)
  7. 在应用开发中,网易云音乐如何兼顾质量和效益
  8. VMware vSphere Client下增加虚拟机磁盘空间的方法
  9. JMeter java.lang.OutOfMemoryError: PermGen space错误
  10. 开源美颜滤镜SDK代码解析
  11. Love To Be Loved By You
  12. 车牌识别,车辆检测,车牌检测和识别,与车相关的点点滴滴
  13. 基于Python的冬奥会领域问答机器人设计
  14. 指法练习软件ECAI使用指南
  15. “芒果数据库”————mongodb分片全集和管理
  16. 怎么选择好的便宜云虚拟主机?分享挑选便宜云虚拟主机的小技巧
  17. python 可执行文件大_python – 如何使用pyinstaller创建最小大小的可执行文件?
  18. 共同期待 经典Q版坦克大战揭开神秘面纱
  19. PIN, PIN2, PUK, PUK2
  20. 百分比,千分比,万分比,百分比或百分吕,千分率等

热门文章

  1. Pycharm 字体大小调整
  2. android 解析程序包时出现问题
  3. Python学习笔记(字符串、列表、字典)
  4. 小丁带你走进git世界一-git简单配置
  5. 听说你在做斗鱼APP?
  6. laravel5整合sendcloud邮箱服务
  7. 算法设计与分析第十三次作业
  8. 《算法设计与分析》第十三周作业
  9. 大数据如何使用OSM模型和AARRR模型搭建指标体系
  10. Python.习题六 字典与集合(上)