1.5.10 图像处理:scipy.ndimage

scipy中专注于专注于图像处理的模块是scipy.ndimage。

In [18]:

  1. from scipy import ndimage

图像处理程序可以根据他们进行的处理来分类。

1.5.10.1 图像的几何变换

改变原点,解析度,..

In [19]:

  1. from scipy import misc
  2. import matplotlib.pyplot as pl
  3. lena = misc.lena()
  4. shifted_lena = ndimage.shift(lena, (50, 50))
  5. shifted_lena2 = ndimage.shift(lena, (50, 50), mode='nearest')
  6. rotated_lena = ndimage.rotate(lena, 30)
  7. cropped_lena = lena[50:-50, 50:-50]
  8. zoomed_lena = ndimage.zoom(lena, 2)
  9. zoomed_lena.shape

Out[19]:

  1. (1024, 1024)

1.5.10 图像处理:scipy.ndimage - 图1

In [25]:

  1. subplot(151)
  2. pl.imshow(shifted_lena, cmap=cm.gray)
  3. axis('off')

Out[25]:

  1. (-0.5, 511.5, 511.5, -0.5)

1.5.10 图像处理:scipy.ndimage - 图2

1.5.10.2 图像滤波器

In [26]:

  1. from scipy import misc
  2. lena = misc.lena()
  3. import numpy as np
  4. noisy_lena = np.copy(lena).astype(np.float)
  5. noisy_lena += lena.std()*0.5*np.random.standard_normal(lena.shape)
  6. blurred_lena = ndimage.gaussian_filter(noisy_lena, sigma=3)
  7. median_lena = ndimage.median_filter(blurred_lena, size=5)
  8. from scipy import signal
  9. wiener_lena = signal.wiener(blurred_lena, (5,5))

1.5.10 图像处理:scipy.ndimage - 图3scipy.ndimage.filtersscipy.signal 有更多应用于图像的滤波器。

练习

比较不同过滤后图像的条形图

1.5.10.3 数学形态学

数学形态学是集合理论分支出来的一个数学理论。它刻画并转换几何结构。特别是二元的图像(黑白)可以用这种理论来转换:被转换的集合是临近非零值像素的集合。这个理论也可以被扩展到灰度值图像。 1.5.10 图像处理:scipy.ndimage - 图4

初级数学形态学操作使用结构化的元素,以便修改其他几何结构。

首先让我们生成一个结构化元素。

In [27]:

  1. el = ndimage.generate_binary_structure(2, 1)
  2. el

Out[27]:

  1. array([[False, True, False],
  2. [ True, True, True],
  3. [False, True, False]], dtype=bool)

In [28]:

  1. el.astype(np.int)

Out[28]:

  1. array([[0, 1, 0],
  2. [1, 1, 1],
  3. [0, 1, 0]])
  • 腐蚀

In [29]:

  1. a = np.zeros((7,7), dtype=np.int)
  2. a[1:6, 2:5] = 1
  3. a

Out[29]:

  1. array([[0, 0, 0, 0, 0, 0, 0],
  2. [0, 0, 1, 1, 1, 0, 0],
  3. [0, 0, 1, 1, 1, 0, 0],
  4. [0, 0, 1, 1, 1, 0, 0],
  5. [0, 0, 1, 1, 1, 0, 0],
  6. [0, 0, 1, 1, 1, 0, 0],
  7. [0, 0, 0, 0, 0, 0, 0]])

In [30]:

  1. ndimage.binary_erosion(a).astype(a.dtype)

Out[30]:

  1. array([[0, 0, 0, 0, 0, 0, 0],
  2. [0, 0, 0, 0, 0, 0, 0],
  3. [0, 0, 0, 1, 0, 0, 0],
  4. [0, 0, 0, 1, 0, 0, 0],
  5. [0, 0, 0, 1, 0, 0, 0],
  6. [0, 0, 0, 0, 0, 0, 0],
  7. [0, 0, 0, 0, 0, 0, 0]])

In [31]:

  1. #腐蚀移除了比结构小的对象
  2. ndimage.binary_erosion(a, structure=np.ones((5,5))).astype(a.dtype)

Out[31]:

  1. array([[0, 0, 0, 0, 0, 0, 0],
  2. [0, 0, 0, 0, 0, 0, 0],
  3. [0, 0, 0, 0, 0, 0, 0],
  4. [0, 0, 0, 0, 0, 0, 0],
  5. [0, 0, 0, 0, 0, 0, 0],
  6. [0, 0, 0, 0, 0, 0, 0],
  7. [0, 0, 0, 0, 0, 0, 0]])
  • 扩张

In [32]:

  1. a = np.zeros((5, 5))
  2. a[2, 2] = 1
  3. a

Out[32]:

  1. array([[ 0., 0., 0., 0., 0.],
  2. [ 0., 0., 0., 0., 0.],
  3. [ 0., 0., 1., 0., 0.],
  4. [ 0., 0., 0., 0., 0.],
  5. [ 0., 0., 0., 0., 0.]])

In [33]:

  1. ndimage.binary_dilation(a).astype(a.dtype)

