Lees ons artikel over

.

Een stap-voor-stap handleiding voor het verzamelen en voorbewerken van satellietbeelden data voor algoritmen voor machinaal leren

Dit artikel is het eerste deel van een 2-delige serie over het gebruik van algoritmen voor machinaal leren op satellietbeelden. Hier zullen we ons richten op de stappen van de data verzameling en voorbewerking, terwijl het tweede deel het gebruik van verschillende algoritmen voor machinaal leren zal laten zien.

TL;DR
Dit artikel zal:

  • U een beter inzicht geven in satellietbeelden
  • Laten zien welk type beeldmateriaal open source kan worden verzameld
  • U door de noodzakelijke stappen leiden om “machine learning-klare” afbeeldingen te hebben

    We zullen de detectie en classificatie van landbouwvelden als voorbeeld gebruiken. Python en jupyter notebook worden gebruikt voor de voorbewerkingsstappen. De jupyter-notebook voor het reproduceren van de stappen is beschikbaar op github.
    Dit artikel gaat uit van basiskennis van data wetenschap en python.

  • Computer vision is een fascinerende tak van machinaal leren die zich de afgelopen jaren snel heeft ontwikkeld. Met openbare toegang tot veel bibliotheken met algoritmen (Tensorflow, OpenCv, Pytorch, Fastai ...) evenals open source datasets (CIFAR -10, Imagenet, IMDB ...) is het heel gemakkelijk voor een data wetenschapper om praktijkervaring met dit onderwerp op te doen.

    Maar wist u dat u ook toegang kunt krijgen tot open source satellietbeelden? Dergelijke beelden kunnen in een groot aantal toepassingen gebruikt worden (Landbouw, Logistiek, Energie ...). Ze bieden echter extra uitdagingen voor een data wetenschapper vanwege hun omvang en complexiteit. Ik heb dit artikel geschreven om enkele van mijn belangrijkste ervaringen te delen.

    Stap 1 - Selecteer de satelliet open data bron

    Eerst moet u kiezen welke satelliet u wilt gebruiken. De belangrijkste kenmerken waar u hier op moet letten zijn :

    • Ruimtelijke resolutie: hoeveel meter er per pixel bedekt wordt, zal een hogere resolutie sommige gebruikssituaties ontsluiten en betere prestaties geven voor de meeste algoritmen.

    • Beschikbare instrumentenDe instrumenten vangen verschillende spectrale banden op, zowel van het zichtbare als van het onzichtbare spectrum. De bruikbaarheid van deze banden hangt af van de toepassing.

    • Temporele resolutie Tijd tussen twee bezoeken aan een bepaalde plek op aarde. Merk op dat veel satellietsystemen in feite meerdere satellieten omvatten en dat in dat geval de globale temporele resolutie meestal gelijk is aan die van een van de satellieten gedeeld door het aantal satellieten.

    • Radiometrische resolutie : het aantal mogelijke waarden dat het instrument vastlegt. Hoe hoger, hoe nauwkeuriger de metingen zijn.

    Hier zijn satellieten waarvan de data gratis beschikbaar zijn:

    Benchmark van satellietsystemen

    Aangezien het ons doel is om landbouwgewassen te detecteren en te identificeren, zou het zichtbare spectrum (dat gebruikt wordt om standaard kleurenbeelden te leveren) heel nuttig moeten zijn. Bovendien zijn er correlaties tussen het stikstofniveau van gewassen en NIR-spectrumbanden (nabij infrarood). Wat de gratis opties betreft, is Sentinel 2 momenteel de beste wat resolutie betreft met 10 m voor die spectrale banden, dus gaan we deze satelliet gebruiken.

    Natuurlijk is een resolutie van 10 m veel lager dan de allernieuwste satellietbeelden met commerciële satellieten die een resolutie van 30 cm bereiken. Toegang tot commerciële data-satellieten kan veel gebruikssituaties ontsluiten, maar ondanks de toenemende concurrentie met nieuwe spelers die deze markt betreden, blijven ze hoog geprijsd en dus moeilijk te integreren in een gebruikssituatie op schaal.

    Stap 2 - Verzamel de satellietbeelden data van Sentinel 2

    Nu we onze satellietbron hebben geselecteerd, is de nieuwe stap het downloaden van de beelden. Sentinel 2 maakt deel uit van het Copernicus-programma van de Europees Ruimteagentschap. We hebben toegang tot de data met de SentinelSat python API.

    We moeten eerst een account aanmaken bij de Copernicus Open Toegang Hub. Merk ook op dat deze website een manier biedt om afbeeldingen met een GUI te bevragen.

    Een manier om de zones die u wilt verkennen op te geven, is door de API te voorzien van een geojson-bestand, wat een json is die de positie van de GPS-coördinaten (breedtegraad en lengtegraad) van een zone bevat. Geojson kan hier snel worden aangemaakt website.

    Op deze manier kunt u alle satellietbeelden opvragen die de opgegeven zone doorsnijden.

    Hier geven we een lijst van alle afbeeldingen die beschikbaar zijn op een voor een bepaalde zone en tijdsbereik:

    api = SentinelAPI(
    referenties[“gebruikersnaam”],
    referenties[“wachtwoord”],
    “https://scihub.copernicus.eu/dhus”
    )

    shape = geojson_to_wkt(read_geojson(geojson_path))

    afbeeldingen = api.query(
    vorm,
    date=(date(2020, 5, 1), date(2020, 5, 10)),
    platformname=”Sentinel-2″,
    verwerkingsniveau = “Niveau-2A”,
    cloudbedekkingspercentage=(0, 30)
    )

    images_df = api.to_dataframe(images)

    Let op het gebruik van argumenten:

    • datum: dit bereik moet worden ingesteld met de temporele resolutie van 6 dagen in gedachten. Aangezien we gewassen gaan detecteren, stellen we het in op een periode vóór de oogst

    • verwerkingsniveau : Niveau-2A is het meest geavanceerde niveau van voorbewerking. Er zijn bijvoorbeeld al atmosferische correcties uitgevoerd op de beelden (om dieper in te gaan op de verwerkingsniveaus)

    • cloudbedekkingspercentage : Wolken maken sommige beelden moeilijk te exploiteren. Wij filteren beelden met meer dan 30 % omdat deze waarschijnlijk onbruikbaar zijn.

    afbeeldingen_df

    Images_df is een pandas dataframe dat alle afbeeldingen bevat die overeenkomen met onze zoekopdracht. We selecteren er een met een lage cloud dekking en downloaden deze met behulp van de api :

    uuid = “01d97f6b-8eb5-4edc-9261-10e3f4d437d0”.”
    api.download(uuid)

    Stap 3 - Begrijpen welke spectrale banden u moet gebruiken en kwantisatie beheren

    Zodra het zipbestand is gedownload, kunnen we zien dat het eigenlijk meerdere afbeeldingen bevat.

    Dit komt omdat, zoals we in stap 1 al zeiden, Sentinel 2 veel spectrale banden vastlegt en niet alleen rood, groen en blauw, en elke band in één beeld wordt vastgelegd.

    Ook hebben de instrumenten niet allemaal dezelfde ruimtelijke resolutie, dus is er een submap voor elke verschillende resolutie 10, 20 en 60 meter.

    Als we de GRANULE//IMG_DATA map zien we dat er een submap is voor elke verschillende resolutie: 10, 20 en 60 meter als de spectrale banden. We gaan die met de maximale resolutie van 10 m gebruiken, omdat deze band 2, 3, 4 en 8 bieden, die blauw, groen, rood en NIR zijn. Band 7, 8 en 9, die de rode rand van de vegetatie vormen (spectrale banden tussen rood en NIR die een overgang in reflectiewaarde voor vegetatie markeren), zouden ook interessant kunnen zijn voor het detecteren van gewassen, maar omdat ze een lagere resolutie hebben, laten we deze nu buiten beschouwing.

    Hier laden we elke band als een 2D numpy matrix:

    def get_band(image_folder, band, resolutie=10):
    subfolder = [f for f in os.listdir(image_folder + "/GRANULE") if f[0] == "L"][0] image_folder_path = f"/GRANULE//IMG_DATA/Rm"
    image_files = [im for im in os.listdir(image_folder_path) if im[-4:] == ".jp2"] geselecteerd_bestand = [im for im in image_files if im.split("_")[2] == band][0]

    met rasterio.open(f"/") als infile:
    img = infile.read(1)

    retourneer img

    band_dict =

    voor band in ["B02", "B03", "B04", "B08"]:
    band_dict[band] = get_band(image_folder, band, 10)

    Een snelle test om er zeker van te zijn dat alles werkt, is proberen om de afbeelding in ware kleur (d.w.z. RGB) opnieuw te maken en weer te geven met opencv en matplotlib:

    img = cv2.merge((band_dict[“B04”], band_dict[“B03”], band_dict[“B02”]))
    plt.imshow(img)

    Satellietbeeld - Probleem met kleurintensiteit (Copernicus Sentinel data 2020)

    Er is echter een probleem met de kleurintensiteit. Dit komt doordat de kwantisatie (aantal mogelijke waarden) afwijkt van de standaard voor matplotlib, die uitgaat van een 0-255 int-waarde of een 0-1 float-waarde. Standaardafbeeldingen gebruiken vaak een 8-bits kwantisatie (256 mogelijke waarden), maar Sentinel 2-afbeeldingen gebruiken een 12-bits kwantisatie en een herbewerking converteert de waarden naar een 16-bits geheel getal (65536 waarden).

    Als we een 16-bits geheel getal willen schalen naar een 8-bits geheel getal, moeten we in theorie delen door 256, maar dit resulteert in een erg donkere afbeelding omdat niet het hele bereik van mogelijke waarden wordt gebruikt. De maximumwaarde in onze afbeelding is in feite 16752 van de 65536 en er zijn maar weinig pixels die waarden hoger dan 4000 bereiken, dus delen door 8 geeft een afbeelding met een behoorlijk contrast.

    img_verwerkt = img / 8
    img_verwerkt = img_verwerkt.astype(int)
    plt.imshow(img_bewerkt)

    Satellietbeeld - Kleurintensiteit rechts (Copernicus Sentinel data 2020)

    We hebben nu een 3-dimensionale tensor van de vorm (10980, 10980, 3) van 8-bits gehele getallen in de vorm van een numpy array

    Merk op dat :

    • We zouden nog verder kunnen gaan door een niet lineaire schalingsmethode te gebruiken om het contrast te verbeteren.

    • Casting als geheel getal komt neer op het afronden van de waarde, dus we verliezen eigenlijk wat informatie. Dit is prima voor veel gebruikssituaties en verbetert de verwerkingssnelheid, maar als precisie belangrijk is, is het misschien beter om de reflectiewaarde om te zetten naar een 0-1 float (een formaat dat ook door de meeste ML-bibliotheken wordt beheerd) in plaats van een 0-255 geheel getal.

    • Voorlopig laten we de NIR-spectrumband buiten beschouwing. Dit zal ons helpen om sneller te testen, omdat veel algoritmen uit de winkel beelden met 3 kleurkanalen verwachten. Maar het zou interessant kunnen zijn om deze band op een gegeven moment opnieuw te integreren, hetzij door een van de andere kanalen te vervangen, hetzij door algoritmen zo aan te passen dat ze 4 kleurkanalen verwachten.

    Stap 4 - Splits de afbeeldingen op tot machine-learningklare formaten

    We zouden kunnen proberen om een algoritme op onze huidige afbeelding toe te passen, maar in de praktijk zou dat met de meeste technieken niet werken vanwege de grootte. Zelfs met veel rekenkracht zouden de meeste algoritmen (en vooral deep learning) niet werken.

    We moeten de afbeelding dus in fragmenten opsplitsen. Een vraag is hoe we de grootte van het fragment kunnen instellen.

    • Kleine fragmenten zullen de prestaties verbeteren.

    • Grotere fragmenten verminderen het aantal objecten dat moeilijk te detecteren zal zijn omdat ze in meerdere afbeeldingen zijn opgesplitst. Te grote fragmenten kunnen echter een probleem vormen voor sommige ML-algoritmen die afbeeldingen herschalen of die niet goed kunnen schalen voorbij een bepaald aantal objecten in een gegeven afbeelding.

    We besluiten om elke afbeelding op te splitsen in een raster van 45 * 45 (45 is gemakshalve een deler van 10980)

    Voorbij deze parameterbepaling is deze stap rechttoe rechtaan met behulp van numpy arraymanipulatie . We slaan onze waarden op in een dict met (x, y) tupels als sleutels.

    frag_count = 45
    frag_size = int(img_processed.shape[0] / frag_count)
    frag_dict =

    voor y, x in itertools.product(range(frag_count), range(frag_count)):
    frag_dict[(x, y)] = img_processed[y*frag_size: (y+1)*frag_size,
    x*frag_size: (x+1)*frag_size, :]

    plt.imshow(frag_dict[(10, 10)])

    Fragment van het satellietbeeld (Copernicus Sentinel data 2020)

    Stap 5 - Koppel uw data aan de satellietbeelden met behulp van GPS-naar-UTM conversie

    Tot slot moeten we onze afbeeldingen koppelen aan de data die we hebben over landbouwvelden om een gesuperviseerde machine-learningbenadering mogelijk te maken. In ons geval hebben we data op landbouwvelden in de vorm van een lijst met GPS-coördinaten (breedtegraad, lengtegraad), vergelijkbaar met de geojson die we in stap 2 hebben gebruikt, en we willen hun pixelpositie kunnen vinden. Voor de duidelijkheid zal ik echter eerst een pixelomzetting naar GPS-coördinaten laten zien en daarna het omgekeerde

    De metadata die verzameld is tijdens het opvragen van de SentinelSat API geeft de GPS-coördinaten van de hoeken van de afbeelding (footprint kolom) en wij willen de coördinaten van een specifieke pixel. Breedtegraad en lengtegraad, die hoekwaarden zijn, evolueren niet lineair binnen een afbeelding, dus we kunnen geen eenvoudige verhouding maken door de pixelpositie te gebruiken. Er zijn manieren om dit op te lossen met wiskundige vergelijkingen, maar er bestaan al kant-en-klare oplossingen in python.

    Een snelle oplossing is om de pixelpositie te converteren naar UTM (Universal Transverse Mercator), waarin een positie wordt gedefinieerd door een zone en een (x, y) positie (in meter-eenheid) die lineair met de afbeelding evolueert. We kunnen dan een UTM-naar- breedtegraad/lengtegraad conversie gebruiken die in de utm-bibliotheek beschikbaar is. Om dit te doen, moeten we eerst de UTM-zone en positie van de linkerbovenhoek van de afbeelding verkrijgen. Deze kunnen gevonden worden in de metadata van de afbeelding in ware kleur.

    #Obevattend meatadata
    transform = rasterio.open(tci_file_path, driver=’JP2OpenJPEG’).transform
    zone_nummer = int(tci_file_path.split(“/”)[-1][1:3])
    zone_letter = tci_file_path.split(“/”)[-1][0] utm_x, utm_y = transform[2], transform[5]

    # Pixelpositie omzetten naar utm
    oost = utm_x + pixel_kolom * 10
    noorden = utm_y + pixel_row * - 10

    # UTM omrekenen naar breedtegraad en lengtegraad
    breedtegraad, lengtegraad = utm.to_latlon(east, north, zone_nummer, zone_letter)

    De omzetting van GPS-positie naar pixel wordt gedaan met behulp van de omgekeerde formules. In dat geval moeten we ervoor zorgen dat de verkregen zone overeenkomt met onze afbeelding. Dit kan gedaan worden door de zone op te geven. Als ons object niet in de afbeelding aanwezig is, zal dit resulteren in een pixelwaarde die buiten de grenzen valt.

    # Breedtegraad en lengtegraad omrekenen naar UTM
    oost, noord, zone_nummer, zone_letter = utm.from_latlon(
    breedtegraad, lengtegraad, force_zone_number=zone_number
    )

    # UTM omzetten naar kolom en rij
    pixe_column = rond((oost - utm_x) / 10)
    pixel_row = rond((noord - utm_y) / -10)
    rauw bekijken

    Conclusie

    We zijn nu klaar om de satellietbeelden te gebruiken voor machinaal leren!

    In het volgende artikel van deze 2-delige serie zullen we zien hoe we die afbeeldingen kunnen gebruiken om veldoppervlakken te detecteren en classificeren met behulp van zowel supervised als unsupervised machine learning.

    Bedankt voor het lezen en aarzel niet om volg de Artefact tech blog als u op de hoogte wilt worden gebracht wanneer dit volgende artikel uitkomt!

    U kunt meer over ons en onze projecten vinden op onze Medium blog