Velkommen til Jernbanen.dk forum. Log venligst ind eller registrér dig.

Faste anlæg

- Sporplanbilleder fra luftfotos
Gå ned Sider: 1 [2]
Sporplanbilleder fra luftfotos
Af Henning Makholm. 27/01-26, 14:52.
Seneste redigering: 27/01-26, 14:55 af Henning Makholm
Citat fra: Shum Dato 27/01-26, 09:59
Citat fra: Henning Makholm Dato 26/01-26, 20:23Så vidt jeg kan se bliver den erstattet en adgang der kun leverer fotos som enorme filer på 10×10 km i fuld opløsning, 6,4 gigapixels i hver. Det kommer der vist ikke nogen brugbar interaktiv oplevelse ud af.

Fordi at opgaven med at lave tiles ud af råmaterialet så ender hos dig, er det rigtigt forstået?

Ja, men hovedsagelig på grund af datamængden. For eksempel ligger Roskilde station på grænsen mellem to 10×10 km tiles (se koordinatnettet på https://earthmaps.dataforsyningen.dk/dfTiles), så man skal lige starte med at downloade 13 megapixels før man kan komme i gang. Det er TIFF-filer som kun er svagt (tabsløst) komprimeret, så der er vel mindst 4-5 GB at downloade.

P.t. virker mit program sådan at når man trækker kortet sidelæns med musen, finder det selv undervejs ud af hvilke 256×256 pixel tiles der nu bliver synlige, og downloader så dem på et par sekunder (i mellemtiden bliver der vist opskalerede korttiles fra en dårligere opløsning, som forhåbentlig er downloadet allerede). Det kan ihvertfald ikke opretholdes her.

Når man så har downloadet de mange data skal der gøres noget ved dem. Men en dekodet billedfil på 80'000 × 80'000 pixels fylder 26 GB i RAM -- så meget RAM har min computer ikke (den er også ved at være udtjent, men selv den nye jeg har bestilt, kunne kun konfigureres til 32 GB i alt). Man kan utvivlsomt slippe for at holde det hele i RAM på en gang ved at bruge nok programmørknofedt på det, men så er det ikke længere bare et spørgsmål om at hive javax.imageio.ImageIo.read(File) ned fra hylden. Der findes specialbibliotekter til at læse GeoTIFF-filer, men jeg ved ikke hvor tilgængelige de er fra Java.

Som sløjfen på hele molevitten er de store filer konstrueret i UTM32-projektion i stedet for den "pseudo-Mercator"-projektion som både Google og OpenStreetmap bruger (og som mine egne vektordefinitioner derfor forudsætter). Det skal der så også korrigeres for undervejs, men det er forholdsvis overskueligt. Man kan finde formler til projektionsskift på nettet; det mest udfordrende vil blive at undgå at skulle regne hele formlen igennem for hver pixel separat.

Jeg får næsten lyst til at gå i gang, bare for udfordringens skyld. Men det ville nok tage mig en uges arbejde at få det til at virke, og gevinsten er begrænset -- det vil kun virke i Danmark, og ringe er Googles fotos nu heller ikke.

Citat fra: Shum Dato 27/01-26, 09:59(Jeg får det lige umiddelbart til 8 pixels pr. meter, så det er vel ikke fordi opløsningen på den måde er overdreven - men det er nogle djævelsk store filer.)

Ja, de er defineret som "12.5 cm per pixel". Den højeste opløsning Google leverer heromkring, er på cirka 4 cm per vist pixel -- nærmere bestemt 2^29 pixels på en hel breddekreds -- men de billeder er så også temmelig uldne når man zoomer ind; jeg tror ikke de er fotograferet i noget nær den opløsning.

Til sporplaner er 32 cm per pixel normalt rigeligt, selvom der kan blive brug for at zoome nærmere ind for at se forskel på krydsningssporskifter og rene krydsninger. (Og hvis billederne er lidt uskarpe, kan det være svært selv da).

Jeg har undersøgt sagen lidt nøjere og fundet ud af at jeg var en smule for sortsynet i mit indlæg ovenfor. Så i sandhedens interesse:

På trods af hvad der står på https://datafordeler.dk/dataoversigt/geodanmark-ortofoto/geodanmark-ortofoto-fildownload-raster/ leverer tjenesten faktisk sine data i 1×1 km kvadrater og ikke 10×10 km. Hvert kvadrat er en enkelt TIFF-fil på 90-140 MB, som mit billige 5G-internet kan downloade på et halvt minuts tid.

Den enkelte TIFF-fil indeholder både den fulde opløsning og oversigtsbilleder i halv, kvart, ottendedel osv. opløsning. Hvert af disse lag er inddelt i felter på 512×512 pixels som er komprimeret selvstændig med JPEG-kompression. De første 8-10 kilobytes af filen indeholder tilstrækkeligt med indeksdata til at lokalisere præcis hvor i filen man kan finde hvert af disse 512×512 felter. Denne struktur kaldes "Cloud Optimized GeoTIFF", og formålet er at man kan nøjes med at downloade de stumper man har brug for. Desværre viser det sig så at Klimadatastyrelsens HTTPS-server ikke understøtter delvise downloads (med HTTP 'Range'-headere), hvilket reducerer fordelen noget i praksis. Men i det mindste kan man (med en smule programmering) nøjes med at afkode de 512×512 pixels JPEG-stumper man har brug for, en ad gangen.

Den fulde opløsning man får, er enten 10 cm eller 12½ cm per pixel, alt efter hvad de berørte kommuner har betalt for. Data findes i hele landet i 12½ cm opløsning (mindre data at downloade), men jeg har ikke hittet ud af hvordan man man beder om dem, bortset fra med et mere omstændeligt API som leverer TIFF-filen pakket ind i en (triviel) ZIP-struktur.

Tak, det er spændende!

Udover at være baneinteresseret er jeg også softwareingeniør, og lige akkurat erfaren nok til at jeg forstår præcis hvad du ævler om. Så selvom publikummet for dine seneste to opdateringer måske er lille, så er det her 😃

Uden at opildne til scope creep: Du må du gerne holde os opdateret hvis du bygger videre!

Mit umiddelbare indskud, når emnet handler om billedfiler i store og/eller usædvanlige formater, ville være at undersøge om ImageMagick værktøjerne/bibliotekerne kan arbejde med det.

Citat fra: nielsm Dato  2/02-26, 11:29Mit umiddelbare indskud, når emnet handler om billedfiler i store og/eller usædvanlige formater, ville være at undersøge om ImageMagick værktøjerne/bibliotekerne kan arbejde med det.

Tak for forslaget. Det man umiddelbart kunne tænke sig at bruge ImageMagick til ville være på forhånd at klippe den store TIFF-fil ud i pæne stykker i et mere håndterligt format som mit mapwarper-program så kan læse bagefter.

Efter jeg har set lidt på sagerne er jeg nu blevet mere ambitiøs end som så: Det vil kunne lade sig gøre at det kun er den rå zip-fil fra Klimadatastyrelsen som ligger på disken, og efterhånden som der bliver brug for at vise dele af den på skærmen, kan mit program (med en forholdsvis beskeden mængde bitpilleri) læse de rigtige bytes fra den som kan smides direkte ind i en standard JPEG-dekoder og give 512×512 pixels ad gangen. Det har virket en gang for mig (med håndkraft og et hexdump), og jeg er nogenlunde sikker på at det også kan programmeres.

En morsom detalje er at de pågældende JPEG-stumper indeholder en ekstra kanal pixeldata ud over de normale R,G,B. Den fjerde kanal er "nær-infrarød", hvilket man bl.a. kan bruge til at se bevoksning, idet grønne planter reflekterer disse bølgelængder meget kraftigere end de fleste ikke-levende materialer gør. Når man åbner TIF-filen i Gimp, tror den den ekstra kanal angiver gennemsigtighed, mens den helt bliver ignoreret af Gimp hvis man kun åbner den udklippede JPEG-bytestrøm.

Jeg har fået mit program til at virke nogenlunde med GeoDanmarks nye API til ortofotos. Det var et interessant projekt -- idet der blev vist en vis interesse for nørderiet, er her nogen detaljer.

Ikke-nørder er velkomne til at springe over; der er ikke meget egentlig jernbanerelevans.

1. Kortprojektion. Det nye API leverer luftfotoene i UTM32-projektion, som er standard for dansk kortlægning, mens mit program laver alle sine interne beregninger i OpenStreetMaps "pseudo-Mercator" projektion.

UTM er sådan set en bedre kortprojektion, idet den er eksakt vinkeltro og strørrelseforholdet kun varierer med under 1% forskellige steder i landet. I et Mercator-kort adskiller størrelsesforholdet sig med over 8% mellem Gedser og Skagen, og pseudo-Mercator er ikke engang eksakt vinkeltro; på vore breddegrader er der omkring 0.2% forskel på skalaen nord-syd og øst-vest. (Til gengæld falder "opad langs kortets akse" ikke ganske sammen med sand nord på et UTM-kort; det varierer fra omkring 3 grader øst i København til en halv grad vest i Esbjerg). Men når jeg nu gerne vil bruge OpenStreetMap som grundkort og skifte frit mellem GeoDanmark og Google Maps, kan jeg ikke bare gå over til UTM internt, så der er ingen vej uden om at at omregne koordinater.

Wikipedia fandt jeg fine omregningsformler med rigelig præcision. De koster imidlertid over tyve trigonometriske operationer per koordinatsæt man vil omregne, så det er for langsomt at gøre det for hver pixel man vil vise.

I stedet deler jeg kortvinduet op i felter på 256×256 pixels og laver koordinattransformationen en gang for midpunktet i hvert felt; for resten af feltet ekstrapolerer jeg fra resultatet i midpunktet (idet jeg holder styr på de afledede mht pseudo-Mercator koordinaterne gennem hele beregningen). Det viser sig, at så længe det punkt jeg omregner, ikke er længere end 8 km væk fra midpunktet, giver den lineære ekstrapolation kun fejl på under 1/1000 af afstanden til midtpunktet, dvs væsentligt mindre end størrelsen på en vist pixel. Og i skalaer på mere end 8 km pr 128 viste pixels er luftfotoene ikke relevante alligevel -- det er for småt til at se spor overhovedet.

2. Datamængder. Det nye API leverer fotoene i store TIFF-filer på 1×1 km med en pixelstørrelse på 12.5 cm. Hver fil fylder 80-95 MB og indeholder også samme 1 km-kvadrat med pixelstørrelser 25, 50, 100 og 200 cm, og hvert af disse lag er igen inddelt i mindre tiles på 512×512 pixels hver. De tabeller der siger hvor hver af alle disse tiles ligger alle i de første få kilobytes af TIFF-filen (formatet i sig selv kræver ikke denne placering, men det har konsekvent været tilfældet under mine tests).

Så så snart jeg har set starten af filen, kan jeg vide hvilken del af den jeg har brug for. Det hjælper mig umiddelbart ikke så meget, idet den server filen ligger på ikke tillader at man addresserer i den. Øv! Men det viser sig også at lagene med den højeste opløsning i praksis ligger sidst i filen. Og til mit formål er 25 cm pixels normalt rigelig detaljerede, så jeg kan simpelthen afbryde downloadforbindelsen når så snart har set alle 25 cm tiles! Det sparer omkring 3/4 af downloadmænden, og jeg kan hente 1×1 km i 25 cm opløsning på omkring 10 sekunder -- det er hurtigt nok til at virke interaktivt.

Undervejs modtager jeg også de mere grovkornede lag meget hurtigt så jeg i det mindste kan vise noget på skærmen før alle 10 sekunder er gået. (Her springer jeg over en masse morsomme mutex-problemer med at få min kode til at vise pixels fra en tile som samme kode tror den stadig er ved at downloade, men det lykkedes).

3. Mmap. Jeg måtte skrive mig min egen TIFF-parser som kan håndtere at den fil den skal fortolke ikke findes i fuld længde endnu, men det var ikke så slemt -- alt hvad jeg har brug for kan rummes indenfor 500 linjer kode, og så er det endda også noget mere generelt end jeg egentlig har brug for her.

Den virker ved at memory-mappe TIFF-filen; så er det let af følge de interne pointere som formatet anvender overalt, uden at skulle til at beregne udtrykkelige søge- og læseoperationer i filsystemet.

Det viser sig at selv om Java i årtier har haft et fint API til at oprette et mmap, har det stadig ikke en officiel måde at lukke det på. Man forventes at vente på at MappedByteBuffer-objektet bliver garbage collectet.

Oracle siger de ikke kan finde ud af at lave en close()-funktionalitet som på idiotsikker vis forhindrer at man forsøger at bruge sit mmap senere. Og idet vi ikke kan få en perfekt løsning, kan vi åbenbart ikke få en dokumenteret løsning overhovedet. Hvis man vil undgå at løbe tør for adresserum fordi spildopsamleren tager den lidt med ro en dag, er man nødt til at bruge sun.misc.Unsafe, og så tage den fordømmende tone i dokumentationen ovenfra og ned ...

4. Zip. Den eneste måde jeg kan finde ud af at få serveren til konsekvent at levere data i 12,5 cm opløsning i stedet for 10 og 12½ cm alt efter hvad der findes, er ved at bruge et API der siger "giv mig alle kvadrater indenfor sådan-og-sådan et område". Selv når jeg ved at der kun er et kvadrat i området, får jeg ikke den rå TIFF-fil, men en ZIP der indeholder netop den fil.

Meget vel -- heldigvis forsøger Zip ikke at komprimere TIFF-filen men gemmer den bare som "rå bytes". Så blot ved at skrælle ZIP-headeren af kan jeg straks give mig til at fortolke TIFF-indholdet, mens downloaden stadig er i gang.

Zip er et frygteligt format. Det er designet til at blive skrevet sekventielt, så en del metadata om hver af filerne (herunder dens længde!) findes i princippet kun i et "central directory" i slutningen af zip-filen. Det duer ikke når jeg har afbrudt min download når kun det kvarte af filen er kommet hjem! (Ingen af de standardværktøjer jeg har forsøgte mig med, har overhovedet ville genkende de delvise downloads som zip-filer).

Der er dog en header i begyndelsen af Zip, og den indeholder lige akkurat nok data til at man kan konkludere "dette er en zip-fil, og den første fil indeni hedder det-og-det og er gemt som rå bytes, men vi ved ikke hvor lang den ser", så håbe på det bedste. Hvis der var mere end én fil i zipfilen og det ikke var den første jeg havde brug for, ville jeg være fortabt ...

5. Jpeg. Hvad min TIFF parser giver mig er addressen og længden af en bytefølge der indeholder det ønskede 512×512 tile indkodet i JPEG-format. Så det kan jeg bare smide ind i en JPEG-dekoder, ikke?

Tjah. For det første er de første 73 bytes af JPEG-bytestrømmen (som indeholder "quantization tables") gemt separat i TIFF-filen, idet alle 512×512 tiles i et zoom-lag deles om disse bytes. (Hurra for den besparelse!) Så dem skal man lige huske at sætte ind i hvad man giver til JPEG-dekoderen.

For det andet indeholder en rå JPEG-bytestrøm ikke nogen standardiseret information om hvordan de fire datakanaler i den skal fortolkes som pixels -- nemlig i dette tilfælde rød, grøn, blå og infrarødt. Hvis det havde været en selvstændig .jpg-fil, vil den normalt starte med en metadata-header der bl.a. fortæller noget om det (der findes mindst to forskellige standarder disse metadata: JFIF eller Exif), men i dette tilfælde er fortolkningen beskrevet i TIFF-indpakningen, og udeladt fra JPEG.

Hvad sker der så når man lader en generisk JPEG-dekoder fortolke denne bytestrøm? I Java tror ImageIO.read(ImageInputStream) at de første tre kanaler er i YCbCr-farveformat, hvilket den hjælpsomt giver sig til at konvertere til RGB; det ser ikke kønt ud.

På den anden side tror de andre grafikværktøjer jeg har prøvet (ImageMagick, NetPBM, Gimp), at de fire kanaler er RGB efterfulgt af gennemsigighed, og deres uddata er så det delvist gennemsigtige billede kopieret ind over en sort baggrund! Det ser ikke helt så slemt ud -- i det mindste er farverne rigtige, blot for mørke -- men stadig ikke godt.

Efter en del frustration fandt jeg en måde at bruge Javas JPEG-dekoder så den overlader farvekonverteringen til mig -- og jeg ved hvordan den skal ske, ihvertfald for de specifikke filer jeg får fra GeoDanmark...

6. Adgangskontrol. Selvom ortofotoene er gratis og under CC-BY-4.0 licens skal man stadig bruge en API-key for at kunne downloade dem fra Klimadatastyrelsen. Man kan lave sig sådan en på et par minutter ved at logge ind på portal.datafordeler.dk med MitID, men jeg tør ikke rigtig offentliggøre den på GitHub, så indtil videre virker det kun hvis brugeren selv skaffer sig en nøgle og lægger den i en lokal konfigurationsfil.

(På den anden side er jeg næsten sikker på at antallet af brugere der ikke er mig, er 0, så det går nok endda).

Sporplanbilleder fra luftfotos
Af Michael Deichmann, Gribskov kommune. 7/02-26, 11:45.
Respekt!

Sporplanbilleder fra luftfotos
Af Henning Makholm. 22/02-26, 01:36.
Seneste redigering: 22/02-26, 01:39 af Henning Makholm
Citat fra: Henning Makholm Dato 25/01-26, 18:23Jeg har brugt programmet til at rette omkring 60 tyske banegårde ud, samt en god snes i resten af Europa, men vil ikke fylde forummet op med alt det uopfordret.
Men så kan jeg alligevel ikke dy mig for at fremvise Essen Hauptbahnhof i al sin stråleglans, med to store og komplekse udfletninger i østenden. Udrettet, sammentrykket ca 11×, med spornumre og andre annoteringer tilføjet i hånden.

Hmm, det der ud som om forummet skalerede billedet ned. Men så http://henning.makholm.net/mapwarper/essen.jpg da.

Gå op Sider: 1 [2]

Lokomotivfabrikker

DB Cargo

Billeder, rettelser og tilføjelser til denne side modtages med tak