python數位影像處理之骨架擷取與分水嶺演算法

不言
發布: 2018-04-27 10:25:41
原創
3706 人瀏覽過

這篇文章主要介紹了python數位影像處理之骨架擷取與分水嶺演算法,現在分享給大家,也為大家做個參考。一起來看看吧

骨架擷取與分水嶺演算法也屬於形態學處理範疇,都放在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(&#39;off&#39;)
ax1.set_title(&#39;original&#39;, fontsize=20)
ax2.imshow(skeleton, cmap=plt.cm.gray)
ax2.axis(&#39;off&#39;)
ax2.set_title(&#39;skeleton&#39;, fontsize=20)
fig.tight_layout()
plt.show()
登入後複製

產生一個測試影像,上面有三個目標對象,分別進行骨架擷取,結果如下:

範例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(&#39;off&#39;)
ax1.set_title(&#39;original&#39;, fontsize=20)
ax2.imshow(skeleton, cmap=plt.cm.gray)
ax2.axis(&#39;off&#39;)
ax2.set_title(&#39;skeleton&#39;, fontsize=20)
fig.tight_layout()
plt.show()
登入後複製

##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=&#39;nearest&#39;)
#用光谱色显示中轴
ax2.imshow(dist_on_skel, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax2.contour(data, [0.5], colors=&#39;w&#39;) #显示轮廓线
fig.tight_layout()
plt.show()
登入後複製

#2、分水嶺演算法

##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=&#39;nearest&#39;)
ax0.set_title("Original")
ax1.imshow(-distance, cmap=plt.cm.jet, interpolation=&#39;nearest&#39;)
ax1.set_title("Distance")
ax2.imshow(markers, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax3.set_title("Segmented")
for ax in axes:
 ax.axis(&#39;off&#39;)
fig.tight_layout()
plt.show()
登入後複製

分水嶺演算法也可以和梯度結合,來實現影像分割。一般梯度影像在邊緣有較高的像素值,而在其它地方則有較低的像素值,理想情況 下,分山嶺恰好在邊緣。因此,我們可以根據梯度來尋找分山嶺。

範例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=&#39;nearest&#39;)
ax0.set_title("Original")
ax1.imshow(gradient, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax1.set_title("Gradient")
ax2.imshow(markers, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax2.set_title("Markers")
ax3.imshow(labels, cmap=plt.cm.spectral, interpolation=&#39;nearest&#39;)
ax3.set_title("Segmented")
for ax in axes:
 ax.axis(&#39;off&#39;)
fig.tight_layout()
plt.show()
登入後複製

相關推薦:

python數位影像處理之高階形態學處理#########################

以上是python數位影像處理之骨架擷取與分水嶺演算法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板