Python に基づいた MODIS リモートセンシング データの処理

序文

MODIS は、250 ~ 500 メートルの解像度で毎日世界中のデータを収集する衛星リモート センシング機器です。Python で MODIS データをインポート、クリーンアップ、プロットする方法を学びます。

1. MODIS イメージの概要

中解像度イメージング分光放射計 (MODIS) は、地球表面のデータを継続的に収集する衛星ベースの機器です。現在、MODIS は公開されているリモート センシング データの中で最高の時間分解能を備えており、地球全体を 24 時間ごとにカバーしています。

MODIS は 36 のスペクトル バンドでデータを収集しますが、このブログでは最初の 7 バンドのみを使用します。

(1) MODIS 表面反射率(MOD09GA 製品)

MODIS データ製品にはさまざまな種類があります。これらは科学で使用するために処理されたデータセットです。このコースでは、MODIS の最初の 7 バンドを含む反射率製品である MOD09GA 製品を使用します。

表面反射率値の通常の範囲は 0 ~ 1 で、1 が最も明るい値、0 が最も暗い値です。表面反射率は、地上で測定される、地球表面の分光反射率の尺度です。これは、目が見るものと同じように考えることができますが、もちろん、電磁スペクトルの可視部分以外の光は目で見ることができません。

MODIS は、このコースで使用する表面反射率 MOD09GA 製品を含む、多数の標準化された製品を提供しています。MOD09GA 製品は、上の表にリストされている 7 つのスペクトル帯域で 500m の空間分解能で表面反射率を提供します。

MOD09 製品を作成したLand Surface Reflectance Science Computing Facilityによると、これらの製品は、大気散乱や吸収がないかのように地上で測定された場合の各バンドの表面分光反射率の推定値です。大気ガス、エアロゾル、薄い巻雲の影響を補正します。

(2) MOD09GAプロダクトのバンドメタデータ

MODIS データをよりよく理解するには、MODIS ユーザー ガイドの 14 ページにある MOD09GA 製品の詳細な表を参照してください。

いくつかの形式は次のとおりです。

MOD09GA 製品に関するこの表を使用して、次の質問に答えてください。

  • データの有効な値の範囲はどれくらいですか?

  • データ価値のないものは何でしょうか?

  • データに関連する倍率は何ですか?

(3) NBR 計算に使用される MODIS バンドを特定する

このブログでは、MODIS データを使用して NBR を計算します。ただし、さまざまなリモート センシング製品を使用して同じ植生指数を計算できても、各リモート センシング データの帯域が異なることに注意してください。

MODIS センサーの帯域範囲を示す上の表を確認してください。NBR インデックスは、760 ~ 900 nm の NIR 帯域と 2080 ~ 2350 nm の SWIR 帯域を持つマルチスペクトル センサーに適用されることを思い出してください。

2. MODIS イメージを開きます

コロラド州のコールドスプリングス火災調査地域からの火災前の MODIS 画像を使用して MODIS データを開く方法を学びます。

開始する前に、次のパッケージをインポートし、作業ディレクトリが設定されていることを確認してください。

from glob import glob
import os

import numpy as np
import numpy.ma as ma
import matplotlib.pyplot as plt
import geopandas as gpd
import rioxarray as rxr
import xarray as xr
from rasterio.plot import plotting_extent
import earthpy as et
import earthpy.spatial as es
import earthpy.plot as ep
from shapely.geometry import box

data = et.data.get_data('cold-springs-fire')
os.chdir(os.path.join(et.io.HOME, 'earth-analytics', 'data'))
Downloading from https://ndownloader.figshare.com/files/10960109
Extracted output to /root/earth-analytics/data/cold-springs-fire/.

前のレッスンでは、glob("*keyword*.tif") を使用して、同時に次のことを行うすべてのファイルのリストを作成しました。

  • アスタリスクで表される特定のキーワード (例: *band*) が含まれます。

  • 拡張子 .tif が含まれます。

まず、キーワードと拡張子 *sur_refl_b*.tif を使用した glob を使用して、MODIS 表面反射ラスターのリストを作成します。

# Create list of MODIS rasters for surface reflectance
modis_bands_pre_list = glob(os.path.join("cold-springs-fire",
                                         "modis",
                                         "reflectance",
                                         "07_july_2016",
                                         "crop",
                                         "*_sur_refl_b*.tif"))