Out[33]:

  1. array([[ 0., 0., 0., 0., 0.],
  2. [ 0., 0., 1., 0., 0.],
  3. [ 0., 1., 1., 1., 0.],
  4. [ 0., 0., 1., 0., 0.],
  5. [ 0., 0., 0., 0., 0.]])
  • 开启

In [34]:

  1. a = np.zeros((5,5), dtype=np.int)
  2. a[1:4, 1:4] = 1; a[4, 4] = 1
  3. a

Out[34]:

  1. array([[0, 0, 0, 0, 0],
  2. [0, 1, 1, 1, 0],
  3. [0, 1, 1, 1, 0],
  4. [0, 1, 1, 1, 0],
  5. [0, 0, 0, 0, 1]])

In [35]:

  1. # 开启移除了小对象
  2. ndimage.binary_opening(a, structure=np.ones((3,3))).astype(np.int)

Out[35]:

  1. array([[0, 0, 0, 0, 0],
  2. [0, 1, 1, 1, 0],
  3. [0, 1, 1, 1, 0],
  4. [0, 1, 1, 1, 0],
  5. [0, 0, 0, 0, 0]])

In [36]:

  1. # 开启也可以平滑拐角
  2. ndimage.binary_opening(a).astype(np.int)

Out[36]:

  1. array([[0, 0, 0, 0, 0],
  2. [0, 0, 1, 0, 0],
  3. [0, 1, 1, 1, 0],
  4. [0, 0, 1, 0, 0],
  5. [0, 0, 0, 0, 0]])
  • 闭合: ndimage.binary_closing

练习

验证一下开启相当于先腐蚀再扩张。

开启操作移除小的结构,而关闭操作填满了小洞。因此这些用来”清洗“图像。

In [37]:

  1. a = np.zeros((50, 50))
  2. a[10:-10, 10:-10] = 1
  3. a += 0.25*np.random.standard_normal(a.shape)
  4. mask = a>=0.5
  5. opened_mask = ndimage.binary_opening(mask)
  6. closed_mask = ndimage.binary_closing(opened_mask)

1.5.10 图像处理:scipy.ndimage - 图5

练习

验证一下重建的方格面积比原始方格的面积小。(如果关闭步骤在开启步骤之前则相反)。

对于灰度值图像,腐蚀(区别于扩张)相当于用感兴趣的像素周围的结构元素中的最小(区别于最大)值替换像素。

In [39]:

  1. a = np.zeros((7,7), dtype=np.int)
  2. a[1:6, 1:6] = 3
  3. a[4,4] = 2; a[2,3] = 1
  4. a

Out[39]:

  1. array([[0, 0, 0, 0, 0, 0, 0],
  2. [0, 3, 3, 3, 3, 3, 0],
  3. [0, 3, 3, 1, 3, 3, 0],
  4. [0, 3, 3, 3, 3, 3, 0],
  5. [0, 3, 3, 3, 2, 3, 0],
  6. [0, 3, 3, 3, 3, 3, 0],
  7. [0, 0, 0, 0, 0, 0, 0]])

In [40]:

  1. ndimage.grey_erosion(a, size=(3,3))

Out[40]:

  1. array([[0, 0, 0, 0, 0, 0, 0],
  2. [0, 0, 0, 0, 0, 0, 0],
  3. [0, 0, 1, 1, 1, 0, 0],
  4. [0, 0, 1, 1, 1, 0, 0],
  5. [0, 0, 3, 2, 2, 0, 0],
  6. [0, 0, 0, 0, 0, 0, 0],
  7. [0, 0, 0, 0, 0, 0, 0]])

1.5.10.4 测量图像

首先让我们生成一个漂亮的人造二维图。

In [41]:

  1. x, y = np.indices((100, 100))
  2. sig = np.sin(2*np.pi*x/50.)*np.sin(2*np.pi*y/50.)*(1+x*y/50.**2)**2
  3. mask = sig > 1

现在让我们看一下图像中对象的各种信息:

In [42]:

  1. labels, nb = ndimage.label(mask)
  2. nb

Out[42]:

  1. 8

In [43]:

  1. areas = ndimage.sum(mask, labels, xrange(1, labels.max()+1))
  2. areas

Out[43]:

  1. array([ 190., 45., 424., 278., 459., 190., 549., 424.])

In [44]:

  1. maxima = ndimage.maximum(sig, labels, xrange(1, labels.max()+1))
  2. maxima

Out[44]:

  1. array([ 1.80238238, 1.13527605, 5.51954079, 2.49611818,
  2. 6.71673619, 1.80238238, 16.76547217, 5.51954079])

In [45]:

  1. ndimage.find_objects(labels==4)

Out[45]:

  1. [(slice(30L, 48L, None), slice(30L, 48L, None))]

In [46]:

  1. sl = ndimage.find_objects(labels==4)
  2. import pylab as pl
  3. pl.imshow(sig[sl[0]])

Out[46]:

  1. <matplotlib.image.AxesImage at 0x10a861910>

1.5.10 图像处理:scipy.ndimage - 图6

1.5.10 图像处理:scipy.ndimage - 图7

高级例子请看一下总结练习图像处理应用:计数气泡和未融化的颗粒