Jak wyciągnąć rzeźbę terenu Księżyca z jednego zdjęcia — eksperymentalny pipeline 2.5D
Krótki opis: Opisuję projekt badawczy, który próbuje estymować względną mapę wysokości powierzchni Księżyca z pojedynczego zdjęcia orbitalnego. Bez stereoskopii, bez uczenia maszynowego — tylko klasyczna analiza cieni, gradientów jasności i danych georeferencynych.
Problem: 3D z 2D
Każde zdjęcie powierzchni Księżyca to rzut 3D na 2D. Informacja o wysokości terenu zostaje „spłaszczona”. Żeby ją odtworzyć, mamy do dyspozycji kilka poszlak:
- Cienie — im dłuższy cień, tym wyższy obiekt (przy znanych parametrach oświetlenia)
- Gradienty jasności — nagłe zmiany jasności wskazują na zbocza
- Albedo — materiał powierzchni też zmienia jasność, co komplikuje oba powyższe
Problem polega na tym, że albedo i topografia są ze sobą splątane. Jasna plama na zdjęciu może być równiną z jasnego regolitu albo stokiem nachylonym w stronę Słońca. Nie da się ich rozdzielić w 100% z jednego ujęcia — to fundamentalne ograniczenie fizyczne. Projekt jawnie to przyznaje i buduje wokół tego ograniczenia cały system zaufania do wyników.

