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


Posted in Python onApril 27, 2018

骨架提取与分水岭算法也属于形态学处理范畴,都放在morphology子模块内。

1、骨架提取

骨架提取,也叫二值图像细化。这种算法能将一个连通区域细化成一个像素的宽度,用于特征提取和目标拓扑表示。

morphology子模块提供了两个函数用于骨架提取,分别是Skeletonize()函数和medial_axis()函数。我们先来看Skeletonize()函数。

格式为:skimage.morphology.skeletonize(image)

输入和输出都是一幅二值图像。

例1:

from 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] = 1
image[-100:-10, 10:-10] = 1
image[10:-10, -100:-10] = 1

#生成目标对象2(X型)
rs, cs = draw.line(250, 150, 10, 280)
for i in range(10):
 image[rs + i, cs] = 1
rs, 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**2
circle2 = (ic - 135)**2 + (ir - 150)**2 < 20**2
image[circle1] = 1
image[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()

生成一幅测试图像,上面有三个目标对象,分别进行骨架提取,结果如下:

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

例2:利用系统自带的马图片进行骨架提取

from 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()

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

medial_axis就是中轴的意思,利用中轴变换方法计算前景(1值)目标对象的宽度,格式为:

skimage.morphology.medial_axis(image,mask=None,return_distance=False)

mask: 掩模。默认为None, 如果给定一个掩模,则在掩模内的像素值才执行骨架算法。

return_distance: bool型值,默认为False. 如果为True, 则除了返回骨架,还将距离变换值也同时返回。这里的距离指的是中轴线上的所有点与背景点的距离。

import numpy as np
import scipy.ndimage as ndi
from skimage import morphology
import matplotlib.pyplot as plt

#编写一个函数,生成测试图像
def microstructure(l=256):
 n = 5
 x, y = np.ogrid[0:l, 0:l]
 mask = np.zeros((l, l))
 generator = np.random.RandomState(1)
 points = l * generator.rand(2, n**2)
 mask[(points[0]).astype(np.int), (points[1]).astype(np.int)] = 1
 mask = ndi.gaussian_filter(mask, sigma=l/(4.*n))
 return mask > mask.mean()

data = microstructure(l=64) #生成测试图像

#计算中轴和距离变换值
skel, distance =morphology.medial_axis(data, return_distance=True)

#中轴上的点到背景像素点的距离
dist_on_skel = distance * skel

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 4))
ax1.imshow(data, cmap=plt.cm.gray, interpolation='nearest')
#用光谱色显示中轴
ax2.imshow(dist_on_skel, cmap=plt.cm.spectral, interpolation='nearest')
ax2.contour(data, [0.5], colors='w') #显示轮廓线

fig.tight_layout()
plt.show()

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

2、分水岭算法

分水岭在地理学上就是指一个山脊,水通常会沿着山脊的两边流向不同的“汇水盆”。分水岭算法是一种用于图像分割的经典算法,是基于拓扑理论的数学形态学的分割方法。如果图像中的目标物体是连在一起的,则分割起来会更困难,分水岭算法经常用于处理这类问题,通常会取得比较好的效果。

分水岭算法可以和距离变换结合,寻找“汇水盆地”和“分水岭界限”,从而对图像进行分割。二值图像的距离变换就是每一个像素点到最近非零值像素点的距离,我们可以使用scipy包来计算距离变换。

在下面的例子中,需要将两个重叠的圆分开。我们先计算圆上的这些白色像素点到黑色背景像素点的距离变换,选出距离变换中的最大值作为初始标记点(如果是反色的话,则是取最小值),从这些标记点开始的两个汇水盆越集越大,最后相交于分山岭。从分山岭处断开,我们就得到了两个分离的圆。

例1:基于距离变换的分山岭图像分割

import numpy as np
import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage import morphology,feature

#创建两个带有重叠圆的图像
x, y = np.indices((80, 80))
x1, y1, x2, y2 = 28, 28, 44, 52
r1, r2 = 16, 20
mask_circle1 = (x - x1)**2 + (y - y1)**2 < r1**2
mask_circle2 = (x - x2)**2 + (y - y2)**2 < r2**2
image = np.logical_or(mask_circle1, mask_circle2)

#现在我们用分水岭算法分离两个圆
distance = ndi.distance_transform_edt(image) #距离变换
local_maxi =feature.peak_local_max(distance, indices=False, footprint=np.ones((3, 3)),
       labels=image) #寻找峰值
markers = ndi.label(local_maxi)[0] #初始标记点
labels =morphology.watershed(-distance, markers, mask=image) #基于距离变换的分水岭算法

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(8, 8))
axes = axes.ravel()
ax0, ax1, ax2, ax3 = axes

ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax0.set_title("Original")
ax1.imshow(-distance, cmap=plt.cm.jet, interpolation='nearest')
ax1.set_title("Distance")
ax2.imshow(markers, cmap=plt.cm.spectral, interpolation='nearest')
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.spectral, interpolation='nearest')
ax3.set_title("Segmented")

for ax in axes:
 ax.axis('off')

fig.tight_layout()
plt.show()

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

分水岭算法也可以和梯度相结合,来实现图像分割。一般梯度图像在边缘处有较高的像素值,而在其它地方则有较低的像素值,理想情况 下,分山岭恰好在边缘。因此,我们可以根据梯度来寻找分山岭。

