1.5.10 图像处理:scipy.ndimage
scipy中专注于专注于图像处理的模块是scipy.ndimage。
In [18]:
from scipy import ndimage
图像处理程序可以根据他们进行的处理来分类。
1.5.10.1 图像的几何变换
改变原点,解析度,..
In [19]:
from scipy import misc
import matplotlib.pyplot as pl
lena = misc.lena()
shifted_lena = ndimage.shift(lena, (50, 50))
shifted_lena2 = ndimage.shift(lena, (50, 50), mode='nearest')
rotated_lena = ndimage.rotate(lena, 30)
cropped_lena = lena[50:-50, 50:-50]
zoomed_lena = ndimage.zoom(lena, 2)
zoomed_lena.shape
Out[19]:
(1024, 1024)
In [25]:
subplot(151)
pl.imshow(shifted_lena, cmap=cm.gray)
axis('off')
Out[25]:
(-0.5, 511.5, 511.5, -0.5)
1.5.10.2 图像滤波器
In [26]:
from scipy import misc
lena = misc.lena()
import numpy as np
noisy_lena = np.copy(lena).astype(np.float)
noisy_lena += lena.std()*0.5*np.random.standard_normal(lena.shape)
blurred_lena = ndimage.gaussian_filter(noisy_lena, sigma=3)
median_lena = ndimage.median_filter(blurred_lena, size=5)
from scipy import signal
wiener_lena = signal.wiener(blurred_lena, (5,5))
在scipy.ndimage.filters 和 scipy.signal 有更多应用于图像的滤波器。
练习
比较不同过滤后图像的条形图
1.5.10.3 数学形态学
数学形态学是集合理论分支出来的一个数学理论。它刻画并转换几何结构。特别是二元的图像(黑白)可以用这种理论来转换:被转换的集合是临近非零值像素的集合。这个理论也可以被扩展到灰度值图像。
初级数学形态学操作使用结构化的元素,以便修改其他几何结构。
首先让我们生成一个结构化元素。
In [27]:
el = ndimage.generate_binary_structure(2, 1)
el
Out[27]:
array([[False, True, False],
[ True, True, True],
[False, True, False]], dtype=bool)
In [28]:
el.astype(np.int)
Out[28]:
array([[0, 1, 0],
[1, 1, 1],
[0, 1, 0]])
- 腐蚀
In [29]:
a = np.zeros((7,7), dtype=np.int)
a[1:6, 2:5] = 1
a
Out[29]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
In [30]:
ndimage.binary_erosion(a).astype(a.dtype)
Out[30]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
In [31]:
#腐蚀移除了比结构小的对象
ndimage.binary_erosion(a, structure=np.ones((5,5))).astype(a.dtype)
Out[31]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
- 扩张
In [32]:
a = np.zeros((5, 5))
a[2, 2] = 1
a
Out[32]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
In [33]:
ndimage.binary_dilation(a).astype(a.dtype)
Out[33]:
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 1., 1., 1., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0.]])
- 开启
In [34]:
a = np.zeros((5,5), dtype=np.int)
a[1:4, 1:4] = 1; a[4, 4] = 1
a
Out[34]:
array([[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 1]])
In [35]:
# 开启移除了小对象
ndimage.binary_opening(a, structure=np.ones((3,3))).astype(np.int)
Out[35]:
array([[0, 0, 0, 0, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 1, 1, 1, 0],
[0, 0, 0, 0, 0]])
In [36]:
# 开启也可以平滑拐角
ndimage.binary_opening(a).astype(np.int)
Out[36]:
array([[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 1, 1, 1, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0]])
- 闭合:
ndimage.binary_closing
练习
验证一下开启相当于先腐蚀再扩张。
开启操作移除小的结构,而关闭操作填满了小洞。因此这些用来”清洗“图像。
In [37]:
a = np.zeros((50, 50))
a[10:-10, 10:-10] = 1
a += 0.25*np.random.standard_normal(a.shape)
mask = a>=0.5
opened_mask = ndimage.binary_opening(mask)
closed_mask = ndimage.binary_closing(opened_mask)
练习
验证一下重建的方格面积比原始方格的面积小。(如果关闭步骤在开启步骤之前则相反)。
对于灰度值图像,腐蚀(区别于扩张)相当于用感兴趣的像素周围的结构元素中的最小(区别于最大)值替换像素。
In [39]:
a = np.zeros((7,7), dtype=np.int)
a[1:6, 1:6] = 3
a[4,4] = 2; a[2,3] = 1
a
Out[39]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 3, 3, 3, 3, 3, 0],
[0, 3, 3, 1, 3, 3, 0],
[0, 3, 3, 3, 3, 3, 0],
[0, 3, 3, 3, 2, 3, 0],
[0, 3, 3, 3, 3, 3, 0],
[0, 0, 0, 0, 0, 0, 0]])
In [40]:
ndimage.grey_erosion(a, size=(3,3))
Out[40]:
array([[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 1, 1, 1, 0, 0],
[0, 0, 3, 2, 2, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0]])
1.5.10.4 测量图像
首先让我们生成一个漂亮的人造二维图。
In [41]:
x, y = np.indices((100, 100))
sig = np.sin(2*np.pi*x/50.)*np.sin(2*np.pi*y/50.)*(1+x*y/50.**2)**2
mask = sig > 1
现在让我们看一下图像中对象的各种信息:
In [42]:
labels, nb = ndimage.label(mask)
nb
Out[42]:
8
In [43]:
areas = ndimage.sum(mask, labels, xrange(1, labels.max()+1))
areas
Out[43]:
array([ 190., 45., 424., 278., 459., 190., 549., 424.])
In [44]:
maxima = ndimage.maximum(sig, labels, xrange(1, labels.max()+1))
maxima
Out[44]:
array([ 1.80238238, 1.13527605, 5.51954079, 2.49611818,
6.71673619, 1.80238238, 16.76547217, 5.51954079])
In [45]:
ndimage.find_objects(labels==4)
Out[45]:
[(slice(30L, 48L, None), slice(30L, 48L, None))]
In [46]:
sl = ndimage.find_objects(labels==4)
import pylab as pl
pl.imshow(sig[sl[0]])
Out[46]:
<matplotlib.image.AxesImage at 0x10a861910>
高级例子请看一下总结练习图像处理应用:计数气泡和未融化的颗粒