https://suche.transparenz.hamburg.de.EXAMPLE.COM/api/action/resource_search?query=url: (“.EXAMPLE.COM” entfernen) liefert aktuell rund 200 Megabyte an JSON, da sollten alle Resourcen drin stecken oder zumindest die, die tatsächlich einen Datensatz referenzieren
Um es in normalen Editoren besser handlebar zu machen, hilft json_pp:
First in a series of very terse posts explaining and documenting the technical setup behind our remote video conferencing FOSSGIS-Jeopardy game setup. Mostly meant as public backup and because sharing is caring. Maybe it can inspire someone else to build silly stupid stuff for fun.
Here we are with the buzzer for the candidates to hit if they want to solve a task (aka ask the question to the presented thing). I wrote this for a funny digital xmas party with the lovely colleagues at Civity in 2020 and re-used it for FOSSGIS-Jeopardy 2021 and 2022.
A admin page can be used to unlock a buzzer “button” (well, a parrot GIF in our case because we need more silly fun in life) on participants’ buzzer pages. Participants can then touch/click their screen to “buzz”. The incoming buzzes are displayed visible for everyone with the delay since the buzzer was unlocked.
This is obviously highly dependent on the participants’ latency, both on their device (touch/click to network message) as well as from their device to the message router. A tab on a desktop browser in LAN will win against a mobile device in 2G if they’d hit it in the same moment. ¯\_(ツ)_/¯
There are two/three components: The message router, the webpages and optionally a webserver (I used crossbar as router which can also host static webpages)
Ask me anything if you want to set this up following the amazing instructions and fail.
I don’t remember anything about the options part. It might not be necessary. I probably tried to stuff something more complex into the messages at some point.
Then just run crossbar as root because you used a single-purpose 2€ VPS for this and you will delete it after the event anyways. Yolo! You should definitely secure your system, crossbar config and certificate and everything else properly otherwise. Seriously!
This is really really horrible and messy code, with lots of left-over bits, bugs and random snippets. But it works so who cares! I could not care less about its bEAuTy. Sometimes a banana is the right hammer.
Screen stays on (support depends on the OS)!
Fullscreen mode can be triggered with a button!
There is a sound when the buzzer is buzzed by anyone!
Animations are CSS transforms on PNG sprites!
Random emojis are displayed if a user did not set a username!
Inconsistent indentation!
Probably some german words here and there!
w3schools was extensively used to create this!
Put them in a web/ directory according to the crossbar config (or host it with another webserver if you like).
https://www.example.com/view.html has a white background for displaying the names and timings in OBS (masking away the white color for transparency)
https://www.example.com/?name=MyName is the buzzer page/”app” for the candidates, they can touch/click anywhere while the run is active to register their buzz. It is meant to be used on a mobile phone.
Raster Image Marker with https://opengameart.org/content/character-spritesheet-duck, vertical anchor at bottom, sprite choice between walking and running (doesn’t actually work) plus the frame via
if it is a one band raster you want to convert. For others you will have to adjust the readers.gdal.header part, e.g. to --readers.gdal.header="Red, Green, Blue". See https://pdal.io/stages/readers.gdal.html.
Das Lied Von Wegen Lisbeth – Bitch hat ein verrücktes Musikvideo, wo sich die Kamera in einer chaotischen Szene scheinbar um sich selbst dreht, während im Hintergrund jemand von links nach rechts läuft.
Ich hab da mal was beklopptes mit gemacht…: Eine Transformation des Videos im Slitscan-Stil. Angefangen 2019, und jetzt endlich mal richtig gerendert.
Kochrezept
Extrahiere die Videoframes: 5621 Frames mit einer Auflösung von 1920×1080 Pixeln
Schneide jeden der Frames in einzelne 1×1080 große Streifen: 5621x der linkste Streifen, 5621x der zweitlinkste Streifen und so weiter.
Setze je ein Bild je Streifen zusammen, als erstes ganz links den linksten Streifen des ersten Frames, direkt daneben den linksten Streifen vom zweiten Frame, dann den vom dritten, etc.: 1920 Bilder mit einer Auflösung von 5621×1080 Pixeln
Setze die resultierenden Bilder als Video zusammen: Video in 5621×1080 Auflösung und 1920 Frames
Ich hab’s mit ffmpeg, graphicsmagick und einem Bash-Skript gemacht. Super ineffizient, aber sehr effektiv ;)
Resultat
Hier in klein, der Link unten führt zur “Vollversion”. Es wabbelt alles bisschen rum, weil die Kamera nicht in gleichbleibender Geschwindigkeit bewegt wurde, oder so ähnlich.
Ein so großes Video kann man nirgendwo einfach hosten oder vernünftig ansehen (oder?), praktischerweise gibt es das Gigapan Time Machine-Projekt, was auch Google für ihre Timelapse-Funktion nutzt. Damit kann man die Bilder nehmen und wie eine animierte Webkarte ansehbar machen, mit Zoom und Pan und einigermaßen effizientem Datenzugriff. Leider ist das Tool veraltet, nicht mehr in Entwicklung und macht es praktisch unmöglich die Videoparameter selbst zu tweaken.
PS: (Ich hab das Resultat vertikal gestaucht, damit die Proportionen besser passen. Und es läuft rückwärts, weil damit die Zeit der meisten Bewegungen passt. Ziemlicher Brainfuck.)
Hä?!
Joa, schwer zu verstehen, was hier passiert. Ein paar schicke Diagramme würden helfen (welcher Pixelstreifen geht wohin und was wurde wie zusammengesetzt), aber das ist mir zu zeitaufwendig. Daher nur ein paar Denkanstöße, vielleicht helfen die:
Das originale Video hat 5621 Frames in 1920×1080. Dieses Video hat 1920 Frames in 5621×1080.
Die Dame mit dem Tuch am Anfang ist etwa bis Frame 750 im originalen Video sichtbar. Im transformierten Video ist sie nie weiter als etwa 750 Pixel vom linken Bildrand entfernt.
Als 3D Volumen/Punktwolke
Weil warum auch nicht hab ich das ganze noch als dreidimensionales Etwas aufbereitet. Jedes Frame des Videos besteht aus 1920×1080 farbigen Pixeln, wenn man alle Frames hintereinander reiht, entsteht ein Kubus 1920x1080x5621 Pixeln. Und das ist im Grunde nichts anderes als eine sehr regelmäßige und “voluminöse” Punktwolke, also kann man entsprechende Tools missbrauchen. Ich hab die Daten mal in das fantastische Potree gesteckt:
Es sind 11 Milliarden Punkte und mit 40 Gigabyte etwas zu groß, als dass ich es hosten möchte. Wer es nachbauen will:
for file in slices_reversed/*.png # 0001.png, 0002.png, ...
do
n=$(echo "${file}" | grep -Eo '[0-9]+' | sed 's#^0*##') # frame number from filename
convert "${file}" sparse-color: | tr " " "\n" | \
sed 's/srgb//g' | sed 's/[()]//g' | \
awk -F ',' -v OFS=',' -v n="$n" '{ print $1,-n-1,$2,$3,$4,$5 }' \
# image to csv, insert frame number-1 so we get 0, flip y \
# TODO flip y seems to have been buggy :(
done > images.xyzrgb.csv
Das 250GB-CSV wiederum mit split nach Belieben splitten, da txt2las bei mir irgendwie nicht mehr als 2^64 Punkte aufeinmal vertragen wollte und dann die Teile
Anschließend die .laz-Dateien mit PotreeConverter zum Ansehen aufbereiten (Achtung, mit dem default Poisson-Sampler fliegt es immer bei 76% auseinander, wohl wegen der verrückt regulären Struktur der Punktwolke):
PotreeConverter ${chunk}.laz -o ${chunk}_potree --encoding BROTLI -p ${chunk} -m random
Die fertigen Teile dann in einen Viewer stecken, z. B. in das multiple_pointclouds.html-Beispiel und Spaß haben.
Disclaimer
Dies ist ein Kunstprojekt und ich hoffe damit es ist von etwas wie der Kunstfreiheit gedeckt. Falls nicht: Eine kurze Mail (hannes ät enjoys dotter it) und ich lösche es von der Seite.
LERC is a kick-ass approach to 2D raster data compression, supported in GDAL since version 3.3. You can use it for lossless compression but it is also able to throw away some bits of information for smaller data sizes. You tell it which level of Z error is acceptable for your values and it will use that freedom to change the values of neighboring cells to do its magic. Z means the “data” axis here, of a single-band in a 2D raster, X and Y are the coordinates, or rather the locations of the data values in the raster, which are obviously not changed.
I used a global SRTM DEM with a Z value in full meters (no floating point values but integers) and applied LERC on it in three ways: Lossless, with a maximum Z error of 1 meter and a maximum Z error of 10 meters. Zstandard compression was always used.
The original GeoTIFF file was already very well compressed with Zstandard level 15 and a horizontal predictor; at ~1296000 x ~417600 pixels it has a size of 86 gigabytes including overviews.
Original (ZSTD level 15): 86 GB
LERC_ZSTD (lossless): 105G
LERC_ZSTD (maximum Z error of 1): 81G
LERC_ZSTD (maximum Z error of 10): 21G
Cool, so if we don’t care about an error of 10 meters, we can have a global DEM (well, as global as SRTM is with its 60° cut-off) at ~30 meters pixel resolution in 21 gigabytes. But what does that actually look like then and how will this error appear? Well, check it out:
Here are some samples visualised with a greyscale color ramp (locally adjusted, so the lowest value in the image is black, the highest value is white). They are shown at a 1:1 resolution, one pixel in the image (if you look at it at 100%) is one cell of the DEM data. The left image is lossless, the middle one was allowed an Z error of 1 meter, the right one 10 meters.
Mountainous, here the values range from 0 meters to about 2000 meters:
You can hardly see a difference, at least visually.
“Mediumish”, values between ~100 and ~500 meters:
At the 10 meter error level you can see a significant terracing effect.
Plains, values all around 100 meters:
You can see some structures collapsing into flat areas in the 1 meter version and oh wow that 10 meters version looks like upscaled pixels.
Time to zoom in! I picked a less flat area again because it makes it easier to understand. Here the values are between ~100 and ~300 meters:
So what do we see here? Neighboring cells with the same values compress better so LERC is shifting the values around (within the allowed error), creating terraces of same-valued cells. If you look closely you can see that there is also a visible pattern of squarish structures. Those are the blocks or windows in which LERC looks at the data and does its adjustments, in this case they were 8×8 pixels wide. Note: What LERC does exactly is a bit more complex than “try to make neighboring values the same”, it actually looks at the bits required to store the values within a block and optimized that within the error tolerance.
And now you know what LERC can do, if you give it a error level to play with.
For reference, here is that same-ish area with the error tolerance at 1 meter:
You have to zoom in quite a bit more to be able to see the effects here due to the nature of the data in this extent in combination with the particular error tolerance:
The larger the zonal differences of your Z values are to each other and in relation to the error tolerance, the less distinguished will this effect be. If there are steps of 100 meters between neighboring pixels, an extra error of 10 meters won’t do much of a difference. But in more flat areas it will have significant “terracing” effects as you could see above. This is similar to “banding” effects in images where there is little variation in color, e. g. a blue sky or an artificial color gradient, and you look at it in a setup that has a color bit depth on a resolution your human eyes can distinguish.
So if you want to use LERC with a lossy approach, think hard about what is going to happen with your data later. What kind of analysis will be performed, how will it be “looked” at, what will be calculated. Do it smart and you can have a predictable/controllable lossy compression with seriously small file sizes, do it without thinking and your data will lead to misinterpretation and apocalypse.
As I will shut it down (no reason, just decluttering) here’s how it works so you can run your own:
Have aerial images with a permissive license
Register a Twitter account and set it up for posting via API access
Write code to pick an image and post it
Done!
Okok, I am kidding.
I used https://suche.transparenz.hamburg.de/dataset/digitale-orthophotos-belaubt-hamburg3 as data source because they have a CC-BY like license, allowing such a project without any legal complications. As a side benefit these images are already provided in tiles: There is not one big image of the whole region but 1km² image tiles. Perfect for random selection, quick resizing and posting.
Registering a Twitter account and setting it up is a privacy nightmare and, being a good human being as you are, you ought hate any part of it. I followed the Twython tutorial for OAuth1 in a live Python interpreter session which was fairly painless. If you do not want to link a phone number to your Twitter account (see above for how you should feel about that), this approach worked for me in the past but I bet they use regional profiling or worse so your luck might differ.
Next you need some code to do the work for you automatically. Here is what I wrote with Pillow==7.0.0 for the image processing and twython==3.8.2 for posting:
import glob
import random
from io import BytesIO
from PIL import Image
from twython import Twython
## Initialise Twitter
# use a Python interpreter to follow the stops on
# https://twython.readthedocs.io/en/latest/usage/starting_out.html#oauth-1-user-authentication
# don't rush, there are some intermediate keys iirc...
APP_KEY = '1234567890ABCDEFGHIJKLMNO'
APP_SECRET = '12345678901234567890123456F8U0CAKATAWAIATATAEARAAA'
OAUTH_TOKEN = '1234567890123456789123456F8U0CAKATAWAIATATAEARAAAA'
OAUTH_TOKEN_SECRET = '123456789012345678901234567890FFSFFSFFSFFSFFS'
twitter = Twython(APP_KEY, APP_SECRET, OAUTH_TOKEN, OAUTH_TOKEN_SECRET)
## Prepare the image
# via https://twython.readthedocs.io/en/latest/usage/advanced_usage.html#posting-a-status-with-an-editing-image
# Pick the image
jpegs = glob.glob("DOP20_HH_sommerbefliegung_2019.zip/*.jpg")
todays_image = random.choice(jpegs)
print(f"Today we will post {todays_image}")
photo = Image.open(todays_image)
# Resize the image
basewidth = 1000
wpercent = (basewidth / float(photo.size[0]))
height = int((float(photo.size[1]) * float(wpercent)))
resized_photo = photo.resize((basewidth, height), Image.ANTIALIAS)
# "Save" the resulting image in temporary memory
stream = BytesIO()
resized_photo.save(stream, format='JPEG')
stream.seek(0)
## We've got what we need, let's tweet
license = "dl-de/by-2-0 (Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung)"
tweet = f"Das ist #IrgendwoInHH, aber wo denn nur?\n\n#codeforhamburg\n\nBild: {license}"
response = twitter.upload_media(media=stream)
twitter.update_status(status=tweet, media_ids=[response['media_id']])
First we initialize that Twython thingie, then we pick a random image from a directory of .jpg files, then we resize it to a maximum of 1000 pixels (you can simplify that if your images are square…) and finally we post it to Twitter.
Set up a cronjob or systemd timer or alarm clock to run the script as often as you like and that’s it.
Egal. Das ist ja großartig! Da werden eine Menge von Anwendungen ermöglicht (Sichtachsen! Verschattungen! Vermaschung! VR! AR!) und verschiedenste Akteure werden die Daten absolut feiern. Auch wenn es mit 1 Meter Auflösung wirklich mies grob ist, auf ein 1 Meter Gitter gerastert ist (nicht ausgedünnt, d. h. es ist teilweise stärker verfälscht und “daneben”) und “nur” bildbasiert (nicht gescannt) ist, geht da schon einiges mit.
Ausprobieren! Im Browser!
Achtung, frickelige Bedienung! Am besten den WASD-Möwen-Modus nutzen, mit Speed 1000. Oder mit einem Doppelklick irgendwo hinzoomen.
Für 2018 liegen die Daten als 12768 einzelne XYZ-Kacheln vor, also als super ineffiziente Textdateien. Insgesamt sind es rund 22 Gigabyte. Für 2020 sind es stattdessen 827 größere Kacheln, aber ebenfalls in XYZ mit einem ähnlichem Platzbedarf.
Schönerweise gibt es freie Tools wie LAStools‘ txt2las, was sie schnell und einfach ins super effiziente LAZ-Format umwandeln kann:
und 4 Minuten später ist die interaktive 3D-Webanwendung fertig, wegen der zusätzlichen Octree-Struktur jetzt bei rund 3 Gigabyte.
Punktwolke mit Farben aus Orthophoto einfärben
Die bereitgestellten Oberflächenmodelle sind so schlicht wie es nur geht, es sind reine XYZ-Daten ohne weitere Dimensionen wie Farbe o. ä.
Glücklicherweise gibt es ja auch die Orthophotos, eventuell wurde sogar dasselbe Bildmaterial genutzt? Da müsste mal jemand durch den Datenwust wühlen, die bei den DOPs werden die relevanten Metadaten nicht mitgeliefert…
Theoretisch könnte man sie also einfärben. Leider ist lascolor proprietär und kommt mit gruseligen, bösartigen Optionen, wenn man es wagt es “unlizenziert” zu nutzen (“Please note that the unlicensed version will (…) slightly change the LAS point order, and randomly add a tiny bit of white noise to the points coordinates once you exceed a certain number of points in the input file.”) und kann JPEG in GeoTIFF nicht lesen (so hab ich mir die DOPs aufbereitet). Eine Alternative ist das geniale PDAL. Mit einer Pipeline wie
ist die Punktwolke innerhalb von Minuten coloriert und kann dann wie gehabt mit PotreeConverter in einen interaktiven 3D-Viewer gesteckt werden.
Update 2023: "minor_version": "2" -> "minor_version": "4", damit LAS 1.4 rauskommt, um dann einfach COPC draus bauen zu können (Farben als 16-Bit, nicht 8-Bit). Und entsprechend noch ein Filter, um die Farben auf den 16-Bit-Wertebereich zu skalieren, das passiert leider nicht automatisch.
Das Ergebnis ist besser als erwartet, da es scheinbar tatsächlich die selben Bilddaten sind (für beide Jahre). Andererseits ist es auch nicht wirklich schick, da die DOPs nicht als True Orthophoto vorliegen und damit höhere Gebäude gekippt in den Bilder abgebildet sind. Sieht man hier schön am Planetarium.
Cloud-Optimized Point Cloud
Als Cloud-Optimized Point Cloud umwandeln kann man das Resultat einfach mit untwine (mit pdal pipeline braucht man immens viel RAM (>64GB), da die Umwandlung nach COPC hier nicht den Streaming Mode nutzen kann):
Anschließend auf einem Server (mit entsprechenden Access-Control-Allow-Headern) gelagert, kann die Punktwolke super einfach mit https://viewer.copc.io/?resources=https://example.com/pointcloud.copc.laz im Browser verwendet werden. Ganz ohne Umwandlung in viele Unterdateien wie beim PotreeConverter.
DOM als GeoTIFF
Wer es lieber als GeoTIFF haben möchte, hat es etwas schwerer, denn GDAL kommt mit dieser Art von Kacheln (mit Lücken und in der bereitgestellten Sortierung) nicht gut klar. Mein Goto-Tool dafür ist GMT.
Hier mal im Vergleich mit dem DGM1 als Schummerungen:
Vermaschung als 3D-Modell
Leider habe ich keine gute Lösung für die 3D-Vermaschung gefunden. tin-terrain und dem2mesh kommen nicht mit so großen Datenmengen auf einmal klar und weiter hab ich nicht geschaut. Wer da was gutes weiß kann sich bei mir bei nächster Gelegenheit Kekse oder Bier abholen. ;)
Daten hinter den Bildern und den Viewern Datenlizenz Deutschland Namensnennung 2.0, Freie und Hansestadt Hamburg, Landesbetrieb Geoinformation und Vermessung (LGV)
Looking for a 10 inch tablet with proper, official Lineage OS support I ended up on the device database. Unfortunately they do not have a simple list of device types. So I wrote some code to extract the tablets with support of at least version 17. The list is short…: