PythonでJAXAの人工衛星だいち(ALOS)の世界標高データ活用(3)

前回:https://shikuuk.blogspot.com/2025/07/pythonjaxaalos2.html


 第3部は2つ(以上)の5*5タイルを読み込み、そのDataをMargeしてMosicImageにしたあと、MatplotlibでTry to drawとThinkします。

 ALOSJapanDomainだけでなくGlobalなElavationDataをContainしているAs、例えばIndonesiaSumatraIslandをDrawにTryします。

 まずはALOSのDownLoadHPでIndonesiaSumatraIslandのAroundのConditionをConfirmします。


 SumatraIslandは5*5のTileでViewすると、North-WestはN10-E95で、そこからS05E105のTileまでがArea we should readのRegionと思われます。
 一度にそこまで進めると、Errorが出た時が面倒くさいので、まずはN10-E95とN5-E100の2つのTileを処理するところからはじめてみました。従来のCodeを使って当該2TilesをDownLaodし、MatplotlibでDrawすると、以下のOutputになります。ColarのContourFigureとLineのContour Figureを作成していますが、最初、ColorのContourFigureでは海岸線が見づらくて、LineContourを追加したところ、LineContourもColorContourによく似た表示になりました。「なぜかなぁ?」とちょっと悩みましたが、ContourLineの間隔、言い換えれば等高線の間隔が小さすぎるということが原因でした。下のLineContourは標高値200m間隔になっています。これでもまだごちゃごちゃしていて見づらい感じは残っています。


 例えばContourの間隔を500mにすると、このようなFigureにbecomeしました。
 LineContourがかなり見やすくなったと思います。

 一応コードも残しておきます。(‘levels = np.arange(math.floor(min_elev / 200) * 200, math.ceil(max_elev / 200) * 200 + 200, 200)’)<--ここが等高線間隔をSettingするSectionです。
import rasterio
import matplotlib.pyplot as plt
import numpy as np
import os
from skimage.transform import downscale_local_mean
import math # mathモジュールのインポートを追加

def plot_merged_elevation(filepath):
    """
    指定されたGeoTIFF標高ファイルをMatplotlibでGoogle Colabの出力ウィンドウに直接表示します。
    メモリ使用量を抑えるために、データをリサイズしてからプロットします。

    Args:
        filepath (str): 表示するGeoTIFFファイルのパス。
    """
    if not os.path.exists(filepath):
        print(f"エラー: GeoTIFFファイル '{filepath}' が見つかりません。")
        return

    try:
        with rasterio.open(filepath) as src:
            # 標高データを読み込む(通常はバンド1)
            elevation_data = src.read(1)
            print(f"オリジナルデータのサイズ: {elevation_data.shape}")

            # 巨大なデータセットをリサイズしてメモリを節約
            # 8分の1にリサイズする例 (ダウンサンプリング)
            downscaled_elevation = downscale_local_mean(elevation_data, (8, 8))
            print(f"リサイズ後のデータのサイズ: {downscaled_elevation.shape}")

            # リサイズされたデータにNoData値が存在する場合、それをNaN(非数)に変換
            if src.nodata is not None:
                # 浮動小数点型に変換してからNaNを代入
                if downscaled_elevation.dtype != np.float64:
                    downscaled_elevation = downscaled_elevation.astype(np.float64)
                downscaled_elevation[downscaled_elevation == src.nodata] = np.nan

            # プロットのセットアップ
            fig, ax = plt.subplots(figsize=(10, 8))

            # 画像として標高データを表示
            valid_downscaled_data = downscaled_elevation[~np.isnan(downscaled_elevation)]
            if valid_downscaled_data.size > 0:
                vmin = np.nanpercentile(valid_downscaled_data, 2)
                vmax = np.nanpercentile(valid_downscaled_data, 98)
            else:
                vmin, vmax = None, None

            # 画像の表示範囲を設定 (左経度, 右経度, 下緯度, 上緯度)
            bounds = src.bounds
            extent = [bounds.left, bounds.right, bounds.bottom, bounds.top]

            im = ax.imshow(
                downscaled_elevation,
                cmap='viridis',
                origin='upper',
                extent=extent,
                vmin=vmin,
                vmax=vmax
            )
           
            ax.set_aspect('equal') # アスペクト比を等しく設定

            ax.set_title(f'Downscaled Elevation Data (Color Map): {os.path.basename(filepath)}')
            ax.set_xlabel('Longitude')
            ax.set_ylabel('Latitude')
            fig.colorbar(im, ax=ax, label='Elevation (meters)')
            ax.grid(True, linestyle=':', alpha=0.7)
            fig.tight_layout()
           
            plt.show()

    except rasterio.errors.RasterioIOError as e:
        print(f"エラー: GeoTIFFファイル '{filepath}' を開けませんでした: {e}")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")