例2:基于梯度的分水岭图像分割

import matplotlib.pyplot as plt
from scipy import ndimage as ndi
from skimage import morphology,color,data,filter

image =color.rgb2gray(data.camera())
denoised = filter.rank.median(image, morphology.disk(2)) #过滤噪声

#将梯度值低于10的作为开始标记点
markers = filter.rank.gradient(denoised, morphology.disk(5)) <10
markers = ndi.label(markers)[0]

gradient = filter.rank.gradient(denoised, morphology.disk(2)) #计算梯度
labels =morphology.watershed(gradient, markers, mask=image) #基于梯度的分水岭算法

fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(6, 6))
axes = axes.ravel()
ax0, ax1, ax2, ax3 = axes

ax0.imshow(image, cmap=plt.cm.gray, interpolation='nearest')
ax0.set_title("Original")
ax1.imshow(gradient, cmap=plt.cm.spectral, interpolation='nearest')
ax1.set_title("Gradient")
ax2.imshow(markers, cmap=plt.cm.spectral, interpolation='nearest')
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.spectral, interpolation='nearest')
ax3.set_title("Segmented")

for ax in axes:
 ax.axis('off')

fig.tight_layout()
plt.show()

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

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

Python 相关文章推荐
Python实现Kmeans聚类算法
Jun 10 Python
python实现扫描日志关键字的示例
Apr 28 Python
使用pandas的DataFrame的plot方法绘制图像的实例
May 24 Python
解决python中遇到字典里key值为None的情况,取不出来的问题
Oct 17 Python
解决Shell执行python文件,传参空格引起的问题
Oct 30 Python
python opencv将图片转为灰度图的方法示例
Jul 31 Python
Python 函数用法简单示例【定义、参数、返回值、函数嵌套】
Sep 20 Python
Python使用enumerate获取迭代元素下标
Feb 03 Python
django 链接多个数据库 并使用原生sql实现
Mar 28 Python
Python带参数的装饰器运行原理解析
Jun 09 Python
Python 防止死锁的方法
Jul 29 Python
Python基础之变量的相关知识总结
Jun 23 Python
python多线程之事件Event的使用详解
Apr 27 #Python
python线程池threadpool使用篇
Apr 27 #Python
Python实现删除时保留特定文件夹和文件的示例
Apr 27 #Python
python中yaml配置文件模块的使用详解
Apr 27 #Python
python 拷贝特定后缀名文件,并保留原始目录结构的实例
Apr 27 #Python
python中subprocess批量执行linux命令
Apr 27 #Python
python复制文件到指定目录的实例
Apr 27 #Python
You might like
YII中assets的使用示例
2014/07/31 PHP
php跨站攻击实例分析
2014/10/28 PHP
php英文单词统计器
2016/06/23 PHP
对字符串进行HTML编码和解码的JavaScript函数
2010/02/01 Javascript
jquery配合css简单实现返回顶部效果
2013/09/30 Javascript
浅析node.js中close事件
2014/11/26 Javascript
深入理解JavaScript系列(37):设计模式之享元模式详解
2015/03/04 Javascript
nodejs中使用多线程编程的方法实例
2015/03/24 NodeJs
jquery实现可横向和竖向展开的动态下滑菜单效果
2015/08/24 Javascript
jQuery实现简单的文件上传进度条效果
2020/03/26 Javascript
为jQuery-easyui的tab组件添加右键菜单功能的简单实例
2016/10/10 Javascript
js实现符合国情的日期插件详解
2017/01/19 Javascript
javascript 使用正则test( )第一次是 true,第二次是false
2017/02/22 Javascript
Web制作验证码功能实例代码
2017/06/19 Javascript
利用Ionic2 + angular4实现一个地区选择组件
2017/07/27 Javascript
vue表单绑定实现多选框和下拉列表的实例
2017/08/12 Javascript
React学习笔记之列表渲染示例详解
2017/08/22 Javascript
JavaScript面试出现频繁的一些易错点整理
2018/03/29 Javascript
详解如何解决vue开发请求数据跨域的问题(基于浏览器的配置解决)
2018/11/12 Javascript
jQuery实现左右两个列表框的内容相互移动功能示例
2019/01/27 jQuery
vue cli3.0 引入eslint 结合vscode使用
2019/05/27 Javascript
Vue2.x通用编辑组件的封装及应用详解
2019/05/28 Javascript
Vue中使用Lodop插件实现打印功能的简单方法
2019/12/19 Javascript
python 不关闭控制台的实现方法
2011/10/23 Python
Python计算回文数的方法
2015/03/11 Python
python如何实现excel数据添加到mongodb
2015/07/30 Python
用python写个自动SSH登录远程服务器的小工具(实例)
2017/06/17 Python
python使用tcp实现局域网内文件传输
2020/03/20 Python
jupyter notebook远程访问不了的问题解决方法
2021/01/11 Python
Python3利用scapy局域网实现自动多线程arp扫描功能
2021/01/21 Python
prAna官网:瑜伽、旅行和冒险服装
2019/03/10 全球购物
Shein英国:女性时尚网上商店
2019/04/10 全球购物
电影T恤、80年代T恤和80年代服装:TV Store Online
2020/01/05 全球购物
《雷鸣电闪波尔卡》教学反思
2014/02/23 职场文书
冬季安全检查方案
2014/05/23 职场文书
武夷山导游词
2015/02/03 职场文书