python3 用地面站點實測降雨數據校正TRMM/3B43遙感降雨數據

目的:學習用地面站點實測降雨數據校正衛星遙感降雨數據。
學習將多景遙感圖像繪製成在一張圖上,且使用同一個colorbar
原始數據:
2007-2010年的TRMM衛星3B43產品(覆蓋範圍精度-180~ 180、緯度-50~50,0.25x0.25度分辨率,像素值單位:mm/hour);
江西梅川江地區63個氣象站的2007-2010年的月降雨數據,以及站點位置SHAPE文件;
數據處理要求:
實驗區2(江西梅川江)
對覆蓋範圍(經度:115-117,緯度:25.5-27.5)內的衛星年降雨數據,用地面數據進行校正,並存爲TIF文件。
校正的衛星年降雨數據可以是一年的,如:2010年,也可以是2007-2010年時間序列數據。
兩個實驗區,選擇一組數據處理即可
建議採用python和本課程學習的各種軟件包完成,但是本着“抓着老鼠就是好貓”原則,可不侷限於本門課程講授的內容。

引言

在遙感領域處理方法即是將站點附近3*3像元內的平均值作爲遙感圖像站點值與地面站點值進行比較,或以站點所在位置爲圓心,10km半徑(或其他半徑)內的像元平均值作爲遙感圖像站點值與地面站點值進行比較,選擇1/3的實驗數據用來建模,2/3的實驗數據用來驗證模型。

在GIS(Geographic Information Science,GIS)領域中,由於尺度問題造成的誤差是通過另一種尺度匹配方法減小的,通常對站點數據shape建立泰森多邊形,將點尺度轉換爲柵格尺度,每個柵格值基於不同因素加權平均得到,然後將轉換後的柵格像元與遙感圖像像元值進行比較建模研究,選擇1/3的實驗數據用來建模,2/3的實驗數據用來驗證模型。

本實驗採用前者,但考慮到TRMM像元空間分辨率爲2.5km,63個站點之間的距離在TRMM遙感圖像上非常接近,無法取3*3像元或圓心半徑法進行研究。本實驗直接取2010年地面站點值與對應位置處遙感圖像值進行建模,由於梅江川地區63個雨量站位置相近,海拔、經緯度等因素對其模型影響可忽略不計,因此只考慮數值誤差之間的差異,選擇一元線性迴歸方法進行建模。

建立模型

點擊鏈接,查看上一篇文章。
用地面雨量計數據校正TRMM/3B43數據之模型建立

模型應用

使用上述線性模型進行校正,並將校正前後的梅川江地區遙感圖像繪製成在一張圖上,且使用同一個colorbar。
前篇代碼
改進後的代碼,如下:

# -*- coding: utf-8 -*-
"""
Created on Sat Nov 16 09:43:08 2019

@author: Administrator
"""

from osgeo import gdal
import numpy as np
import sympy as sp
import matplotlib.pyplot as plt
from matplotlib.colors import Normalize

#-------------------------讀取2007、2008、2009年TRMM降水遙感圖像-----------------------
path = 'E:\\課程PPT\\Python空間數據處理\\python空間數據處理-期中大作業02\\衛星降雨數據TRMM3B43_分辨率0.25度\\'
#有時候路徑必須雙反斜槓
dataset = gdal.Open(path + '3B43_2007.TIF')
dataset2 = gdal.Open(path + '3B43_2008.TIF')
dataset3 = gdal.Open(path + '3B43_2009.TIF')
samples = dataset.RasterXSize
lines = dataset.RasterYSize
bands = dataset.RasterCount
img_geotrans = dataset.GetGeoTransform()
#Out[10]: (-180.0, 0.25, 0.0, 50.0, 0.0, -0.25)
img_proj = dataset.GetProjection()
#Out[12]: 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"...]]]
#可以看到此遙感圖像未進行投影定義,因此還不是投影座標,只是地理座標
#在求解這些實測站點位於圖像中哪個行列位置時不用將其轉爲投影座標
im_data1 = dataset.ReadAsArray(0,0,samples,lines)
im_data2 = dataset2.ReadAsArray(0,0,samples,lines)
im_data3 = dataset3.ReadAsArray(0,0,samples,lines)
del dataset
del dataset2
del dataset3
#--------------------------------校正數據---------------------------------------
cor_data1 = 0.797 * im_data1 + 352.279
cor_data2 = 0.797 * im_data2 + 352.279
cor_data3 = 0.797 * im_data3 + 352.279
#-------------------------------找到研究區範圍的行列號-------------------------------------
#-----------------------轉換左上、右下經緯度座標到對應遙感圖像上的行列號----------
im_loc = [[],[]]
#第一個列表放行號,存緯度換出來的值,後者爲列號,存經度換出來的值
# variable += [value] 等同於 variable.append(value)
#左上角 115 27.5
#右下角 117 25.5
pnt_coordinates = [[115,117],[27.5,25.5]]
for i in range(len(pnt_coordinates[0])):
    sample = sp.Symbol('sample')
    line = sp.Symbol('line')
    #pnt_coordinates[0][i] = img_geotrans[0] + sample*img_geotrans[1] + line*img_geotrans[2]
    #pnt_coordinates[1][i] = img_geotrans[3] + sample*img_geotrans[4] + line*img_geotrans[5]
    a = -pnt_coordinates[0][i] + img_geotrans[0] + sample*img_geotrans[1] + line*img_geotrans[2]
    b = -pnt_coordinates[1][i] + img_geotrans[3] + sample*img_geotrans[4] + line*img_geotrans[5]
    answer = sp.solve([a,b],[sample,line])#解二元一次方程組
    #Out[15]: {x: 0, y: 1}
    line = int(np.floor(answer[line]))
    sample = int(np.floor(answer[sample]))
    im_loc[0] += [line]
    im_loc[1] += [sample]
