ナビゲーションをスキップする

MODIS

SatelliteImagery EarthObservation AIforEarth NASA USGS

中分解能撮像分光放射計 (MODIS) の衛星画像。

MODIS は、1999 年から現在まで、広いスペクトル範囲の地球観測データを提供しています。 MODIS 衛星は 1 から 2 日ごとに地球の画像を撮影しますが、MODIS データから派生した個々の製品では、時間分解能が低い場合があります。 MODIS は、米国航空宇宙局 (NASA) と米国地質調査所 (USGS) によって管理されています。 現在、2000 年に遡って MCD43A4 (500 m 分解能、日別地球表面反射率) 製品を Azure でミラーリングしており、その他の MODIS 製品もオンボードされる予定です。

Storage のリソース

データは、米国東部データ センターにある次の BLOB コンテナーの BLOB に格納されています。

https://modissa.blob.core.windows.net/modis

このコンテナー内では、次の形式に従ってデータが整理されれています。

[product]/[htile]/[vtile]/[daynum]/[filename]

product は MODIS 製品名です。現在、MCD43A4 が Azure で利用可能です。

htilevtile は、MODIS 正弦波グリッド システムのタイル番号を指します。 “データ アクセス” で利用できるノートブックでは、緯度と経度をこのグリッド システムにマップする 1 つの方法を示しています。

daynum は、4 桁の年と 3 桁の通日 (001 から 365 まで) の組み合わせです。たとえば、2019001 は 2019 年 1 月 1 日を表します。

たとえば、次のフォルダーがあるとします。

MCD43A4/00/08/2019010

このフォルダーには、2019 年 1 月 10 日の画像が含まれています。

画像は GeoTIFF 形式で保存され、MODIS チャネルごとに 1 つの画像があります。 チャネルからスペクトル バンドへのマッピングは製品固有です。MCD43A4 の場合、マッピングはこちらで提供されています。

該当のドキュメントによると、スペクトル バンド 1 は MCD43A4 のチャネル 7 に対応するので、上記のディレクトリの次のファイルには、

MCD43A4.A2019001.h00v08.006.2019010201703.hdf_07.tiff

スペクトル バンド 1 からの情報が含まれています。

MODIS 画像へのアクセスやプロットに関する完全な Python の例は、“データ アクセス”で提供されるノートブックでご確認いただけます。

また、BlobFuse などを介して MODIS データにアクセスできるように、読み取り専用の SAS (Shared Access Signature) トークンも提供されます。これにより、BLOB コンテナーをドライブとしてマウントできます。

st=2019-07-26T22%3A24%3A15Z&se=2032-07-27T22%3A24%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=ENT24qUY%2BlxL93XMykFQwfq4ctHDPLmYPDaaAn7YI3Q%3D

Linux でのマウントの手順については、こちらをご覧ください。

MODIS データは数百テラバイトを消費する可能性があるため、大規模な処理は、画像が保存されている米国東部の Azure データ センターで実行するのが最適です。 MODIS データを環境科学の用途に使用する場合は、コンピューティング要件をサポートするために、AI for Earth 助成金の申請を検討してください。

かわいい写真


2019 年 5 月 15 日のシカゴ エリアのイメージ。

Contact

このデータセットに関するご質問がある場合は、aiforearthdatasets@microsoft.com にお問い合わせください。

通知

Microsoft は、Azure オープン データセットを “現状有姿” で提供します。 Microsoft は、データセットの使用に関して、明示または黙示を問わず、いかなる保証も行わないものとし、条件を定めることもありません。 現地の法律の下で認められている範囲内で、Microsoft は、データセットの使用に起因する、直接的、派生的、特別、間接的、偶発的、または懲罰的なものを含めたいかなる損害または損失に対しても一切の責任を負わないものとします。

このデータセットは、Microsoft がソース データを受け取った元の条件に基づいて提供されます。 データセットには、Microsoft が提供するデータが含まれている場合があります。

Access

Available inWhen to use
Azure Notebooks

Quickly explore the dataset with Jupyter notebooks hosted on Azure or your local machine.

Select your preferred service:

Azure Notebooks

Azure Notebooks

Package: Language: Python

Demo notebook for accessing MODIS data on Azure

This notebook provides an example of accessing MODIS data from blob storage on Azure, including (1) finding the MODIS tile corresponding to a lat/lon coordinate, (2) retrieving that tile from blob storage, and (3) displaying that tile using the rasterio library.

This notebook uses the MODIS surface reflectance product as an example, but data structure and access will be the same for other MODIS products.

MODIS data are stored in the East US data center, so this notebook will run most efficiently on Azure compute located in East US. We recommend that substantial computation depending on MODIS data also be situated in East US. You don't want to download hundreds of terabytes to your laptop! If you are using MODIS data for environmental science applications, consider applying for an AI for Earth grant to support your compute requirements.

Imports and environment

In [1]:
# Standard or standard-ish imports
import os
import tempfile
import numpy as np
import shutil
import urllib
import matplotlib.pyplot as plt

# Less standard, but still pip- or conda-installable
import rasterio

# pip install azure-storage-blob
from azure.storage.blob import ContainerClient

# Storage locations are documented at http://aka.ms/ai4edata-modis
modis_account_name = 'modissa'
modis_container_name = 'modis'
modis_account_url = 'https://' + modis_account_name + '.blob.core.windows.net/'
modis_blob_root = modis_account_url + modis_container_name

# Temporary folder for data we need during execution of this notebook (we'll clean up
# at the end, we promise)
temp_dir = os.path.join(tempfile.gettempdir(),'modis')
os.makedirs(temp_dir,exist_ok=True)

# This file is provided by NASA; it indicates the lat/lon extents of each
# MODIS tile.
#
# The file originally comes from:
#
# https://modis-land.gsfc.nasa.gov/pdf/sn_bound_10deg.txt
modis_tile_extents_url = modis_blob_root + '/sn_bound_10deg.txt'

# Load this file into a table, where each row is (v,h,lonmin,lonmax,latmin,latmax)
modis_tile_extents = np.genfromtxt(modis_tile_extents_url,
                     skip_header = 7, 
                     skip_footer = 3)

# Read-only shared access signature (SAS) URL for the MODIS container
modis_sas_token = 'st=2019-07-26T17%3A21%3A46Z&se=2029-07-27T17%3A21%3A00Z&sp=rl&sv=2018-03-28&sr=c&sig=1NpBV6P8SIibRcelWZyLCpIh4KFiqEzOipjKU5ZIRrQ%3D'

modis_container_client = ContainerClient(account_url=modis_account_url, 
                                         container_name=modis_container_name,
                                         credential=None)
                                
%matplotlib inline

Functions

In [2]:
def lat_lon_to_modis_tile(lat,lon):
    """
    Get the modis tile indices (h,v) for a given lat/lon
    
    https://www.earthdatascience.org/tutorials/convert-modis-tile-to-lat-lon/
    """
    
    found_matching_tile = False
    i = 0
    while(not found_matching_tile):
        found_matching_tile = lat >= modis_tile_extents[i, 4] \
        and lat <= modis_tile_extents[i, 5] \
        and lon >= modis_tile_extents[i, 2] and lon <= modis_tile_extents[i, 3]
        i += 1
        
    v = int(modis_tile_extents[i-1, 0])
    h = int(modis_tile_extents[i-1, 1])
    
    return h,v


def list_blobs_in_folder(container_name,folder_name):
    """
    List all blobs in a virtual folder in an Azure blob container
    """
    
    files = []
    generator = modis_container_client.list_blobs(name_starts_with=folder_name)
    for blob in generator:
        files.append(blob.name)
    return files
        
    
def list_tiff_blobs_in_folder(container_name,folder_name):
    """"
    List .tiff files in a folder
    """
    
    files = list_blobs_in_folder(container_name,folder_name)
    files = [fn for fn in files if fn.endswith('.tiff')]
    return files
             

def download_url(url, destination_filename=None, progress_updater=None, force_download=False):
    """
    Download a URL to a temporary file
    """
    
    # This is not intended to guarantee uniqueness, we just know it happens to guarantee
    # uniqueness for this application.
    if destination_filename is None:
        url_as_filename = url.replace('://', '_').replace('.', '_').replace('/', '_')
        destination_filename = \
            os.path.join(temp_dir,url_as_filename)
    if (not force_download) and (os.path.isfile(destination_filename)):
        print('Bypassing download of already-downloaded file {}'.format(os.path.basename(url)))
        return destination_filename
    print('Downloading file {}'.format(os.path.basename(url)),end='')
    urllib.request.urlretrieve(url, destination_filename, progress_updater)  
    assert(os.path.isfile(destination_filename))
    nBytes = os.path.getsize(destination_filename)
    print('...done, {} bytes.'.format(nBytes))
    return destination_filename

Access and plot a MODIS tile

In [3]:
# Files are stored according to:
#
# http://modissa.blob.core.windows.net/[product]/[htile]/[vtile]/[year][day]/filename

# Surface reflectance
product = 'MCD43A4'

# Let's look at the tile containing Chicago, IL, on May 15, 2019 (day of year 135)
h,v = lat_lon_to_modis_tile(41.881832,-87.623177)
daynum = '2019135'
folder = product + '/' + '{:0>2d}/{:0>2d}'.format(h,v) + '/' + daynum

# Find all .tiff files from this tile on this day, one file per channel
files = list_tiff_blobs_in_folder(modis_container_name,folder)

norm_value = 4000

# Channel 7 in a MCD43A4 file corresponds to MODIS band 1.  
#
# Let's map bands 1, 4, and 3 (channels 7,10,9) to RGB.
channels = [7,10,9]
image_data = []
for ifn in channels:
    remote_fn = files[ifn]
    url = modis_blob_root + '/' + remote_fn
    fn = download_url(url)
    raster = rasterio.open(fn,'r')
    band_array = raster.read(1)
    raster.close()
    band_array = band_array / norm_value
    image_data.append(band_array)
rgb = np.dstack((image_data[0],image_data[1],image_data[2]))
np.clip(rgb,0,1,rgb)
plt.imshow(rgb)
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_08.tiff...done, 11546274 bytes.
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_11.tiff...done, 11546274 bytes.
Downloading file MCD43A4.A2019135.h11v04.006.2019149220457.hdf_10.tiff...done, 11546274 bytes.
Out[3]:
<matplotlib.image.AxesImage at 0x223970bbc48>

Clean up temporary files

In [ ]:
shutil.rmtree(temp_dir)