Zo verwerk je stereofoto’s met RealityScan

Sinds een tijdje zijn ook de stereofoto’s van het Landelijk Beeldmateriaal als open data via de Dataroom voor iedereen te downloaden. Waar voorheen alleen de orthofoto’s als open data beschikbaar waren, kan nu iedereen zelf ook 3D data uit deze foto’s genereren. Mede door de populariteit van dronefotografie zijn er veel opties voor verwerkingssoftware – van open source programma’s zoals COLMAP via populaire commerciële opties zoals Pix4D en Agisoft Metashape tot high-end software als Trimble Inpho met het desbetreffende prijskaartje.

Ik heb ervoor gekozen om RealityScan (voorheen RealityCapture) van Epic Games te gebruiken. Deze is vrij snel, kan ook met grote foto’s overweg, en is voor organisaties met minder dan US$ 1 miljoen omzet per jaar gratis te gebruiken.

Download foto’s

Op het dataportaal zijn er diverse opties om foto’s te selecteren – bijv. voor een hele provincie of gemeente, maar ook voor een specifiek adres. In het vervolg kun je kiezen uit AHN of Beeldmateriaal (daar gaan we dus nu voor) en krijg je keuze uit de voorjaarsvlucht (ong. 7,5cm resolutie) en de zomervlucht (ong. 25cm resolutie). Dan is het nog kiezen tussen voor het jaartal (op het moment van het schrijven van dit artikel is voor de regio Rotterdam de data van 2025 nog niet beschikbaar, dus wordt het 2024) en ortho- of stereofoto’s (uiteraard het laatste). Uiteindelijk krijg je een overzicht van de beschikbare data en de grootte van de download, voor de gemeente Maassluis ruim 6GB:

 

Tot de download behoren niet alleen de foto’s in TIFF-formaat, maar ook metadata zoals kalibratierapporten en een tekstbestand met de uitwendige oriëntatie.

Import in RealityScan

RealityScan gebruikt een Ribbon interface dat telkens alleen de relevante knoppen voor een bepaalde taak toont. Vanuit Workflow kun je de meeste stappen oproepen, waaronder de import van foto’s:

Via Application – Settings kun je trouwens het te gebruiken coördinatenstelsel instellen. Voor RD/NAP is dat niet EPSG:28992 (dat is een 2D stelsel), maar EPSG:7415.

Via Flight Log kun je de bekende uitwendige oriëntatie van de foto’s importeren. Coördinaten zijn makkelijk, oriëntatiehoeken leveren helaas bijna altijd gedoe op omdat verschillende conventies gebruikt worden. RealityScan verwacht roll/pitch/yaw hoeken, geen omega/phi/kappa. Aan het einde van deze post is een Python script te vinden dat deze conversie kan doen. Na het matchen van de foto’s resulteren andere hoeken, hier heb ik geen verklaring voor. Na de import krijg je een melding dat niet alle foto’s gevonden konden worden, deze kun je gerust negeren.

Je kunt bij de instellingen ook cameraparameters en kalibratiewaarden instellen. Helaas verwacht RealityScan het 35mm-equivalente brandpuntsafstand in plaats van het daadwerkelijke brandpuntsafstand en de pixelgrootte (die in het kalibratierapport te vinden zijn), ik heb daarom alles op Unknown laten staan.

Alignment

Nu zou je met Start het gehele proces kunnen opstarten, maar voor meer controle is het handiger om de stappen los van elkaar te doen. Met Align images worden de foto’s uitgelijnd. De eerste keer betekent dit dat eerst features gedetecteerd moeten worden, dit kan afhankelijk van het aantal foto’s en de snelheid van de computer even duren.

Zoals ik al schreef was RealityScan het niet helemaal eens met de geïmporteerde oriëntatiehoeken, wat helaas ook betekende dat de resultaten niet helemaal op de goede plek lagen. Het is daarom zinvol een aantal paspunten te gebruiken. De coördinaten hiervan kun je vrij eenvoudig in QGIS met behulp van de orthofoto van het landelijk beeldmateriaal en AHN hoogtegrids bepalen.

Voor het toevoegen gebruik je in de objectenboom onder Control points de functie Create. Het type staat in eerste instantie op Tie point (Verbindingspunt), deze kun je gebruiken om handmatig verbindingspunten tussen foto’s te maken. Door het type te wijzigen naar Ground control kun je coördinaten en de bijbehorende nauwkeurigheid invoeren. Het is uiteraard ook mogelijk om een lijst met paspunten te importeren.

Als de foto’s al uitgelijnd zijn stelt RealityScan zelf posities voor de paspunten voor in alle foto’s die een paspunten zouden moeten kunnen zien. Deze kunnen definitief gemaakt worden door de marker te verplaatsen of op de groene plus te klikken. Als daarna Align images opnieuw uitgevoerd wordt, worden de paspunten in de blokvereffening meegenomen.

3D reconstructie

Als het uitlijnen van de foto’s en daarmee het berekenen van de cameraposities en -oriëntaties naar tevredenheid is gebeurd kan de 3D reconstructie uitgevoerd worden. Standaard wordt deze voor het gehele gebied uitgevoerd, maar mogelijk is alleen een kleiner gebied relevant en kan veel rekentijd bespaard worden door een kleiner gebied met Set Reconstruction Region in te stellen. Daarna volgen deze stappen:

  • Model berekenen (onder Mesh Model – Create Model). Hier zijn verschillende detailniveaus mogelijk.
  • Mesh inkleuren. Colorize levert één kleur voor elk driehoek, Texture berekend texturen en levert daardoor een mooier resultaat.
  • Export van het resultaat. Er zijn veel verschillende mesh formaten, maar ook puntenwolken in bijv. LAS formaat kunnen aangemaakt worden.

Nog een korte uitleg over de weergave in RealityScan: Met de bovenste rij knoppen naast het RealityScan logo kan ingesteld worden hoeveel vensters getoond worden. Elk venster kan met het kleine knopje rechts bovenaan in een andere modus gezet worden:

  • 1D: instellingen in tabelvorm
  • 2D: 2D weergave van foto’s
  • 3D: 3D weergave van resultaten

Voor een 3D weergave kunnen onder Scene 3D – VIEW verdere instellingen gedaan worden, zoals de weergave van paspunten (GCPs) en de weergave van punten (Vertices) of driehoeken (Solid/Sweet).

Het 3D model kan in verschillende bestandsformaten geëxporteerd worden.

Orthofoto

Naast 3D meshes en puntenwolken kan RealityScan ook orthofoto’s berekenen en exporteren. Deze functie is te vinden onder Workflow – Ortho Projection. Voor een orthofoto uit luchtfotos is het juiste type Top en, als een getextureerd model is berekend, bij Rendering method de keuze True ortho from a textured model. De pixelgrootte kan handmatig ingesteld of de optimale resolutie automatisch berekend worden, met Render wordt de ortho aangemaakt. Hierna kan deze als TIFF geëxporteerd worden.

Twee aandachtspunten:

  • Om de volledige resolutie van de foto’s te gebruiken moet eerst een High Detail mesh berekend worden.
  • De geëxporteerde TIFF bevat geen piramides, afhankelijk van de bestandsgrootte kan het laden dus erg traag gaan. QGIS kan via Raster – Miscellaneous – Build Overviews (Pyramids) piramides berekenen, gebruikmakend van GDAL.

Het resultaat is een True Ortho, waarbij dus voor de omvalling gecorrigeerd is.

Gebruik van puntenwolken

Waar RealityCapture alleen met gestructureerde puntenwolken overweg kon is RealityScan nu ook in staat om met vanuit de lucht ingewonnen puntenwolken te werken. Deze hebben dan meestal een lagere resolutie dan foto’s, maar een betere geometrische nauwkeurigheid, vooral bij contrastarme vlakken. Ook wordt voor het AHN aanzienlijk lager gevlogen dan voor het landelijke beeldmateriaal, waardoor gevels van panden beter in beeld zijn.