#------------------------------起始終止行列號------------------------------------
start_line = im_loc[0][0]
end_line = im_loc[0][1]
start_sample = im_loc[1][0]
end_sample = im_loc[1][1]
#將所有裁剪的數據存在一個列表中
datasets = []
for j in range(3):
    datasets += [eval('im_data'+str(j+1))[start_line:end_line,start_sample:end_sample]]
for i in range(3):
    datasets += [eval('cor_data'+str(i+1))[start_line:end_line,start_sample:end_sample]]
#----------------------------用於生產colorbar的vmin和vmax-----------------------
vmin = np.min(datasets)
vmax = np.max(datasets)
#------------------------------------繪圖---------------------------------------
fig,axs = plt.subplots(nrows = 2, ncols = 3,figsize = (14,8))
#figsize = (width,hight) #按照出圖比例來
extent = (0,1,0,1)
#將x周和y軸都歸一化。方便指定label的位置(0,1)相對比例,否則指定label位置時不好指定
norm = Normalize(vmin = vmin,vmax = vmax)
#Normalize()跟歸一化沒有任何關係,函數的作用是將顏色映射到vmin-vmax上,即讓接下來的顏色表/顏色柱的起始和終止分別取值vmin和vmax
for i in range(2):
    if i == 0:        
        for j in range(3):
            axs[i,j].imshow(datasets[j],extent = extent,norm = norm,cmap = 'jet_r')
            axs[i,j].set_xlabel(str(2007+j)+ ' Original',fontdict = {'family' : 'Times New Roman','fontweight':'bold','size':15})
            axs[i,j].set_xticks(np.linspace(0,1,5))
            font = {'fontweight':'bold'}
            axs[i,j].set_xticklabels(('115.0E','115.5E','116.0E','116.5E','117.0E'),fontdict = font)
            axs[i,j].set_yticks(np.linspace(0,1,5))
            axs[i,j].set_yticklabels(('25.5 N','26.0 N','26.5 N','27.0 N','27.5 N'),fontdict = font)
    else:
        for j in range(3):
            axs[i,j].imshow(datasets[j+3],extent = extent,norm = norm,cmap = 'jet_r')
            axs[i,j].set_xlabel(str(2007+j)+ ' Corrected',fontdict = {'family' : 'Times New Roman','fontweight':'bold','size':15})
            axs[i,j].set_xticks(np.linspace(0,1,5))
            font = {'fontweight':'bold'}
            axs[i,j].set_xticklabels(('115.0E','115.5E','116.0E','116.5E','117.0E'),fontdict = font)
            axs[i,j].set_yticks(np.linspace(0,1,5))
            axs[i,j].set_yticklabels(('25.5 N','26.0 N','26.5 N','27.0 N','27.5 N'),fontdict = font)
            if j == 2:
                sc = axs[i,j].imshow(datasets[j+3],extent = extent,norm = norm,cmap = 'jet_r')
#一行三個子圖的總寬度 爲 全部寬度的 0.9;剩下的0.1用來放置colorbar
fig.subplots_adjust(right=0.9)
#colorbar 左 下 寬 高 
l = 0.92
b = 0.53
w = 0.015
h = 0.35
#對應 l,b,w,h;設置colorbar位置;
rect = [l,b,w,h] 
cbar_ax = fig.add_axes(rect) 
plt.colorbar(sc, cax=cbar_ax)
plt.savefig('correct_pictures.png',dpi = 300,bbox_inches='tight')
plt.show()

在這裏插入圖片描述

模型精度評價

爲評價線性模型校正精度,分別計算校正之前和校正之後的TRMM/3B43遙感反演數據與雨量計數據之間的MAE(mean absolute error,MAE)、RMSE(root mean square error,RMSE)和 ,計算63個雨量計數據與校正前後的上述統計指標。
注意:接下來的代碼需在上面的基礎上運行

# -*- coding: utf-8 -*-
"""
Created on Tue Nov 12 19:31:07 2019

@author: BAI Depei
"""

from osgeo import ogr
from osgeo import gdal
import numpy as np
import sympy as sp

#------------------read the station_coordinates--------------------
fn = 'E:\課程PPT\Python空間數據處理\python空間數據處理-期中大作業02\梅川江地面數據\meichuan_prec_station.shp'
ds = ogr.Open(fn,False)
layer = ds.GetLayer(0)
spatialref = layer.GetSpatialRef()
lydefn = layer.GetLayerDefn()  #圖層定義信息
geomtype = lydefn.GetGeomType()
fieldlist = [] 
for i in range(lydefn.GetFieldCount()):
    fddefn = lydefn.GetFieldDefn(i)
    fddict = {'name':fddefn.GetName(),'type':fddefn.GetType(),\
              'width':fddefn.GetWidth(),'decimal':fddefn.GetPrecision()}
    fieldlist += [fddict]
    #獲取屬性表每列列名及其屬性:類型、寬度、精度
    geomlist,reclist = [],[]
    #geomlist存放所有圖形的座標點(字符串中包含),reclist存放所有的圖形名
    feature = layer.GetNextFeature()
    #首次獲取feature
    while feature is not None:
        geom = feature.GetGeometryRef()
        geomlist += [geom.ExportToWkt()]
        rec = {}
        for fd in fieldlist:
            rec[fd['name']] = feature.GetField(fd['name'])
        reclist += [rec]
        feature = layer.GetNextFeature()
ds.Destroy()
#關閉數據
#-------------------------將座標寫入列表中---------------------------------
pnt_coordinates = [[],[]]
for i in range(len(geomlist)):
    a = geomlist[i].split(' ')
    b = a[1].split('(')
    c = a[2].split(')')
    longitude = float(b[1])
    latitude = float(c[0])
    pnt_coordinates[0] += [longitude]
    pnt_coordinates[1] += [latitude]
#reclist則不必寫入其他變量,因其調用簡單

#-------------------------讀取2010年TRMM降水遙感圖像-----------------------
path = 'E:\\課程PPT\\Python空間數據處理\\python空間數據處理-期中大作業02\\衛星降雨數據TRMM3B43_分辨率0.25度\\'
#有時候路徑必須雙反斜槓
dataset = gdal.Open(path + '3B43_2010.TIF')
samples = dataset.RasterXSize
lines = dataset.RasterYSize
bands = dataset.RasterCount
img_geotrans = dataset.GetGeoTransform()
#Out[10]: (-180.0, 0.25, 0.0, 50.0, 0.0, -0.25)
img_proj = dataset.GetProjection()
#Out[12]: 'GEOGCS["WGS 84",DATUM["WGS_1984",SPHEROID["WGS 84"...]]]
#可以看到此遙感圖像未進行投影定義,因此還不是投影座標,只是地理座標
#在求解這些實測站點位於圖像中哪個行列位置時不用將其轉爲投影座標
im_data = dataset.ReadAsArray(0,0,samples,lines)

del dataset
#-----------------------轉換站點經緯度座標到對應遙感圖像上的行列號----------
im_loc = [[],[]]
#第一個列表放行號,存緯度換出來的值,後者爲列號,存經度換出來的值
# variable += [value] 等同於 variable.append(value)
for i in range(len(pnt_coordinates[0])):
    sample = sp.Symbol('sample')
    line = sp.Symbol('line')
    #pnt_coordinates[0][i] = img_geotrans[0] + sample*img_geotrans[1] + line*img_geotrans[2]
    #pnt_coordinates[1][i] = img_geotrans[3] + sample*img_geotrans[4] + line*img_geotrans[5]
    a = -pnt_coordinates[0][i] + img_geotrans[0] + sample*img_geotrans[1] + line*img_geotrans[2]
    b = -pnt_coordinates[1][i] + img_geotrans[3] + sample*img_geotrans[4] + line*img_geotrans[5]
    answer = sp.solve([a,b],[sample,line])#解二元一次方程組
    #Out[15]: {x: 0, y: 1}
    line = int(np.floor(answer[line]))
    sample = int(np.floor(answer[sample]))
    im_loc[0] += [line]
    im_loc[1] += [sample]
#----------------------read 2007_2009_TRMM_stationpnt_value-------------------------    
data_TRMM_stationpnt = [[],[],[],[],[],[]]
for i in range(len(im_loc[0])):
    data_TRMM_stationpnt[0] += [im_data1[im_loc[0][i],im_loc[1][i]]]
    data_TRMM_stationpnt[1] += [im_data2[im_loc[0][i],im_loc[1][i]]]
    data_TRMM_stationpnt[2] += [im_data3[im_loc[0][i],im_loc[1][i]]]
    data_TRMM_stationpnt[3] += [cor_data1[im_loc[0][i],im_loc[1][i]]]
    data_TRMM_stationpnt[4] += [cor_data2[im_loc[0][i],im_loc[1][i]]]
    data_TRMM_stationpnt[5] += [cor_data3[im_loc[0][i],im_loc[1][i]]]
