去年由于要采用MODIS植被数据(VCC/VCF)产品MOD44B来分析我国近十二年(如:2000~2011年)的植被空间分布变化,但是,由于时间尺度是12年,空间尺度为全中国,所以数据量是及其庞大的,要采用软件的方式来处理这些数据,基本上是不可能的。所以在此就选择了利用python结合一些遥感影像处理开发包,写了一段代码,来实现上述目的。
首先,介绍下我的分析方法。为了分析近12年的植被空间分布变化,为此,我采用了基于最小二乘法的线性拟合来求算植被覆盖度在这十二年中的一个变化斜率,通过这个变化斜率来反映我国植被覆盖度的变化情况。
然后,我采用了普聚类算法,将植被覆盖度的变化分为五类(增长很大、增长较大、无变化、衰退较快、衰退很快),以此来反映植被覆盖度变化的一个空间聚集性。
以下是实现线性拟合的代码:
#coding=utf-8
import numpy as np
import os
import pyhdf.SD as hdf
import Image
import scipy as sp
import osgeo.gdal as gdal
import osgeo.osr as osr
from osgeo.gdalconst import *
import re
#定义文件输入和输出路径
path='D:/GJSF/DATA/2908'
#path='D:/GJSF/DATA/jx'
savepth='D://GJSF//DATA//TIFF'
#从影像中得到数据集
lista=os.listdir(path)
datalist=[]
for k in range(len(lista)):
strpth=path+'/'+lista[k]
dt=hdf.SD(strpth)
dataset=dt.select('Percent_Tree_Cover')
data=dataset.get()
#将所有的数据暂时存入一个列表中
datalist.append(data)
#进行数据叠加处理
dtarelist=[]
for m in range(len(datalist)):
dtarelist.append((datalist[m].reshape((1,4800,4800))))
for a in range(len(datalist)):
if a==0:
dtaz=np.concatenate([dtarelist[a],dtarelist[a+1]],axis=0)
if a>1:
dtaz=np.concatenate([dtaz,dtarelist[a]],axis=0)
#清理内存空间
del(dataset)
del(data)
del(datalist)
del(dtarelist)
#数据分割处理
#dtalist=[]
#dtalist.append(dtaz[0:11,0:2400,0:2400])
#dtalist.append(dtaz[0:11,0:2400,2400:4800])
#dtalist.append(dtaz[0:11,2400:4800,0:2400])
#dtalist.append(dtaz[0:11,2400:4800,2400:4800])
#del(dtaz)
#采用最小二乘法,实现线性拟合,并得到斜率值
#设定时间数组
Arraytime=np.array([0,1,2,3,4,5,6,7,8,9,10])
Time=np.vstack([Arraytime,np.ones(len(Arraytime))]).T
#定义结果存储数组
temparray=[]
XL=np.zeros((4800,4800),dtype=np.float)
#进行斜率值的计算
for r in range(4800):
for c in range(4800):
for k in range(11):
temparray.append(dtaz[k,r,c])
Arrayslope=np.array(temparray)
temparray=[]
m,b=np.linalg.lstsq(Time,Arrayslope)[0]
XL[r,c]=m
#将结果输出为tiff影像
driver=gdal.GetDriverByName("GTiff")
driver.Register()
print np.max(XL)
tifsavepth=savepth+'/'+'2908.tif'
outDataset = driver.Create(tifsavepth,4800,4800,1,gdal.GDT_Float32)
#定义空间参考坐标系
proj=osr.SpatialReference()
proj.ImportFromProj4("+proj=sinu +lon_0=0 +x_0=0 +y_0=0 +a=6371007.181 +b=6371007.181 +units=m +no_defs")
outDataset.SetProjection(proj.ExportToWkt())
sd = hdf.SD('D:/GJSF/DATA/2908/MOD44B.A2000065.h29v08.005.2011259234325.hdf')
md = sd.attributes()['StructMetadata.0'][0:1111]
mu = re.search("UpperLeftPointMtrs=(.+)",md)
UpperLeftPointMtrs = md[mu.start():mu.end()]
x0,y0 = eval(UpperLeftPointMtrs[19:])
mu = re.search("LowerRightMtrs=(.+)",md)
LowerRightMtrs = md[mu.start():mu.end()]
x1,y1 = eval(LowerRightMtrs[15:])
geotransform = (x0,(x1-x0)/4800,0,y0,0,-(y1-y0)/4800)
outDataset.SetGeoTransform(geotransform)
band = outDataset.GetRasterBand(1)
dataset = band.WriteArray(XL)
结果如下图所示:
其实上述代码还是有缺陷的,每次只能处理同一地区12年的影像。没有实现全国的一次性计算完成,原因是多方面的:1.自己的水平还相当有限,写此博客也是班门弄斧。2.自己的计算机性能有限,没法一次性完成全国的计算。3.时间和精力有限。
在此希望有志同道合之人能够将此代码加以修改,将不胜感激!
下面是实现普聚类的代码:
#coding=utf-8
#Python 2.6.6 (r266:84297, Aug 24 2010, 18:46:32) [MSC v.1500 32 bit (Intel)] on win32
import sklearn
from sklearn.cluster import KMeans
from sklearn import metrics
import numpy as np
import pylab as pl
from sklearn.feature_extraction import image
from sklearn.cluster import spectral_clustering
import osgeo.gdal as gdal
import Image as Img
#读取tiff影像
dtatif=Img.open('D:/GJSF/DATA/ccy/2605RSize.tif')
tempArray=np.array(dtatif)
smallarray=tempArray[0:1200,0:1200]
#tempImg=Img.fromarray(tempArray)
ddimg=image.array2d(smallarray)
del(tempArray)
del(dtatif)
del(smallarray)
mask = ddimg.astype(bool)
ddimg=ddimg.astype(float)
graph = image.img_to_graph(ddimg, mask=mask)
graph.data = np.exp(-graph.data / graph.data.std())
labels = spectral_clustering(graph, n_clusters=4, eigen_solver='arpack')
label_im = -np.ones(mask.shape)
label_im[mask] = labels
pl.matshow(ddimg)
pl.matshow(label_im)
pl.show()
聚类结果如下图所示:
在聚类的过程中,没有完整的对整幅影像进行聚类,只是挑选了一块像素100*100的进行聚类。