Bij de import worden “virtuele camera’s” aangemaakt. Hiervoor moet een vlieghoogte opgegeven worden – hoe lager, hoe meer camera’s er aangemaakt worden, zowel nadir als obliek. Een lagere hoogte en meer camera’s resulteren in meer detail, maar ook in meer virtuele foto’s en dus inspanning bij het prikken van pas- en verbindingspunten.

Hieronder screenshots met modellen resulterend uit 150m en 1.000m camerahoogte:


Foto’s en puntenwolken kunnen via verbindingspunten aan elkaar gekoppeld worden, zoals boven beschreven. Als daarna een alignment uitgevoerd wordt dan bevat de resulterende component alle data.

Bij het berekenen van een 3D model is het belangrijk de cropping distance voor de puntenwolken niet te krap te zetten, anders worden deze niet gebruikt. Deze moet groter zijn dan de vlieghoogte, waarbij de vlieghoogte *1,5 logisch klinkt (iets met wortel 2). Gezien de AHN puntenwolken geen kleur bevatten is het ook verstandig om alle puntenwolken te selecteren en Enable texturing and coloring op Disable te zetten.

Met de puntenwolken erbij is het resulterende model veel strakker zonder het “lakeneffect” bij gebruik van alleen de foto’s. Ook zijn de voorheen verdwenen hoge gebouwen nu wel aanwezig. De gevels zijn helaas niet erg mooi, om deze beter te kunnen textureren zouden obliekfoto’s vereist zijn.

Bij “platte” geometrie, zoals het circuit van Zandvoort, is het resultaat echter ook zonder obliekfoto’s best mooi te noemen:

Conversiecode

import pandas as pd
import numpy as np

rho = 180.0/np.pi

def R_OPK(omega:float, phi:float, kappa:float) -> np.ndarray:
    omega /=rho
    phi /= rho
    kappa = kappa-90.0
    kappa /= rho

    Rx = np.array([
            [1, 0, 0], 
            [0, np.cos(omega), -np.sin(omega)], 
            [0, np.sin(omega), np.cos(omega)]
        ])
    Ry = np.array([
            [np.cos(phi), 0, np.sin(phi)],
            [0, 1, 0],
            [-np.sin(phi), 0, np.cos(phi)]
        ])
    Rz = np.array([
            [np.cos(kappa), -np.sin(kappa), 0], 
            [np.sin(kappa), np.cos(kappa), 0],
            [0,0,1]
        ])
    return Rz@Rx@Ry

def R_to_rpy(R:np.ndarray) -> float|float|float:
    roll = 180.0-np.atan2(-R[2,1],-R[2,2])*rho
    pitch = np.atan2(-R[2,0],np.sqrt(R[2,1]**2+R[2,2]**2))*rho
    yaw = np.atan2(R[1,0],R[0,0])*rho

    return roll, pitch, yaw

if __name__=='__main__':
    columns = ['filename','x','y','z','omega','phi','kappa']
    filename = r"2024_projectiecentra_01_01_hrl.txt"
    eo = pd.read_csv(filename,names=columns,sep=r'\s+')
    for i in eo.index:
        R = R_OPK(eo.loc[i].omega,eo.loc[i].phi,eo.loc[i].kappa)
        roll, pitch, yaw = R_to_rpy(R)
        eo.loc[i,'roll']=roll
        eo.loc[i,'pitch']=pitch
        eo.loc[i,'yaw']=yaw

    eo.to_csv(filename.replace('.txt','_rpy.txt'),sep=' ',columns=['filename','x','y','z','yaw','pitch','roll'],index=False,header=False)

 

Een reactie plaatsen

Je e-mailadres wordt niet gepubliceerd. Vereiste velden zijn gemarkeerd met *