Python的GDAL庫繪製多波段、長時序遙感影像時間曲線圖

疯狂学习GIS發表於2024-08-03

  本文介紹基於Python中的gdal模組,對大量長時間序列的柵格遙感影像檔案,繪製其每一個波段中、若干隨機指定的像元的時間序列曲線圖的方法。

  在之前的文章中,我們就已經介紹過基於gdal模組,對大量多時相柵格影像,批次繪製像元時間序列折線圖的方法。不過當時文章中的需求,每1個時相都對應著3個不同的遙感影像檔案,而每1個遙感影像檔案則都僅僅只有1個波段;而在本文中,我們每1景遙感影像都對應著2個波段,我們最終繪製的多條曲線圖,也都來自於這每1景遙感影像的不同波段。

  我們再來明確一下本文的需求。現在有一個資料夾,其中放置了大量的遙感影像檔案,如下圖所示。其中,所有遙感影像都是同一地區、不同成像時間的影像,其各自的空間參考資訊、像元行數與列數等都是一致的,檔名中有表示成像日期的具體欄位;且每1景遙感影像都具有2個波段。現在我們希望,在遙感影像覆蓋的區域內,隨機選取若干的像元,基於這些像元,我們繪製其隨時間變化的曲線圖。因為我們的每個遙感影像都有2個波段,且都希望繪製出曲線圖,因此最終的曲線圖一共就有2條曲線。

image

  明確了需求,我們就可以開始程式碼的撰寫。本文用到的程式碼如下。

# -*- coding: utf-8 -*-
"""
Created on Tue Jul 25 23:04:41 2023

@author: fkxxgis
"""

import os
import random
import matplotlib.pyplot as plt
from osgeo import gdal

def load_image(image_path):
    dataset = gdal.Open(image_path)
    band1 = dataset.GetRasterBand(1).ReadAsArray()
    band2 = dataset.GetRasterBand(2).ReadAsArray()
    del dataset
    return band1, band2

def plot_time_series(image_folder, pic_folder, num_pixels):
    image_files = [file for file in os.listdir(image_folder) if file.endswith(".tif")]
    band1_merge, band2_merge = [], []
    i = 0
    
    for image_file in image_files:
        image_path = os.path.join(image_folder, image_file)
        band1, band2 = load_image(image_path)
        band1_merge.append(band1)
        band2_merge.append(band2)
        i += 1

    x_size, y_size = band1.shape
    pixel_indices = random.sample(range(x_size * y_size), num_pixels)

    for pixel_index in pixel_indices:
        x, y = divmod(pixel_index, y_size)
        band_list_1, band_list_2 = [], []
        for i in range(len(band1_merge)):
            band_data_1 = band1_merge[i]
            band_list_1.append(band_data_1[x, y])
            band_data_2 = band2_merge[i]
            band_list_2.append(band_data_2[x, y])

        plt.figure()
        plt.plot(range(len(band1_merge)), band_list_1, label="Band 1")
        plt.plot(range(len(band1_merge)), band_list_2, label="Band 2")
        plt.xlabel("Time")
        plt.ylabel("NDVI")
        plt.ylim(0, 1000)
        plt.title(f"Time Series for Pixel at ({x}, {y})")
        plt.legend()
        plt.savefig(os.path.join(pic_folder, str(x) + "_" + str(y)))
        plt.show()

image_folder_path = "E:/02_Project/Result/test"
pic_folder_path = "E:/02_Project/TIFF/Plot"
num_pixels = 50
plot_time_series(image_folder_path, pic_folder_path, num_pixels)

  上述程式碼的具體含義如下。

  首先,我們匯入了需要使用的庫;其中,os用於處理檔案路徑和目錄操作,random用於隨機選擇畫素,matplotlib.pyplot則用於繪製影像。

  隨後,我們定義函式load_image(image_path);這個函式接收一個影像檔案路徑image_path作為輸入引數。隨後,在函式內使用gdal庫開啟該影像檔案,然後提取其第一個和第二個波段的資料,並分別儲存在band1band2中。最後,函式返回這兩個波段的資料。

  接下來,我們定義函式plot_time_series(image_folder, pic_folder, num_pixels);這個函式接收三個輸入引數,分別為image_folderpic_foldernum_pixels。其中,image_folder為包含多個.tif格式的影像檔案的資料夾路徑,pic_folder是儲存生成的時間序列影像的資料夾路徑,而num_pixels則指定了隨機選擇的畫素數量,用於繪製時間序列圖——這個引數設定為幾,我們最後就會得到幾張結果影像。

  在這個函式的內部,我們透過os.listdir函式獲取image_folder中所有以.tif結尾的影像檔案,並將這些檔名儲存在image_files列表中。然後,我們建立兩個空列表band1_mergeband2_merge,用於儲存所有影像檔案的2個波段資料。接下來,我們遍歷所有影像檔案,逐個載入每個影像檔案的全部波段資料,並將它們新增到對應的列表中。其次,使用random.sample函式從畫素索引的範圍中隨機選擇num_pixels個畫素的索引,並儲存在pixel_indices列表中。接下來,我們遍歷並恢復pixel_indices中的每個畫素索引,計算該畫素在每個影像中的每個波段的時間序列資料,並儲存在band_list_1band_list_2列表中。

  隨後,我們即可繪製兩個時間序列圖,分別表示2個波段在不同影像日期上的數值。最後,我們將影像儲存到指定的資料夾pic_folder中,命名規則為x_y,其中xy分別代表畫素的橫、縱座標。

  執行上述程式碼,我們即可在指定的資料夾路徑下看到我們生成的多張曲線圖;如下圖所示。

  其中,每1張影像都表示了我們2個波段在這段時間內的數值走勢;如下圖所示。

  至此,大功告成。

相關文章