python卷积计算_【Python】(3):numpy卷积运算识别核心斑块

之前有介绍卷积运算的内容,但是使用的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.

你可能感兴趣的:(python卷积计算)