之前有介绍卷积运算的内容,但是使用的ENVI软件进行的实现,还是不够灵活。本期文章介绍下如何使用python来实现卷积运算,并以一个特殊卷积核为例介绍景观生态学中核心斑块的识别。
1.原理
在景观生态学的边缘效应理论中,一个生境斑块的核心部分和边缘部分是有不同的性质的。核心斑块各种生态属性更加稳定,而边缘部分由于跟外界基质的交互作用更加频繁从而会更不稳定。
在景观生态学的常用软件Fragstats中, 有一个景观指数叫CONTIG可以表征这种斑块边缘复杂程度。下图是提出该指数的原始文献格网中的数字是运算后的结果,后面会说,这里不用管它。
这个指数的算法是很简单的,就是一个卷积运算。下面是算法的详细解释:
1.输入软件的是一个斑块数据,即一个二值化图像。该图像中是斑块的部分值为1,非斑块的部分值为0,也就是说每个输入的斑块无论形状怎样,对计算机来说都是一个二维数组。下面是例子:左图中黑色部分值为1,白色部分值为0。右边的矩阵由于行列数较大,中间部分省略显示了。
2.对这个数组进行卷积运算,过程示例如下:把原始图像中1的部分想成一个斑块,然后经过卷积运算后,其值发生了变化(斑块形状是不会变的,变的是栅格的值)
3.刚才的示例中,原始图像斑块是没有核心斑块的,经过这个卷积运算后值是2,5,4。那对于有核心斑块的图像,其值计算出来会是怎样的呢?答案是13,因为卷积核中9个数字的和是13。换句话说,如果通过该运算得到的结果中有13的栅格,那这些栅格就是核心斑块。这个算法就是这样识别出核心斑块的。示例:这些图形是计算后的结果,其中值为13的部分就是核心斑块部分。
4.根据文章中的公式计算斑块的CONTIG指数。本期的主题是介绍核心斑块识别的,所以这里我们就不继续计算这个指数了,公式在下方,算起来非常简单:
式中:C就是CONTIG指数,即我们要计算的结果;n是总的像元个数;m是卷积核的数字和,即13;C(i)是第i个像元的值。
5. 把值为13的部分导出成一个tif文件,就完成核心斑块的提取了~
Python实现
本脚本中主要使用的是arcpy和numpy两个库,前者用于读取地理数据并转成数组,后者用于卷积运算。算法步骤如下:
1.读取矢量斑块,将其转成栅格数据。若你的原始数据就是栅格数据,则无需此操作。代码如下:
import arcpy as ap
import numpy as np
ap.env.workspace="E:\\zhihu"
patch = 'patch.shp'
raster = 'patch.tif'
ap.PolygonToRaster_conversion(paych,"Class_Id",raster, cellsize = 10)
2.将栅格数据读成数组,并将其中非1的值转为0;
patch = ap.RasterToNumPyArray(raster)
index = np.where(patch!=1)
patch[index]=0
3.对该数组进行行列添加。因为我们使用的是一个3X3模板进行的卷积运算,在图像边缘运算时,我们得补上一个0行和0列才能让运算能够顺利进行。这里我定义了一个在数组四周增加0行0列的函数:
# 传入一个矩阵及其行数和列数,返回一个给其四周加上0行0列的新数组
def AddMatrix(matrix,row,col):
zero_row = np.zeros(col,dtype=np.int)
matrix_new = np.insert(matrix, 0, values = zero_row, axis=0)
matrix_new = np.vstack([matrix_new,zero_row])
row_new = matrix_new.shape[0]
zero_col = np.zeros((row_new ,),dtype=np.int)
matrix_new = np.insert(matrix_new,0,values = zero_col,axis=1)
matrix_new = np.column_stack((matrix_new,zero_col))
return matrix_new
4.定义卷积核,并开始进行卷积运算。使用for循环对每行每列像元进行操作:
flt = np.array([[1,2,1],
[2,1,2],
[1,2,1]])
row = patch.shape[0]
col = patch.shape[1]
patch_new = AddMatrix(patch,row,col)
patch_copy=patch[:]
for i in range(row):
for j in range(col):
if patch[i][j] == 1:
temp=np.array([[patch_new[i][j],patch_new[i][j+1],patch_new[i][j+2]],
[patch_new[i+1][j], patch_new[i+1][j+1], patch_new[i+1][j+2]],
[patch_new[i+2][j],patch_new[i+2][j+1],patch_new[i+2][j+2]]])
patch_copy[i][j] = np.sum(flt*temp)
5.对卷积运算后的矩阵进行二值化处理,不是13的部分值设为0:
index = np.where(patch_copy!=13)
patch_copy[index]=0
6.将数字矩阵转为栅格:
inRas = ap.Raster(raster)
lowerLeft = ap.Point(inRas.extent.XMin,inRas.extent.YMin)
raster2=ap.NumPyArrayToRaster(patch_copy,lowerLeft, x_cell_size=10)
raster2.save('Core.tif')红色的线是原始斑块边缘线。土黄色部分就是识别出的核心斑块。
总结
本期文章介绍了景观生态学中CONTIG指数的原理及python实现,并实现了核心斑块的提取。指的一提的是,本篇文章使用的是3X3的卷积核提取的核心斑块,而原始论文中也有给出5X5的卷积核,大家若有想去可以尝试修改下卷积核看看结果如何。这是5X5的卷积核:友情提示:如果要用5X5的卷积核,那么在给矩阵四周加0行0列的时候就应该加上两个行列而不是一个了。
完整代码如下:
def AddMatrix(matrix,row,col):
zero_row = np.zeros(col,dtype=np.int)
matrix_new = np.insert(matrix, 0, values = zero_row, axis=0)
matrix_new = np.vstack([matrix_new,zero_row])
row_new = matrix_new.shape[0]
zero_col = np.zeros((row_new ,),dtype=np.int)
matrix_new = np.insert(matrix_new,0,values = zero_col,axis=1)
matrix_new = np.column_stack((matrix_new,zero_col))
return matrix_new
def CoreArea(raster):
patch = ap.RasterToNumPyArray(raster)
index = np.where(patch!=1)
patch[index]=0
print(patch)
flt = np.array([[1,2,1],
[2,1,2],
[1,2,1]])
row = patch.shape[0]
col = patch.shape[1]
patch_new = AddMatrix(patch,row,col)
patch_copy=patch[:]
for i in range(row):
for j in range(col):
if patch[i][j] == 1:
temp=np.array([[patch_new[i][j],patch_new[i][j+1],patch_new[i][j+2]],
[patch_new[i+1][j], patch_new[i+1][j+1], patch_new[i+1][j+2]],
[patch_new[i+2][j],patch_new[i+2][j+1],patch_new[i+2][j+2]]])
patch_copy[i][j] = np.sum(flt*temp)
index = np.where(patch_copy!=13)
patch_copy[index]=0
return patch_copy
if __name__ == '__main__':
ap.env.workspace="E:\\zhihu"
patch = 'patch.shp'
raster = 'patch.tif'
ap.PolygonToRaster_conversion(patch,"Class_Id",raster, cellsize = 10)
patch_copy=CoreArea(raster)
inRas = ap.Raster(raster)
lowerLeft = ap.Point(inRas.extent.XMin,inRas.extent.YMin)
raster2=ap.NumPyArrayToRaster(patch_copy,lowerLeft, x_cell_size=10)
raster2.save('Core.tif')
参考^LaGro J. Assessing patch shape in landscape mosaics[J]. Photogrammetric Engineering and Remote Sensing, 1991, 57(3): 285-293.