Schneiden Sie ein Raster mit Rasterio und Geopandas

8

Ich beschneide eine Reihe historischer Luftbilder. Diese Fotos haben große schwarze Bereiche an den Rändern (Wert 0). Es gibt jedoch auch gültige Daten mit einem Wert von 0. Der Workflow, den ich verwende, ist:

  1. Laden Sie das Raster mit Rasterio
  2. Polygonisieren Sie das Raster mit rasterio.features.shapes ()
  3. Identifizieren Sie Polygone mit einem Wert von 0 und einer Größe von> 5000 Quadratmetern
  4. Maskieren Sie die Originalbilder mit Polygonen und führen Sie eine invertierte Maske durch

Hier ist mein aktueller Code zum Maskieren eines einzelnen Bildes:

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))

Wenn ich diesen Code ausführe, wird folgende Fehlermeldung angezeigt: AttributeError: 'str' object has no attribute 'get'

In der Dokumentation zu rasterio.mask heißt es: Polygone sind GeoJSON-ähnliche Diktate, die die Grenzen der Features im Raster angeben , die beibehalten werden sollen. Alle Daten außerhalb der angegebenen Polygone werden auf nodata gesetzt.

Ich gehe davon aus, dass ich rasterio.mask die falsche Art von "GeoJSON-ähnlichem Diktat" gebe. Ich habe versucht, das Diktat auf verschiedene Weise neu zu formatieren, ohne Erfolg. Kennt jemand den richtigen Weg, um GeoJSON in ein "GeoJSON-ähnliches Diktat" umzuwandeln?

Oder kann jemand das richtige Format eines "GeoJSON-ähnlichen Diktats" angeben?

Ich bin neu in Rasterio und Geopandas.

Rosswin
quelle

Antworten:

6

Das Problem ist behoben. Das Problem war, dass ich die Dokumentation falsch gelesen habe. Beim zweiten Lesen wird in der Dokumentation zu rasterio.mask klar angegeben, dass Polygone eine Liste von GeoJSON-ähnlichen Diktaten sein sollten. Ich habe den folgenden Codeausschnitt gefunden, um diese Listen aus dieser Antwort zu generieren :

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

Hier ist der vollständige Code, der funktioniert:

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))   
Rosswin
quelle