rasterioとgeopandasを使用してラスターをクロップする


8

歴史的な航空写真を切り抜いています。これらの写真は、端に大きな黒い領域があります(値0)。ただし、値が0の有効なデータもあります。私が使用しているワークフローは:

  1. rasterioでラスターを読み込む
  2. rasterio.features.shapes()を使用してラスターをポリゴン化します
  3. 値が0でサイズが5000平方メートルを超えるポリゴンを特定する
  4. 元の画像をポリゴンでマスクし、反転マスクを実行します

これが単一の画像をマスクするための私の現在のコードです:

import rasterio
from rasterio import features
from rasterio import mask
import json
import geopandas as gpd

results = []
final_results = []

with rasterio.open(r"C:\1927_oahu\tif\_Line1_6to8_0.tif") as src:
    src_meta = src.meta
    src_affine = src_meta.get("transform")

    band = src.read(1)

    for geometry, raster_value in features.shapes(band, transform=src_affine):
        if raster_value == 0:
        result = {'properties': {'raster_value': raster_value}, 'geometry': geometry}
        results.append(result)

gpd_results = gpd.GeoDataFrame.from_features(results)

gpd_results["area"] = gpd_results["geometry"].area

gpd_results_filtered = gpd_results[gpd_results["area"] > 5000]

gpd_filtered_json_str = gpd_results_filtered.to_json()

gpd_filtered_json_dict = json.loads(gpd_filtered_json_str)

for k, v in gpd_filtered_json_dict.iteritems():
    if k == "features":
        for items in v:
            #final_results = {"coordinates": (items.get("geometry").get("coordinates"))}
            final_results = {"geometry": (items.get("geometry").get("coordinates"))}

masked_band, masked_transform = mask.mask(src, final_results, invert=True)

src_meta.update(dtype=rasterio.uint8, nodata=0)
with rasterio.open(os.path.join(r"C:\1927_oahu_output", "out.tif"), 'w', **src_meta) as dst:
    dst.write_band(1, masked_band.astype(rasterio.uint8))

このコードを実行すると、次のエラーが表示されます。 AttributeError: 'str' object has no attribute 'get'

rasterio.maskドキュメントの状態:ポリゴンは、保持するラスタのフィーチャの境界を指定するGeoJSONのような辞書です。指定されたポリゴン以外のすべてのデータはnodataに設定されます。

私はrasterio.maskに間違ったタイプの "GeoJSON-like dict"を与えていると想定しています。私は成功することなくいくつかの方法でdictを再フォーマットしようとしました。誰かがGeoJSONを「GeoJSONのような辞書」に変換する正しい方法を知っていますか?

または、「GeoJSONのようなdict」の正しい形式を提供できますか?

私はラスタリオとジオパンダが初めてです。

回答:


6

この問題は解決されました。問題は、ドキュメントを誤って読んだことです。2回目の読み取りでは、rasterio.maskのドキュメントに、ポリゴンはGeoJSONに似たディクトリストである必要があることが明記されています。私はこの回答からそれらのリストを生成する次のコードスニペットを見つけました:

geoms = [feature["geometry"] for feature in shapefile]

これが機能している完全なコードです:

import rasterio
from rasterio import features
from rasterio import mask
import json
import geopandas as gpd
import os

results = []
final_results = []

with rasterio.open(r"C:\1927_oahu\tif\_Line1_6to8_0.tif") as src:
    src_meta = src.meta.copy()
    src_affine = src_meta.get("transform")

    band = src.read(1)

    for geometry, raster_value in features.shapes(band, transform=src_affine):
        if raster_value == 1:
            result = {'properties': {'raster_value': raster_value}, 'geometry': geometry}
            results.append(result)

        gpd_results = gpd.GeoDataFrame.from_features(results)

        gpd_results["area"] = gpd_results["geometry"].area

        gpd_results_filtered = gpd_results[gpd_results["area"] > 5000]

        gpd_filtered_json_str = gpd_results_filtered.to_json()

        gpd_filtered_json_dict = json.loads(gpd_filtered_json_str)

        final_results = [feature["geometry"] for feature in gpd_filtered_json_dict["features"]]

        masked_band, masked_transform = mask.mask(src, final_results, invert=True)

        masked_band[masked_band > 255] = 0

        src_meta.update(dtype=rasterio.uint8, height=int(masked_band.shape[1]), width=int(masked_band.shape[2]), nodata=0, transform=masked_transform, compress='lzw')

        with rasterio.open(r"C:\1927_oahu\output\_Line1_6to8_0.tif"), 'w', **src_meta) as dst:
                dst.write(masked_band.astype(rasterio.uint8))   
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.