使用卷积窗口(python)

时间:2016-01-13 16:22:03

标签: python numpy image-processing scipy

我试图从数据集中分离沿海网格。我能够通过单独检查陆地网格的每个邻居来做到这一点,如果8个邻居中的一个是海洋网格,那么我将保存网格。这是我写的功能:

def coastalGrids(ds):
grid=~out[0,:,:].mask #out is a 3D masked array (time,lat,lon)

#At each grid where there is land, check all its 8 neighbors, 
#and if any of them are ocean, save the grid to the dataset
coastline=np.zeros(grid.shape, dtype=bool)
for i in range(1,len(lat)-1):
    for j in range(1,len(lon)-1):
        if grid[i,j]==True:
            if (grid[i+1,j+1]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i+1,j]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i+1,j-1]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i,j+1]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i,j-1]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i-1,j+1]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i-1,j]!=True):
                coastline[i,j]= grid[i,j]
            elif (grid[i-1,j-1]!=True):
                coastline[i,j]= grid[i,j]
return coastline

我想知道是否:

  1. 使用scipy的卷积窗函数有一种不那么难看的方式吗?
  2. 扩展这样的功能,有没有办法将陆地网格与海岸线的10个半径隔离?
  3. 谢谢!

2 个答案:

答案 0 :(得分:4)

使用图像形态运算符

您目前正在做的是等同于原始布尔数组与其binary erosion之间的差异。

这与morphological gradient密切相关,但定义略有不同。

无论如何,假设我们有一个非常简单的岛屿:

import numpy as np
import matplotlib.pyplot as plt

y, x = np.mgrid[-10:10:20j, -10:10:20j]
land = np.hypot(x, y) < 7

fig, ax = plt.subplots()
ax.pcolormesh(land, cmap='gray', edgecolor='gray', antialiased=True)
plt.show()

enter image description here

我们可以通过侵蚀岛屿来计算海岸线:

import scipy.ndimage
erosion = scipy.ndimage.binary_erosion(land)

enter image description here

然后看看哪里有任何差异:

coast = land != erosion

enter image description here

方形与对角线连接

默认情况下,它使用“方形”连接。换句话说,它不会将对角线视为触摸。默认结构(a.k.a。“footprint”)如下所示:

[[0, 1, 0],
 [1, 1, 1],
 [0, 1, 0]]

在你的代码中,你假设对角线正在触摸。在这种情况下,您需要“完整”连接,以及看起来像这样的结构:

[[1, 1, 1],
 [1, 1, 1],
 [1, 1, 1]]

为此,我们指定类似于:

的内容
erosion = scipy.ndimage.binary_erosion(land, structure=np.ones((3,3)))

作为一个完整的例子:

import numpy as np
import matplotlib.pyplot as plt
import scipy.ndimage

y, x = np.mgrid[-10:10:20j, -10:10:20j]
land = np.hypot(x, y) < 7

erosion = scipy.ndimage.binary_erosion(land, structure=np.ones((3,3)))
coast = land != erosion

fig, ax = plt.subplots()
ax.pcolormesh(coast, cmap='gray', edgecolor='gray', antialiased=True)
plt.show()

enter image description here

使用形态学梯度

您也可以考虑使用形态渐变算子。这是给定输入和连接足迹的二进制扩张和二进制侵蚀之间的差异。

在你的情况下,它还包括与陆地接壤的海洋像素,以及与海洋接壤的陆地像素。实际上,它会给你更厚的边框。

举个例子:

import numpy as np
import matplotlib.pyplot as plt
import scipy.ndimage

y, x = np.mgrid[-10:10:20j, -10:10:20j]
land = np.hypot(x, y) < 7

coast = scipy.ndimage.morphological_gradient(land,
                                            footprint=[[0, 1, 0],
                                                       [1, 1, 1],
                                                       [0, 1, 0]])

fig, ax = plt.subplots()
ax.pcolormesh(coast, cmap='gray', edgecolor='gray', antialiased=True)
plt.show()

enter image description here

答案 1 :(得分:1)

我不确定scipy的卷积功能,但上面的一个版本是有点terser循环位移索引:

neighbours = [(1,1), (1,0), (1,-1), (0,1),
              (0,1), (-1,1), (-1, 0), (-1,-1)]
for i in range(1,len(lat)-1):
    for j in range(1,len(lon)-1):
        if grid[i,j]==True:
            for (di, dj) in neighbours:
                if (grid[i+di,j+dj] != True:
                    coastline[i,j]= grid[i,j]
                    break