20180917【图像分水岭算法原理和代码】

原理的理解上:

       灰度图像类比成三维地势图:我们向每个山谷中灌入不同颜色的水,随着水位的升高,不同山谷的水就会相遇并且汇合,为了防止不同山谷的水汇合,我们需要在水即将汇合的部分建起堤坝。不停地灌水,就要不停的构筑堤坝,直到所有的山峰都被水淹没。这个时候,我们构筑的堤坝就是对图像的分割!

代码分析:

                                                 

先从找到硬币的近似估计开始。使用Otsy‘s二值化:

# -*- coding: utf-8 -*-
"""
Created on Sun Jan 19 12:10:49 2014
@author: duan
"""
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.imread('water_coins.jpg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)  将图像从彩色变换为灰度图像

ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

cv2.THRESH_BINARY_INV:低于该阈值的像素值,转换为255

图像阈值在P66)使用的方法是阈值处理,将灰度图变换为二值图

cv2.threshold(灰度图像,阈值,参数3,使用的不同观点阈值确定方法)

其中参数3是:当像素值高于(有时候是低于)阈值时候,应该被赋予的新的像素值

那么在断码段中,使用阈值确定方法为otsu方法(多阈值),因此要将初始的阈值设置为0。

函数的返回值里,第一个ret是最优阈值,明显在其他方法中并不需要使用这个值,thresh是结果图像。

结果图像如下:

              

现在要去掉图像中的白噪声:开运算=腐蚀+膨胀

所以我们现在知道靠近对象中心的区域肯定是前景,而远离对象中心的区域肯定是背景。如图:

              

# noise removal
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)
# Finding sure foreground area
# 距离变换的基本含义是计算一个图像中非零像素点到最近的零像素点的距离,也就是到零像素点的最短距离
# 个最常见的距离变换算法就是通过连续的腐蚀操作来实现,腐蚀操作的停止条件是所有前景像素都被完全
# 腐蚀。这样根据腐蚀的先后顺序,我们就得到各个前景像素点到前景中心??像素点的
# 距离。根据各个像素点的距离值,设置为不同的灰度值。这样就完成了二值图像的距离变换
#cv2.distanceTransform(src, distanceType, maskSize)
# 第二个参数0,1,2 分别表示CV_DIST_L1, CV_DIST_L2 , CV_DIST_C
dist_transform = cv2.distanceTransform(opening,1,5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)

有关距离变换的讲解,参考:https://blog.csdn.net/qq_18234121/article/details/82754187

得到下面经过距离变换以后的图:

                       

现在知道了那些是背景那些是硬币了。那我们就可以创建标签(一个与原图像大小相同,数据类型为in32 的数组),并标记其中的区域了。对我们已经确定分类的区域(无论是前景还是背景)使用不同的正整数标记,对我们不确定的区域使用0 标记。我们可以使用函数cv2.connectedComponents()来做这件事。它会把将背景标记为0,其他的对象使用从1 开始的正整数标记。但是,我们知道如果背景标记为0,那分水岭算法就会把它当成未知区域了。所以我们想使用不同的整数标记它们。而对不确定的区域(函数cv2.connectedComponents 输出的结果中使用unknown 定义未知区域)标记为0。

# Marker labelling
ret, markers1 = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers1+1
# Now, mark the region of unknown with zero
markers[unknown==255] = 0

结果使用JET 颜色地图表示。深蓝色区域为未知区域。肯定是硬币的区域使用不同的颜色标记。其余区域就是用浅蓝色标记的背景了。现在标签准备好了。到最后一步:实施分水岭算法了。标签图像将会被修改,边界区域的标记将变为-1.

markers3 = cv2.watershed(img,markers)
img[markers3 == -1] = [255,0,0]

结果如下。有些硬币的边界被分割的很好,也有一些硬币之间的边界分割的不好。

            

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值