Architektura pipeline’u
Kod jest podzielony na 7 etapów, każdy produkujący własny obraz diagnostyczny:
Etap 1 — Detekcja cieni
Maska cienia generowana jest metodą percentylową (domyślnie: najciemniejsze 15% pikseli) lub odchylenia standardowego. To metoda heurystyczna — ciemny materiał może zostać mylnie zakwalifikowany jako cień.
01_shadow_mask.png
Etap 2 — Wysokości z cieni
Z maski cienia mierzy się długości cieni i przelicza na względne wysokości:
height = shadow_length_px × pixel_scale_m × tan(sun_elevation°)
Przyjęte założenie: obiekty rzucające cień są pionowe. To przybliżenie, ale wystarczające dla skał i krawędzi kraterów.
02_shadow_length_map.png
03_shadow_height_map.png
Etap 3 — Mapa albedo
Algorytm interpoluje „oczekiwaną” jasność tła z tzw. inspect boxów — małych okien próbkujących jasność materiału w znanych punktach geograficznych. W wersji 2.6 pozycje tych okien są wyznaczane z prawdziwych współrzędnych księżycowych (lat/lon) z danych QuickMap, nie losowo.
04_albedo_reference_map.png
Etap 4 — Normalizacja jasności
Jasność obserwowana dzielona jest przez oczekiwaną jasność albedo, żeby wyizolować wpływ topografii:
normalized = observed / expected_albedo
05_normalized_brightness.png
Etap 5 — Gradienty
Na znormalizowanej jasności liczone są przestrzenne gradienty (magnitude i kierunek). Silny gradient wskazuje na zbocze; kierunek gradientu informuje o orientacji stoku.
06_gradient_magnitude.png
07_gradient_direction.png ← wizualizacja HSV: barwa = kierunek
Etap 6 — Mapa zaufania (confidence map)
To jest serce projektu. Mapa zaufania łączy 5 niezależnych składowych:
| Składowa | Co mierzy |
|---|---|
| Shadow distance | Bliskość do krawędzi cienia |
| Gradient | Siła gradientu jasności |
| Texture variance | Lokalna variancja (tekstura) |
| Albedo stability | Bliskość do inspect boxów |
| Failure penalty | Kara za obszary z góry nienadające się do analizy |
Ostateczna mapa zaufania = ważona suma składowych × kara za regiony nieudane.
08_confidence_map.png ← zielony = wysoka pewność, czerwony = niska
Etap 7 — Końcowa mapa wysokości
Wysokości z cieni i ze stoków gradientowych są łączone. W obszarach niskiego zaufania wyniki są wygładzane w kierunku mediany — żeby nie prezentować szumu jako terenu.
09_height_map.png
10_height_map_confidence_overlay.png ← wysokości + zaufanie jako krycie
Dane wejściowe: QuickMap
Projekt używa danych z QuickMap (LROC, Arizona State University):
- Obraz LROC NAC — zdjęcie orbitalne w wysokiej rozdzielczości (~1 m/piksel przy pełnej rozdzielczości)
- Region Data CSV — punkty pomiarowe z QuickMap zawierające: współrzędne geograficzne (lat/lon), wysokość terenu (TerrainHeight), nachylenie (Slope), skład optyczny i inne
Plik .vrt (GDAL Virtual Dataset) dostarcza metadane georeferencyje: układ współrzędnych, transformację geograficzną, skalę pikselową.
Iteracje projektu
Kod przeszedł trzy iteracje, każda dodając nową warstwę:
Iteracja 2 — podstawowy pipeline (cienie + gradienty + mapa zaufania)
Iteracja 2.5 — warstwa diagnostyczna: rozkład mapy zaufania na 5 składowych, histogram gradientów, nakładka outlierów, interakcja cień–gradient. Cel: „Czy ufam pipeline’owi z właściwych powodów?”
Iteracja 2.6 — prawdziwe współrzędne: inspect boxy wyznaczane z danych QuickMap, a nie losowo. Mapowanie lat/lon → piksel z liniowym przybliżeniem (bez korekcji projekcji kartograficznej).
Iteracja 3 (validate_iteration3.py) — walidacja trendów: porównanie kierunków gradientów z zewnętrznym DEM (LOLA/LROC). Nie optymalizuje — tylko odpowiada na pytanie: „Czy rekonstruowane trendy zbieżne są z prawdziwą topografią?”
Czego projekt nie robi
To jest lista równie ważna jak lista funkcji:
- Nie generuje DEM — wysokości są względne, bez bezwzględnej referencji
- Nie stosuje uczenia maszynowego — każdy krok jest interpretowalny przez człowieka
- Nie jest fotogrametrią — brak par stereo, brak triangulacji
- Nie działa dobrze na równinach — jednolite obszary nie dają sygnału topograficznego
- Nie rozdziela w pełni albedo od topografii — to niemożliwe z jednego zdjęcia
Wyniki i walidacja
Przy teście na przykładowym regionie księżycowym (7.63°N, 6.53°E), w pełnej rozdzielczości LROC NAC (1 m/px), używając syntetycznego DEM (brak dostępu do LOLA w czasie testów), walidacja Iteracji 3 klasyfikuje:
- ok. 3.6% obszarów z wysoką pewnością jako zgodne z trendem DEM
- ok. 17.7% jako niezgodne
- reszta: zbyt niska pewność, żeby wyciągać wnioski
Wyniki są uczciwie raportowane — projekt nie próbuje tych liczb tłumaczyć ani „naprawiać”. Niezgodność jest informacją, nie błędem do ukrycia.
Potencjał i zastosowania
Warto tu wspomnieć o szerszym kontekście danych, z których korzysta projekt.
Zdjęcia powierzchni Księżyca wykonane przez LROC NAC to najbardziej szczegółowe mapowanie powierzchni ciała niebieskiego poza Ziemią. Przy rozdzielczości ~1 m/piksel każdy piksel odpowiada powierzchni jednego metra kwadratowego — to poziom szczegółowości nieosiągalny dla żadnej innej planety czy księżyca w Układzie Słonecznym. Brak atmosfery na Księżycu eliminuje rozmycie i zniekształcenia optyczne, co dodatkowo podnosi jakość zdjęć.
QuickMap oferuje też widok 3D rekonstruowany z danych LOLA (LRO Laser Altimeter). Daje on rozszerzone pojęcie o ukształtowaniu terenu, ale podobnie jak ten pipeline, przedstawia topografię w ograniczonym zakresie — nie jest to pełna, precyzyjna fotogrametria.
Co jeszcze można by z tego wyciągnąć
Główna ograniczająca przesłanka tego projektu to jedno zdjęcie z jednego kąta. Gdyby dostępne były dwa lub więcej zdjęć tego samego obszaru w zbliżonej rozdzielczości i różnych kątach oświetlenia, możliwości analizy rosną istotnie:
Ocena ścieżek poruszania się — identyfikacja terenów z minimalnym nachyleniem i małą liczbą głazów przydatna przy planowaniu tras łazika.
Ocena grubości regolitu — cienie głazów i ich relacja do otoczenia mogą wskazywać na głębokość luźnej warstwy powierzchniowej.
Analiza formacji skalnych — rozmieszczenie i morfologia głazów pod różnymi kątami oświetlenia pozwala na wstępną klasyfikację litologiczną.
To wszystko na razie obszar badawczy, nie gotowe narzędzie. Ale punkt wyjścia jest tu wyjątkowo dobry: dane są publiczne, darmowe i najwyższej możliwej jakości.
Kod i licencja
Kod Python (~1600 linii, bez zewnętrznych frameworków AI) używa wyłącznie: numpy, opencv-python, scipy, matplotlib
Kod źródłowy narzędzia jest dostępny publicznie na GitHubie: github.com/MarcinSFox/Lunar_2.5D
Wszystkie kroki są jawne i udokumentowane. Każdy etap generuje własny obraz diagnostyczny, co pozwala zrozumieć, gdzie pipeline działa dobrze, a gdzie się myli.
Dane testowe: przykładowy region księżycowy (~7.63°N, 6.53°E), obraz LROC NAC z QuickMap, skala ~1 m/px.
Projekt traktuję jako eksperyment badawczy i narzędzie do nauki. Wyniki to hipotezy o kształcie terenu, nie pomiary. Wartość projektu leży w przejrzystości metody i jawnym modelowaniu niepewności — nie w dokładności wyników.