def plot_merged_elevation_contour(filepath):
    """
    指定されたGeoTIFF標高ファイルをMatplotlibでGoogle Colabの出力ウィンドウに直接表示します。
    メモリ使用量を抑えるためにデータをリサイズし、等高線マップとしてプロットします。
    背景の着色は行いません。

    Args:
        filepath (str): 表示するGeoTIFFファイルのパス。
    """
    if not os.path.exists(filepath):
        print(f"エラー: GeoTIFFファイル '{filepath}' が見つかりません。")
        return

    try:
        with rasterio.open(filepath) as src:
            # 標高データを読み込む(通常はバンド1)
            elevation_data = src.read(1)
            print(f"オリジナルデータのサイズ: {elevation_data.shape}")

            # 巨大なデータセットをリサイズしてメモリを節約
            # 8分の1にリサイズする例 (ダウンサンプリング)
            downscaled_elevation = downscale_local_mean(elevation_data, (8, 8))
            print(f"リサイズ後のデータのサイズ: {downscaled_elevation.shape}")

            # リサイズされたデータにNoData値が存在する場合、それをNaN(非数)に変換
            if src.nodata is not None:
                # 浮動小数点型に変換してからNaNを代入
                if downscaled_elevation.dtype != np.float64:
                    downscaled_elevation = downscaled_elevation.astype(np.float64)
                downscaled_elevation[downscaled_elevation == src.nodata] = np.nan

            # プロットのセットアップ
            fig, ax = plt.subplots(figsize=(10, 8))

            # 画像の表示範囲を設定 (左経度, 右経度, 下緯度, 上緯度)
            bounds = src.bounds
            extent = [bounds.left, bounds.right, bounds.bottom, bounds.top]

            # 等高線を描画
            valid_data = downscaled_elevation[~np.isnan(downscaled_elevation)]
            if valid_data.size > 0:
                min_elev = np.nanmin(valid_data)
                max_elev = np.nanmax(valid_data)
                # 等高線の間隔を調整(例:200mごと)
                levels = np.arange(math.floor(min_elev / 200) * 200, math.ceil(max_elev / 200) * 200 + 200, 200)
            else:
                levels = None # 有効なデータがない場合は等高線を描画しない

            if levels is not None and len(levels) > 1:
                # 等高線プロット (背景のimshowは削除)
                contour_plot = ax.contour(
                    downscaled_elevation,
                    levels=levels,
                    cmap='terrain', # 地形に適したカラーマップ
                    linewidths=0.4, # 線の太さを0.8から0.4に変更
                    extent=extent,  # 地理的な範囲を設定
                    origin='upper'  # 画像の原点を左上に設定
                )
                # 等高線にラベルを追加
                # inline_spacingを大きくして、ラベルの表示数を減らす
                ax.clabel(contour_plot, inline=True, fontsize=8, fmt='%1.0f', inline_spacing=10)
            else:
                print("Warning: Not enough valid elevation data or levels to draw contours.")
               
            ax.set_aspect('equal') # アスペクト比を等しく設定

            # ax.imshow() を削除したため、背景は透明になります
            # 必要であれば、ax.set_facecolor('lightgray') などで単一の背景色を設定できます

            ax.set_title(f'Downscaled Elevation Data (Contour Map): {os.path.basename(filepath)}')
            ax.set_xlabel('Longitude')
            ax.set_ylabel('Latitude')
            # 等高線マップではカラーバーは必須ではないため、削除
            # fig.colorbar(im, ax=ax, label='Elevation (meters)')
            ax.grid(True, linestyle=':', alpha=0.7)
            fig.tight_layout()
           
            plt.show()

    except rasterio.errors.RasterioIOError as e:
        print(f"エラー: GeoTIFFファイル '{filepath}' を開けませんでした: {e}")
    except Exception as e:
        print(f"予期せぬエラーが発生しました: {e}")

