015
08.01.2016, 06:22 Uhr
Hans
Library Walker (Operator)
|
Hi,
irgendwie beschäftigt micht dieses Thema auch, weil ich ein ähnliches Problem "auf der langen Bank liegen" habe...
Ich beziehe mich jetzt nur mal auf dieses hier:
Zitat von Yadgar: |
Ich habe ein Programm geschrieben, das aus Bitmaps (TGA-Format) mit aus eingescannten topographischen Karten extrahierten Höhenlinien 16-bit-Heightfields für POV-Ray erzeugen soll. POV-Ray interpretiert dabei nur die Rot- und Grünwerte, so dass sich 65536 Höhenstufen ergeben.
|
Das die Ausgabe von PovRay weiter verarbeitet werden soll, lass ich mal aussen vor, denn es geht mir gerade nur darum, aus dem Bild mit den Höhenlinien ein Heigtfield zu machen. Dazu kam ich auf folgenden Ansatz: Das Programm liesst die Bilddatei, die im besten Fall nur zweifarbig ist, also nur ein Bit Farbtiefe hat. In der Bilddatei ist ja auch die Höhe und die Breite des Bildes codiert. Diese wird dazu benutzt, ein Integerarray mit den gleichen Ausmaßen des Bildes zu definieren, aus dem das Heightfield wird. Dieses Array wird zunächst mit -99999 (also einen sehr kleinen negativen Wert) initialisiert, da 0 (Null) durchaus ein sinnvoller Wert sein kann. Der Wert -99999 zeigt an, das für diesen Punkt noch kein Wert ermittelt wurde. Als nächstes sucht das Programm vom Koodinatenursprung des Bildes aus die erste Höhenlinie. Wenn es die gefunden hat, wird an den korrepondierenden Koordinaten des Int-Arrays ein Wert gesetzt, z.B. Eins. Anschliessend wird die Fläche, die sich jenseits der Höhenlinie befindet abgescannt und die zugehörigen Punkte (inclusive derer der Höhelinie selbst) im Heightfield ebenfalls auf eins gesetzt. Das macht man solange, bis die nächste Höhenlinie kommt. Die begrenzt den zu füllenden Bereich. Dieses Durchsuchen ist im Prinzip das gleiche, wie bei einem Algorithmus zum Flächen füllen in Malprogrammen, also ein Floodfill. Der Unterschied ist, dass ein einer Bitmap gesucht wird und Werte an korrespondierenden Koordinaten in einem Integerarray geändert werden. Dieses Vorgehen dient dazu, Widersprüche zu vermeiden, die auftreten können, wenn eine Höhenline an zwei verschiedenen Stellen der x-Achse den gleichen y-Wert hat, etwa weil sie einen Bogen beschreibt. Wenn auf diese Weise eine Fläche bearbeitet wurde, d.h. ein Teil des Int-arrays mit Werten belegt ist, wird die nächste Höhenlinie gesucht. Wenn diese gefunden ist, wird wiederum der Bereich jenseits dieser Höhenlinie nach dem selben Prinzip abgesucht. In dem Intarray wird jetzt aber ein anderer Wert eingetragen, als zuvor. Der kann jetzt zwei betragen, besser ist es aber, wenn er 10 beträgt. Warum, erkläre ich später noch. Das ganze wird solange widerholt, bis das Bild komplett bearbeitet ist.
Jetzt gibt es aber noch vier Probleme: 1. Da nur die Höhenlinien gegeben sind, aber keine weiteren Informationen, können Gipfel und Senken (oder Täler) nur schlecht, bzw. gar nicht erkannt werden. 2. Es ist wichtig, das die Höhenlinien auch wirklich getrennt sind. Denn wenn sie zu nah aneinander liegen, kann es sein, das sie nicht mehr eindeutig auseinander zu halten sind. 3. Nachdem man den Floodfill das erste mal ausgeführt hat, und auf die zweite Höhenlinie trift, ist es nötig, an der korrespondierenden Stelle im Intarray nachzusehen, ob dort schon ein Wert ungleich des Init-Wertes steht! Dann braucht man da nämlich erst mal nichts weiter zu tun. Das kann durch den floodfill durchaus vorkommen, nämlich dann, wenn die zweite gefundene Höhenlinie in Wirklichkeit das andere Ende der ersten ist, also an einer Stelle y zwei x-Werte hat. Und ebenfalls, wenn eine Höhenlinie an einer Stelle x zwei y-Werte hat, also etwa auch wieder einen Bogen beschreibt. 4. Wenn man diese Arbeit mit einem Bild erledigt hat, erhält man als Ergebnis nur "Tafelberge", bzw. Stufen. An dieser Stelle kommt die Sache mit Gradientenberechnung und der Spline-interpolation ins Spiel, die ao vorgeschlagen hat. Dazu ist es nach meinen bisherigen Überlegungen allerdings erfolderlich, sich den Verlauf der Höhenlinien zu merken. Ansonsten müsste man das mit in den Floodfill-Algorithmus einbauen, und das halte ich bisher nicht für sinnvoll. Wenn man die Gradienten jedoch an den Punkten entlang der Höhenlinien berechnet hat, kann man den Bereich zwischen jeweils zwei Höhenlinien mit Zwischenwerten füllen, die sich für den Bereich als passend ergeben. Das ist auch der Grund dafür, die einzelnen Felder mit Zahlen zu füllen, die sich um mehr als eins unterscheiden. (Anmerkung für mich: Vielleicht ist es auch sinnvoll, anstelle von integer ein Array aus float-zahlen zu nehmen. Dann kann man für die jeweilige Steigung soviele Zwischenwerte bestimmen, wie man braucht. Bei sehr steilem Gelände kommt man mit wenig Zwischenwerten aus, bei sehr geringen Steigungen kann man dagegen auch mehr als 10 aus meinem obigem Beispiel bestimmen. Beim speichern werden die Daten dann mit einem Faktor einer glatten 10er-Potenz multipliziert und nach int konvertiert. Ende der Anmerkung.)
Wenn Du mit Blender eingermassen klar kommst, ist es eine brauchbare Idee, ein Bild mit wenigen Höhenlinien (max. 10) zu nehmen und das entsprechende Gelände aus einem Grid heraus nachzubauen. Ich hab das mal mit 9 Höhenlinien gemacht:
Hier nur die Höhenlinien; als Bezierkurven in Blender. Hier mit einem Grid darüber. Es besteht aus 61 x 61 Vertexen. Und hier das, was dabei heraus kommen kann.
Am Letzten Bild sieht man zum einem, was ich mit "Tafelbergen" meine. Aber auch, das die Höhenlinien, wenn sie für sich alleine stehen, nicht eindeutig sind. Oder ist irgendwer beim betrachten der Höhenlinien auf die Idee gekommen, dass das unten rechts eine Senke sein könnte? Soweit mal für den Augenblick, Hans -- Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung. Dieser Post wurde am 08.01.2016 um 06:23 Uhr von Hans editiert. |