#----------------------read 2010_rain_gauge_value------------------------------
path2 = 'E:\\課程PPT\\Python空間數據處理\\python空間數據處理-期中大作業02\\梅川江地面數據\\'
file_handle = open(path2 + 'meichuan_precipitation_2007-2010.txt')
line_value = file_handle.readlines()
file_handle.close()

#data_TRMM_stationpnt是根據geomlist次序依次遍歷獲得的,
#而geomlist次序與reclist次序一致,因此用reclist中臺站名和2010作爲關鍵字去檢索
data_rain_gauge_2007_2009 = [[],[],[]]
#站點數據
for i in range(1,len(line_value)):
    temp = line_value[i][:-2].split(',')
    #Out[3]: '200704,DongShao,184.200000\n'
    if temp[0] == '200701':
        data = []
        for j in range(12):
            temp  = line_value[i+j][:-2].split(',')
            data += [float(temp[2])]
        total_value = sum(data)
        data_rain_gauge_2007_2009[0] +=  [total_value]
        i += 12
        continue
    if temp[0] == '200801':
        data = []
        for j in range(12):
            temp  = line_value[i+j][:-2].split(',')
            data += [float(temp[2])]
        total_value = sum(data)
        data_rain_gauge_2007_2009[1] +=  [total_value]
        i += 12
        continue
    if temp[0] == '200901':
        data = []
        for j in range(12):
            temp  = line_value[i+j][:-2].split(',')
            data += [float(temp[2])]
        total_value = sum(data)
        data_rain_gauge_2007_2009[2] +=  [total_value]
        i += 12
        continue
#------------------------calculate statistics index--------------------------
mean_TRMM_2007 = np.mean(data_TRMM_stationpnt[0])
mean_TRMM_2008 = np.mean(data_TRMM_stationpnt[1])
mean_TRMM_2009 = np.mean(data_TRMM_stationpnt[2])
MAE = []
for i in range(3):
    MAE += [sum(abs(np.array(data_TRMM_stationpnt[i])-np.array(data_rain_gauge_2007_2009[i])))/63]
for i in range(3):
    MAE += [sum(abs(np.array(data_TRMM_stationpnt[i+3])-np.array(data_rain_gauge_2007_2009[i])))/63]
RMSE = []
for i in range(3):
    RMSE += [np.sqrt((sum(abs(np.array(data_TRMM_stationpnt[i])-np.array(data_rain_gauge_2007_2009[i])))**2)/63)]
for i in range(3):
    RMSE += [np.sqrt((sum(abs(np.array(data_TRMM_stationpnt[i+3])-np.array(data_rain_gauge_2007_2009[i])))**2)/63)]
R = []
for i in range(6):
    if i <3:       
        mean_TRMM = np.mean(np.array(data_TRMM_stationpnt[i]))
        mean_rain = np.mean(np.array(data_rain_gauge_2007_2009[i]))
        a = np.array(data_TRMM_stationpnt[i]) - mean_TRMM
        b = np.array(data_rain_gauge_2007_2009[i]) - mean_rain
        c = (sum(a*b))/np.sqrt(sum(a**2)*sum(b**2))
        R.append(c)
        i += 1 
    else:
        mean_TRMM = np.mean(np.array(data_TRMM_stationpnt[i]))
        mean_rain = np.mean(np.array(data_rain_gauge_2007_2009[i-3]))
        a = np.array(data_TRMM_stationpnt[i]) - mean_TRMM
        b = np.array(data_rain_gauge_2007_2009[i-3]) - mean_rain
        c = (sum(a*b))/np.sqrt(sum(a**2)*sum(b**2))
        R += [c]

結論

結論就是該模型效果不好,此處不予展示。
通過該模型校正之後,TRMM數據與雨量計實測數據之間的MAE明顯變大,RMSE相比校正前明顯變大,模型校正前後R變化不大,因此可知利用2010年建立的線性迴歸模型雖然本身是顯著的,但利用該模型校正其他年份的TRMM數據效果不理想,考慮到各個雨量站之間的地理環境差異不大,因此建立與地理環境因素有關的模型是不成立的,而純粹的一元線性迴歸數學模型又會使得偏差增大,因此下一步可以考慮嘗試其他數學模型如殘差模型等來進行校正。


好好生活,珍惜愛你的和你愛的人!

版權歸作者 小白是哪個小白_ 所有,轉載、引用請註明鏈接出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章