# Sort the list of bands
modis_bands_pre_list.sort()
modis_bands_pre_list
['cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b01_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b02_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b03_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b04_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b05_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b06_1.tif',
 'cold-springs-fire/modis/reflectance/07_july_2016/crop/MOD09GA.A2016189.h09v05.006.2016191073856_sur_refl_b07
def combine_tifs(tif_list):
    """A function that combines a list of tifs in the same CRS
    and of the same extent into an xarray object

    Parameters
    ----------
    tif_list : list
        A list of paths to the tif files that you wish to combine.

    Returns
    -------
    An xarray object with all of the tif files in the listmerged into 
    a single object.

    """

    out_xr = []
    for i, tif_path in enumerate(tif_list):
        out_xr.append(rxr.open_rasterio(tif_path, masked=True).squeeze())
        out_xr[i]["band"] = i+1

    return xr.concat(out_xr, dim="band")

次に、関数combine_tifsを使用して、globを使用して作成したバンドのリストからrioxarrayオブジェクトを作成します。その後、MODIS バンドをインポートして RGB マップを作成できます。

# Open file list with function

modis_bands_pre = combine_tifs(modis_bands_pre_list)
# Plot MODIS RGB

ep.plot_rgb(modis_bands_pre.values,
            rgb=[0, 3, 2],
            title="Surface Reflectance \n MODIS RGB Bands")
plt.show()

冷水火災前の期間の RGB バンドを使用した MODIS 表面反射率。

3. データの値を確認する

データの調査を開始するには、選択したバンドの最小値と最大値を計算して、値の範囲を確認します。たとえば、MODIS スタックの最初のバンド (赤) についてこれらの値を計算できます。

# Identify minimum and maximum values of band 1 (red)
print(modis_bands_pre[1].min(), modis_bands_pre[1].max())
<xarray.DataArray ()>
array(-100., dtype=float32)
Coordinates:
    band         int64 2
    spatial_ref  int64 0 <xarray.DataArray ()>
array(10039., dtype=float32)
Coordinates:
    band         int64 2
    spatial_ref  int64 0

データ開放がすごい!ただし、ジョブ用にデータをトリミングする必要もあります。これは 2 つの簡単な手順で実行できます。

  • 火災境界線を MODIS データと同じ CRS 内に再投影します。

  • MODIS データは、ファイア バウンドと xarray_name.rio.clip() 関数を使用してクリップされます。この関数を GeoPandas オブジェクトで使用するには、 geopandas オブジェクトのジオメトリ列を呼び出す必要があります。

xarray_name.rio.clip(crop_bound.geometry)

但是,此方法会将场景剪裁成矢量形状的确切轮廓。 这可能很有用,但通常您会希望剪切覆盖矢量形状边界的矩形,而不是精确的形状。 为此,您可以使用从 shapely.geometry 导入的 box 函数在要剪切的几何体周围创建一个框。

xarray_name.rio.clip([box(*crop_bound.total_bounds)])

您可以在下面看到这两种方法剪辑场景的不同之处!

# Open fire boundary
fire_boundary_path = os.path.join("cold-springs-fire",
                                  "vector_layers",
                                  "fire-boundary-geomac",
                                  "co_cold_springs_20160711_2200_dd83.shp")
fire_boundary = gpd.read_file(fire_boundary_path)
fire_bound_sin = fire_boundary.to_crs(modis_bands_pre.rio.crs)

fire_bound_box = [box(*fire_bound_sin.total_bounds)]


# MODIS Clipped to Geometry
modis_clip_geometry = modis_bands_pre.rio.clip(fire_bound_sin.geometry,
                                               all_touched=True,
                                               from_disk=True)

# MODIS Clipped to Bounds
modis_clip = modis_bands_pre.rio.clip(fire_bound_box,
                                      all_touched=True,
                                      from_disk=True)

extent = plotting_extent(modis_clip[0].values, modis_clip.rio.transform())

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 15))

# Plotting Geometry Clip
ep.plot_rgb(modis_clip.values,
            rgb=[0, 3, 2],
            ax=ax1,
            extent=extent,
            title='MODIS Clipped to Bounds')

