Wer schon einmal mit Astrokameras gearbeitet hat, wird sicherlich schon FITSD-ateien begegnet sein. FITS ist ein quelloffenes Rohdatenformat, welches von der NASA entwickelt wurde und wohl auch deshalb der quasi-Standard für RAW-Daten im Bereich der Astronomie/Astrophotographie ist (weitere Infos zu FITS).
Im Ökosystem von Python existieren zudem zahlreiche quelloffene Pakete für wissenschaftliche und technische Anwendungen. Mit dem Paket “astropy” ist ein Paket verfügbar, welches Methoden und Funktionen rum um astronomische Fragestellungen beinhaltet. Zudem ist “astropy” in der Lage, auch mit FITS-Dateien umzugehen.
Zur Installation von “astropy” in einer vorhandenen Python-Umgebung kann “pip” genutzt werden:
pip install astropy
Nach dem Download aller Dateien kann “astropy” über den “import” Befehl geladen werden. Zudem laden wir auch direkt “matplotlib” um unser Bild ausgeben zu können und numpy, weil das nie schaden kann 😉
import numpy as np
from astropy.io import fits
import matplotlib.pyplot as plt
Aus “astropy.io” benötigen wir das Package “fits”, welches die Methoden und Funktionen enthält, um FITS Dateien und die “Header Data Unit” (HUD) der Datei zu verarbeiten. Zudem gibt es Funktionen, um die Bilddaten des Primärbildes direkt auszulesen. Mit der Funktion “fits.getdata” können wir das FITS Bild einlesen und in ein numpy-Array schreiben:
image_data = fits.getdata("ngc7380.fits")
type(image_data)
numpy.ndarray
Das numpy-Array ist in diesem Fall ein 2D-Array, dessen Dimensionen der Pixelzahl des RAW-Bildes entspricht:
np.shape(image_data)
(3522, 4656)
Die einzelnen Werte sind dabei die Helligkeitswerte der Pixel. Deshalb ist es möglich das Bild direkt und ohne Umwege mit Matplotlib zu plotten:
plt.imshow(image_data, cmap='gray')
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x271165efb90>
Irgendwie sieht man nicht viel, was daran liegt, dass astronomische Bilder oft sehr schwache und dunkle Objekte zeigen und die Bilder zuerst normalisiert oder gestreckt (streching) werden müssen. “atropy.visualization” stellt mit “simple_norm” eine Klasse zur Normalisierung und zum Streching von FITS Bildern bereit mit dem Ziel, die Daten zum Plotten in Matplotlib bereitzustellen. Dazu wird zuerst “simple_norm” importiert:
from astropy.visualization import simple_norm
Zuerst einmal versuchen wir das Bild mittels einer Wurzelfunktion zu strecken. Die Pixelwerte im Bild bewegen sich zwischen 0 und maximal 65500. Eine entsprechende Kurve der Wurzelfunktion hat in diesem Bereich folgenden Verlauf:
x = np.linspace(0, 65500, num=65500)
y = np.sqrt(x)
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x27111ef97d0>]
Beim Strecken mit “sqrt” (Abkürzung für “squareroot” = Quadratwurzel) wird jedem Pixelwert der entsprechende Funktionswert zugewiesen, also:
Anschließend wird das dunkelste Pixel auf einen Wert von Null und das hellste Pixel auf einen Wert von ca. 65500 skaliert. Strecken wir also das FITS Image mit dieser Wurzel-Funktion und plotten das Resultat mit Matplotlib:
img_norm = simple_norm(image_data, "sqrt")
plt.imshow(image_data, cmap='gray', norm=img_norm)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x2712a2dbdd0>
Nun sind schon deutlich mehr Sterne und auch einige schwache, nebulöse Strukturen im Bild zu erkennen. Das Strecken mit “sqrt” führt dazu, dass Pixel mit geringen Helligkeitswert deutlich aufgehellt werden. Die Kurve steigt nahe Null steil an, die Steigung nimmt dann jedoch schnell ab und steigt ab einem Wert von 10000 nur noch nahezu linear an. Diese Aufhellung genügt aber anscheinend nicht, um die nebulösen Strukturen im Bild gut sichtbar werden zu lassen. Etwas aggressiver geht da ein logarithmischer Stretch vor:
x = np.linspace(1, 65500, num=65500)
y = np.log10(x)
plt.plot(x,y)
[<matplotlib.lines.Line2D at 0x2712637ba10>]
Ganz dunkle Pixel werden hier wesentlich deutlicher aufgehellt und auf unser FITS übertragen sieht das Resultat so aus:
img_norm = simple_norm(image_data, "log")
plt.imshow(image_data, cmap='gray', norm=img_norm)
plt.colorbar()
<matplotlib.colorbar.Colorbar at 0x2710de3ffd0>
Jetzt sind schon wesentlich mehr feine, nebelartige Strukturen (NGC 7380) zu erkennen. Gut zu sehen ist der aggressivere Stretch auch an der Skalierung der Helligkeitswert am rechten Rand der Grafik. Vergleicht man z.B. die Helligkeit des Pixelwertes 10000 im “log”-Stretch mit der Helligkeit im “sqrt”-Stretch dann wird klar, wie viel mehr die dunklen Pixel mit “log” gestreckt wurden. Darüber hinaus sind mit “simple_norm” noch weitere Stretches wie “sinh” oder “power” möglich. Eine Dokumentation der Funktion ist unter diesem Link zu finden.
Dieses kleines Beispiel hier sollte kurz verdeutlichen, wie unkompliziert man mit “atropy” FITS Dateien öffnen, visuell strecken und mit Matplotlib plotten kann.