# --- メイン実行ブロック ---
if __name__ == "__main__":
    # 結合されたGeoTIFFファイルが保存されているディレクトリ
    extracted_data_dir = '/content/all_unzip_files'

    # 結合されたGeoTIFFファイルのパス
    merged_elevation_filepath = os.path.join(extracted_data_dir, 'merged_elevation.tif')
   
    # カラーマップで標高データを表示
    print("--- カラーマップで標高データを表示 ---")
    plot_merged_elevation(merged_elevation_filepath)

    # 等高線マップで標高データを表示
    print("\n--- 等高線マップで標高データを表示 ---")
    plot_merged_elevation_contour(merged_elevation_filepath)



 次は、All parts of SumatraIslandのALOS_DEM_DataのGetにTryします。
 まず最初にALOSのHP(https://www.eorc.jaxa.jp/ALOS/aw3d/index.htm)からSmatraIslandのDEM_DataをPCにDownLoadしたあと、TheseFilesをGoogleDriveにUploadします。
 次に、GoogleDriveにUploadしたZipFileのUnzipOperationですが、これまではCode内にFilenameを1つずつWriteしていましたが、面倒くさいので、ALOS_DEM_Dataを取得する範囲をNorth-WestCornerとSouth-EastCounerのLogitude,Latitudeから、その中に含まれているはずのLongtudeとLatitudeそれぞれ5degreeごとにAutomaticにForRoopを使ってFilenameをCreateしておき、当該FilenemaがGoogleDrive上にあればUnzipOperationに繊維、当該FilenameがExitしないならそのFilenameをIgnore、skipするCodeをMasterGeminiにAsk for Creatingしました。

# 20250806_Latest version
# Automatically Create the zip filenames from subject area's north-west lon, lat and south-west lon, lat
import os
import zipfile
import math
from google.colab import drive

def generate_alos_zip_filenames(nw_lat, nw_lon, se_lat, se_lon):
    """
    指定された北西隅角と南東隅角の緯度経度に基づいて、
    該当するALOS 5x5タイルZIPファイルのファイル名を生成します。

    ALOS 5x5タイルZIPの命名規則は、SW_LAT_LON_NE_LAT_LON.zip形式です。
    例: N005E095_N010E100.zip は、緯度5N-10N、経度95E-100Eの範囲を示します。

    Args:
        nw_lat (float): 北西隅角の緯度 (例: 10.0)
        nw_lon (float): 北西隅角の経度 (例: 95.0)
        se_lat (float): 南東隅角の緯度 (例: 0.0)
        se_lon (float): 南東隅角の経度 (例: 100.0)

    Returns:
        list: 生成されたZIPファイル名のリスト。
    """
    zip_filenames = []

    # 5度グリッドの開始緯度・経度を計算
    # 緯度は南から北へ、経度は西から東へループ
    start_lat_grid = math.floor(se_lat / 5) * 5
    end_lat_grid = math.ceil(nw_lat / 5) * 5

    start_lon_grid = math.floor(nw_lon / 5) * 5
    end_lon_grid = math.ceil(se_lon / 5) * 5

    current_lat_grid = start_lat_grid
    while current_lat_grid < end_lat_grid:
        current_lon_grid = start_lon_grid
        while current_lon_grid < end_lon_grid:
            # 5x5ブロックの南西隅角
            sw_lat = current_lat_grid
            sw_lon = current_lon_grid

            # 5x5ブロックの北東隅角
            ne_lat = current_lat_grid + 5
            ne_lon = current_lon_grid + 5

            # ファイル名コンポーネントのフォーマット
            # 緯度: Nで北、Sで南。3桁でゼロ埋め。
            sw_lat_str = f"N{sw_lat:03d}" if sw_lat >= 0 else f"S{-sw_lat:03d}"
            ne_lat_str = f"N{ne_lat:03d}" if ne_lat >= 0 else f"S{-ne_lat:03d}"

            # 経度: Eで東、Wで西。3桁でゼロ埋め。
            sw_lon_str = f"E{sw_lon:03d}" if sw_lon >= 0 else f"W{-sw_lon:03d}"
            ne_lon_str = f"E{ne_lon:03d}" if ne_lon >= 0 else f"W{-ne_lon:03d}"

            zip_filename = f"{sw_lat_str}{sw_lon_str}_{ne_lat_str}{ne_lon_str}.zip"
            zip_filenames.append(zip_filename)

            current_lon_grid += 5
        current_lat_grid += 5

    return zip_filenames

def unzip_alos_data(zip_files_full_paths, output_dir):
    """
    指定されたZIPファイルのリストを解凍し、指定されたディレクトリにすべての内容を抽出します。
    ファイルは元のサブフォルダ構造を維持して保存されます。

    Args:
        zip_files_full_paths (list): 解凍するZIPファイルのフルパスのリスト。
        output_dir (str): 解凍したファイルを保存する出力ディレクトリのパス。
    """
    # 出力ディレクトリが存在しない場合は作成
    os.makedirs(output_dir, exist_ok=True)
    print(f"解凍先ディレクトリが作成されました: {output_dir}")

    # 各ZIPファイルを解凍
    for zip_file_path in zip_files_full_paths:
        try:
            with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:
                print(f"'{os.path.basename(zip_file_path)}' を解凍中...")
                # ZIPファイル内のディレクトリ構造を維持して解凍
                zip_ref.extractall(output_dir)
                print(f"'{os.path.basename(zip_file_path)}' を '{output_dir}' に正常に解凍しました。")
        except FileNotFoundError:
            print(f"エラー: ファイル '{zip_file_path}' が見つかりません。スキップします。")
        except zipfile.BadZipFile:
            print(f"エラー: ファイル '{zip_file_path}' は有効なZIPファイルではありません。スキップします。")
        except Exception as e:
            print(f"'{zip_file_path}' の解凍中に予期せぬエラーが発生しました: {e}。スキップします。")

    print("\n解凍処理が完了しました。")
    print(f"解凍先ディレクトリ '{output_dir}' の内容:")
    print(os.listdir(output_dir))


# --- メイン実行ブロック ---
if __name__ == "__main__":
    # Google Driveをマウント
    print("Google Driveをマウント中...")
    drive.mount('/content/drive')
    print("Google Driveのマウントが完了しました。")

    # --- 解凍したいエリアの緯度経度を入力 ---
    # 例: スマトラ島周辺の特定のエリア (N000E095_N005E100.zip と N005E095_N010E100.zip を含む範囲)
    # 北西隅角 (緯度, 経度)
    area_nw_lat = 10.0
    area_nw_lon = 95.0
    # 南東隅角 (緯度, 経度)
    area_se_lat = -10
    area_se_lon = 110.0

    print(f"\n指定されたエリア: 北西 ({area_nw_lat}N, {area_nw_lon}E) - 南東 ({area_se_lat}N, {area_se_lon}E)")

    # 該当するZIPファイル名を生成
    generated_zip_filenames = generate_alos_zip_filenames(
        area_nw_lat, area_nw_lon, area_se_lat, area_se_lon
    )

    if not generated_zip_filenames:
        print("指定されたエリアに該当するZIPファイル名が生成されませんでした。")
    else:
        print("\n生成されたZIPファイル名リスト:")
        for fname in generated_zip_filenames:
            print(f"- {fname}")

        # ZIPファイルが格納されているGoogle Drive上のディレクトリ
        google_drive_zip_dir = '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM'

        # 解凍するZIPファイルのフルパスのリストを作成
        zip_files_full_paths = [
            os.path.join(google_drive_zip_dir, fname) for fname in generated_zip_filenames
        ]

        # 解凍したファイルを保存する新しいディレクトリ
        output_directory = '/content/extracted_alos_data'

        # 関数を呼び出して解凍処理を実行
        unzip_alos_data(zip_files_full_paths, output_directory)



>>Output<<
Google Driveをマウント中...
Drive already mounted at /content/drive; to attempt to forcibly remount, call drive.mount("/content/drive", force_remount=True).
Google Driveのマウントが完了しました。

指定されたエリア: 北西 (10.0N, 95.0E) - 南東 (-10N, 110.0E)

生成されたZIPファイル名リスト:
- S010E095_S005E100.zip
- S010E100_S005E105.zip
- S010E105_S005E110.zip
- S005E095_N000E100.zip
- S005E100_N000E105.zip
- S005E105_N000E110.zip
- N000E095_N005E100.zip
- N000E100_N005E105.zip
- N000E105_N005E110.zip
- N005E095_N010E100.zip
- N005E100_N010E105.zip
- N005E105_N010E110.zip
解凍先ディレクトリが作成されました: /content/extracted_alos_data
エラー: ファイル '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM/S010E095_S005E100.zip' が見つかりません。スキップします。
'S010E100_S005E105.zip' を解凍中...
'S010E100_S005E105.zip' を '/content/extracted_alos_data' に正常に解凍しました。
'S010E105_S005E110.zip' を解凍中...
'S010E105_S005E110.zip' を '/content/extracted_alos_data' に正常に解凍しました。
エラー: ファイル '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM/S005E095_N000E100.zip' が見つかりません。スキップします。
'S005E100_N000E105.zip' を解凍中...
'S005E100_N000E105.zip' を '/content/extracted_alos_data' に正常に解凍しました。
'S005E105_N000E110.zip' を解凍中...
'S005E105_N000E110.zip' を '/content/extracted_alos_data' に正常に解凍しました。
'N000E095_N005E100.zip' を解凍中...
'N000E095_N005E100.zip' を '/content/extracted_alos_data' に正常に解凍しました。
'N000E100_N005E105.zip' を解凍中...
'N000E100_N005E105.zip' を '/content/extracted_alos_data' に正常に解凍しました。
エラー: ファイル '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM/N000E105_N005E110.zip' が見つかりません。スキップします。
'N005E095_N010E100.zip' を解凍中...
'N005E095_N010E100.zip' を '/content/extracted_alos_data' に正常に解凍しました。
エラー: ファイル '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM/N005E100_N010E105.zip' が見つかりません。スキップします。
エラー: ファイル '/content/drive/MyDrive/Colab Notebooks/20240805_ALOS_DEM/N005E105_N010E110.zip' が見つかりません。スキップします。

解凍処理が完了しました。
解凍先ディレクトリ '/content/extracted_alos_data' の内容:
['S005E105_N000E110', 'N000E100_N005E105', 'S010E105_S005E110', 'N000E095_N005E100', 'N005E095_N010E100', 'S010E100_S005E105', 'S005E100_N000E105']

 次に、それぞれのZipFilenameに基づいて別々のFolderに格納されたDataFileを新たに作成した1つのFolderに格納しなおします。このCodeもMasterGeminiにCreatしてもらいました。(別々のFolderに格納されたままだと、それぞれのFolderに必要なFileを探しに行かないといけないので面倒です。ですので、1つのFolderにまとめておいて、そのFolderの中だけを検索して必要なFileを取り出すようにしました。)
# 20250801_Update
# Collect Tile Files to one Folder
import os
import shutil

def move_files_from_subdirectories(source_dir, destination_dir):
    """
    指定されたソースディレクトリにあるサブディレクトリ内のすべてのファイルを、
    新しいデスティネーションディレクトリに移動します。

    Args:
        source_dir (str): 移動元のルートディレクトリのパス。
        destination_dir (str): 移動先のディレクトリのパス。
    """
    # 移動先ディレクトリが存在しない場合は作成
    os.makedirs(destination_dir, exist_ok=True)
    print(f"Destination directory created at: {destination_dir}")

    # ソースディレクトリ内のファイルとフォルダをリストアップ
    for item in os.listdir(source_dir):
        source_path = os.path.join(source_dir, item)

        # サブディレクトリのみを対象にファイルを移動
        if os.path.isdir(source_path):
            print(f"Processing subdirectory: {source_path}")
            # サブディレクトリ内のファイルをすべてリストアップ
            for filename in os.listdir(source_path):
                file_path = os.path.join(source_path, filename)
                if os.path.isfile(file_path):
                    # 移動先に同じファイル名が存在しないか確認
                    dest_path = os.path.join(destination_dir, filename)
                    if os.path.exists(dest_path):
                        print(f"Warning: File '{filename}' already exists in the destination. Skipping.")
                        continue

                    # ファイルを移動
                    try:
                        shutil.move(file_path, destination_dir)
                        print(f"Moved file: {file_path} -> {destination_dir}")
                    except Exception as e:
                        print(f"Error moving file {file_path}: {e}")

            # ファイルを移動した後に空になったサブディレクトリを削除
            try:
                os.rmdir(source_path)
                print(f"Removed empty directory: {source_path}")
            except OSError as e:
                print(f"Error removing directory {source_path}: {e}")
        elif os.path.isfile(source_path):
            # ソースディレクトリ直下のファイルも移動
            print(f"Processing file: {source_path}")
            dest_path = os.path.join(destination_dir, item)
            if os.path.exists(dest_path):
                print(f"Warning: File '{item}' already exists in the destination. Skipping.")
                continue

            try:
                shutil.move(source_path, destination_dir)
                print(f"Moved file: {source_path} -> {destination_dir}")
            except Exception as e:
                print(f"Error moving file {source_path}: {e}")

    print("\nFile moving process completed.")
    print(f"Content of the new directory '{destination_dir}':")
    print(os.listdir(destination_dir))
    print(f"Content of the original directory '{source_dir}':")
    print(os.listdir(source_dir))


# --- メイン実行ブロック ---
if __name__ == "__main__":
    # ZIP解凍で生成されたファイルが格納されているディレクトリ
    source_directory = '/content/extracted_alos_data'

    # 移動先の新しいディレクトリ名
    new_directory_name = 'all_unzip_files'

    # 新しいディレクトリのフルパス
    destination_directory = os.path.join('/content', new_directory_name)

    # 関数を呼び出してファイル移動処理を実行
    move_files_from_subdirectories(source_directory, destination_directory)


 このFolderの中にあるFileからDEM_Data_FileであるFilenameの末尾が‘DSM.tif’となっているものを全てTakeOutしたうえで、それらのFileのDEM_DataをMargeして大きなDEM_Modelを作成します。このCodeももちろんMasterGeminiのSuggestionです。
# 20250806_Update
# recognize automatcally '***DSM.tif' files
import rasterio
import os
import numpy as np
from rasterio.enums import Resampling
from rasterio.merge import merge

def merge_alos_tiles(tile_dir, output_filepath):
    """
    指定されたディレクトリ内の末尾が'DSM.tif'のすべてのALOS GeoTIFFファイルを読み込み、結合し、新しいファイルとして保存します。

    Args:
        tile_dir (str): GeoTIFFファイルが格納されているディレクトリのパス。
        output_filepath (str): 結合されたGeoTIFFファイルの出力パス。
    Returns:
        str: 結合されたGeoTIFFファイルのパス (成功した場合)、またはNone (失敗した場合)。
    """
    src_files_to_mosaic = []

    # ディレクトリ内を検索して、末尾が'DSM.tif'のファイルを見つける
    specific_tile_filenames = [f for f in os.listdir(tile_dir) if f.endswith('DSM.tif')]

    # 指定されたファイル名リストをループしてファイルを開く
    for filename in specific_tile_filenames:
        filepath = os.path.join(tile_dir, filename)
        if not os.path.exists(filepath):
            print(f"Warning: Specified file '{filepath}' does not exist. Skipping.")
            continue

        try:
            src_files_to_mosaic.append(rasterio.open(filepath))
        except rasterio.errors.RasterioIOError as e:
            print(f"Warning: Could not open {filepath} (possibly corrupted or not a valid GeoTIFF): {e}. Skipping.")
        except Exception as e:
            print(f"Warning: Unexpected error opening {filepath}: {e}. Skipping.")

    if not src_files_to_mosaic:
        print("No valid GeoTIFF tile files found to merge from the specified list. Exiting.")
        return None

    print(f"Merging {len(src_files_to_mosaic)} tiles...")

    # Merge the datasets
    mosaic, out_transform = merge(src_files_to_mosaic, resampling=Resampling.nearest)

    # Get metadata from the first source file and update with merged properties
    out_meta = src_files_to_mosaic[0].meta.copy()
    out_meta.update({
        "driver": "GTiff",
        "height": mosaic.shape[1],
        "width": mosaic.shape[2],
        "transform": out_transform,
        "crs": src_files_to_mosaic[0].crs,
        "nodata": src_files_to_mosaic[0].nodata
    })

    # Close all source files
    for src in src_files_to_mosaic:
        src.close()

    # Save the merged mosaic to a new GeoTIFF file
    try:
        with rasterio.open(output_filepath, "w", **out_meta) as dest:
            dest.write(mosaic)
        print(f"Successfully merged tiles to '{output_filepath}'.")
        return output_filepath
    except Exception as e:
        print(f"Error saving merged GeoTIFF: {e}")
        return None

# --- Main Execution Block ---
if __name__ == "__main__":
    # Define the directory where GeoTIFF files are extracted
    extracted_data_dir = '/content/all_unzip_files'

    # Define the output path for the merged GeoTIFF file in Google Colab's file system
    output_merged_filepath = os.path.join(extracted_data_dir, 'merged_elevation.tif')

    print("Starting GeoTIFF tile merging process...")
    # 関数からselected_filenames引数を削除
    merged_file_path = merge_alos_tiles(extracted_data_dir, output_merged_filepath)

    if merged_file_path:
        print(f"\nSuccessfully merged all tiles. The merged file is saved to your Google Colab file system at: {merged_file_path}")
    else:
        print("GeoTIFF file merging failed.")


 これでスマトラ島全体のALOSの30mResolutionのDigitalElevationDataをGetすることができました。これをMatplotlibでPlotすると次のような画像が得られました。




コメント