fire_bound_sin.boundary.plot(ax=ax1)

# Plotting Bounds Clip
ep.plot_rgb(modis_clip_geometry.values,
            rgb=[0, 3, 2],
            ax=ax2,
            extent=extent,
            title='MODIS Clipped to Geometry')

fire_bound_sin.boundary.plot(ax=ax2)

plt.show()

出于 NDVI 和 NBR 分析的目的,我们对周围区域以及直接位于几何体内部的像素感兴趣,因此对于此分析,我们将使用边界方法。

要探索裁剪后的数据,请回想一下,您还可以使用 earthpy 中的 plot_bands 函数来创建每个波段的图。

# Create a list of titles
titles = ["Red Band", "Near Infrared (NIR) Band", "Blue/Green Band", "Green Band",
          "Near Infrared (NIR) Band", "Mid-infrared Band", "Mid-infrared Band"]

# Plot all bands individually
ep.plot_bands(modis_clip,
              cols=3,
              title=titles,
              figsize=(10, 6))
plt.show()

来自 MODIS 的表面反射率裁剪图像,适用于冷泉前火灾的所有波段。

使用 RGB 波段的 MODIS 裁剪表面反射率,用于预冷泉火灾。

# Create a colors and titles list to use in the histogram
colors = ['r', 'k', 'b', 'g', 'k', 'y', 'y']
titles = ["Red Band", "Near Infrared (NIR) Band", "Blue/Green Band",
          "Green Band", "Near Infrared (NIR) Band",
          "Mid-infrared Band", "Mid-infrared Band"]

# Plot histogram
ep.hist(modis_clip.values,
        colors=colors,
        title=titles,
        cols=2)
plt.show()

来自 MODIS 的裁剪表面反射率直方图,用于预冷泉火灾的所有波段。

从直方图中,您可以看到表面反射率的值范围似乎更合适,但仍不在 0 和 1 之间。

4、MODIS 影像中的反射率值

如博客前面所述,反射率值的正常范围是 0 到 1,其中 1 是最亮的值,0 是最暗的值。

再次查看上面为波段 1 计算的最小值和最大值。您注意到什么?

如您所见,最小值和最大值大大超出 0 到 1 的预期范围。查看波段 1 的直方图,您还可以看到值的范围不是您所期望的。

是什么原因造成的? 要回答这个问题,您需要先更好地理解数据,然后才能更多地使用它。

(1)比例因子

使用遥感数据时,比例因子很常见。 数据很大,比例因子用于保持数据较小。 例如,存储带小数的数字(称为浮点数)比存储整数需要更多的空间。 因此,通常删除传感数据应用了一个比例因子,可用于

查看 MOD09GA 产品的表格,您可以看到 MODIS 数据的比例因子为 0.0001。 这意味着您应该将每一层乘以该值以获得数据的实际反射率值。

您可以使用 numpy 数组数学(有时在 GIS 工具中称为栅格数学)将此比例因子值应用于堆栈中的所有图层。 此处将整个数组乘以 .0001 以缩放每个图层或波段。

# Scale values of MODIS imagery stack
modis_bands_pre_scaled = modis_clip * 0.0001
# Identify minimum and maximum values of scaled band 1 (red)

print(modis_bands_pre_scaled[1].min(), modis_bands_pre_scaled[1].max())
<xarray.DataArray ()>
array(0.2496, dtype=float32)
Coordinates:
    band         int64 2
    spatial_ref  int64 0 <xarray.DataArray ()>
array(0.3013, dtype=float32)
Coordinates:
    band         int64 2
    spatial_ref  int64 0
# Create a colors and titles list to use in the histogram
colors = ['r', 'k', 'b', 'g', 'k', 'y', 'y']
titles = ["Red Band", "Near Infrared (NIR) Band", "Blue/Green Band", "Green Band",
          "Near Infrared (NIR) Band", "Mid-infrared Band", "Mid-infrared Band"]

# Plot histogram
ep.hist(modis_bands_pre_scaled.values,
        colors=colors,
        title=titles,
        cols=2)
plt.show()

来自 MODIS 的裁剪和缩放表面反射率的直方图,用于预冷泉火灾的所有波段。

おすすめ

転載: blog.csdn.net/u010329292/article/details/129268849