26. Juli 2026 · 🔭 Astronomie 🖥️ Technologie
Der Gedanke kam abends im Bett – ein Sonntag mit fremdem Siril-Code
Er kam kurz vor dem Einschlafen: Cyril Richard, einer der Siril-Entwickler, hat doch selbst ein Skript geschrieben, das mehrere Nächte kalibriert und stapelt. Ziemlich genau das, was mein eigenes Skript im ersten Teil macht. Warum habe ich da eigentlich noch nie hineingesehen?
Am nächsten Morgen – Sonntag, Hannover, Kaffee – war in Texas noch Nacht. Mein Rig bei Starfront stand auf Sh2-129, dem Fliegenden Fledermausnebel, und sammelte Ha und OIII: im einen Kanal die Fledermaus, im anderen die Aussicht auf den Squid, der sich fast ausschließlich in OIII zeigt. Zu bearbeiten gab es also nichts – die Daten entstanden gerade erst, 8.500 Kilometer weiter westlich.
Ein guter Vormittag, um zu lesen statt zu bauen.
Aus der einen Idee wurden drei Runden: erst Cyrils Skript, dann alles im offiziellen Repository, was mit Farbe zu tun hat, dann der Rest. Sechsundzwanzig fremde Skripte.
Es ging dabei nie darum, etwas abzuschreiben, sondern zu sehen, wie andere dieselben Probleme lösen – und zu verstehen, warum sie es so tun. Manches habe ich übernommen, manches bewusst nicht, und an einer Stelle hat mich fremder Code über meinen eigenen aufgeklärt.
Runde eins: das Skript, das dieselbe Aufgabe löst
AMSP ist das Skript aus dem nächtlichen Gedanken. Die Frage an die Analyse war nicht „was kann ich mitnehmen“, sondern: Was macht Cyril anders – und was davon macht er besser? Die Antwort war unbequemer, als mir lieb war.
Er gruppiert nach Belichtungszeit, ich habe nur gewarnt. AMSP bildet Gruppen aus Objekt, Filter und Belichtung. Mein Skript poolte alle Belichtungen eines Filters und suchte das Dark anhand eines repräsentativen Frames aus – ein Filter mit 120- und 300-Sekunden-Subs bekam also ein Dark, das nur der Hälfte passt. Eine Warnung gab es, aber eine Warnung repariert nichts.
Jetzt wird ein solcher Filter in Teilen kalibriert: jede Belichtung mit ihrem eigenen Dark, danach werden die Teile wieder zusammengeführt, noch vor der Registrierung.
Seine Dateinamen tragen das Rezept. AMSP baut den Namen aus den Header-Daten der geladenen Datei – dadurch kann er gar nicht falsch zugeordnet werden. Meine Zuordnung lief über eine interne Tabelle, die ich mit einigem Aufwand abgesichert hatte; seine Lösung braucht diese Absicherung erst gar nicht.
Aus M16_HA_fullframe.fit ist deshalb M16_HA_29x300s_G100_-10C_fullframe.fit geworden.
Der eigentliche Gewinn steckt in einer Absicherung, die ich mir dabei abgeschaut habe. Nach dem Ausrichten wird jeder Master gefragt, welchen Filter er selbst in seinen Header-Daten stehen hat – bevor sein Name geschrieben wird. Widerspricht das der internen Tabelle, fliegt der Kanal raus.
Denn ein Kanal unter falschem Namen ist der eine Fehler in dieser Kette, den danach nichts mehr bemerkt: Das Bild wäre fertig, farbkalibriert und plausibel – nur wäre Ha dort, wo OIII hingehört.
Zwei Punkte habe ich bewusst liegen lassen. Er korrigiert optische Verzeichnung schon während der Registrierung; bei meiner Brennweite liegt der Effekt vermutlich unter dem Rauschen.
Und er kalibriert grundsätzlich pro Nacht und führt erst danach zusammen – damit kann jedes Light das Flat seiner eigenen Nacht bekommen. Das ist die einzige echte Architekturdifferenz zwischen den beiden Skripten. Für ein fest montiertes Rig, an dem zwischen den Nächten niemand schraubt, wäre es ein großer Umbau für einen Vorteil, den ich nicht hätte.
Die Rejection-Stufen habe ich komplett von ihm übernommen. Welches Verfahren zum Aussortieren von Ausreißern das richtige ist, hängt davon ab, wie viele Frames gestapelt werden – bei vier Bildern taugt etwas anderes als bei dreihundert. Ich hatte dafür Schwellen nach Bauchgefühl gesetzt.
Cyril entwickelt Siril mit. Wenn er in seinem Skript festlegt, ab welcher Frame-Zahl von Perzentil auf Sigma, dann auf Winsorized, GESDT und schließlich Linear Fit gewechselt wird, dann hat er dafür Gründe, die ich nicht habe. Seine Schwellen sind durchdacht, meine waren geraten.
Der Vergleich zeigte Abweichungen in drei von fünf Bändern: Ich hatte Linear Fit in der Mitte stehen, er ganz oben; GESDT begann bei mir erst ab 50 Frames, bei ihm schon ab 31. Also stehen jetzt seine Stufen in meinem Skript, samt Quellenangabe im Kommentar.
Umgekehrt gibt es Bereiche, in denen mein Skript weiter ist: Es hält fertige Kalibrierungs-Master vor, statt sie bei jedem Lauf neu zu bauen, und es schreibt einen Bericht darüber, was tatsächlich passiert ist.
Und Farbe ist bei AMSP gar kein Thema – es endet beim ausgerichteten Master, während bei mir Palette, Komposition und Farbkalibrierung erst danach anfangen. Das ist kein Mangel, sondern ein anderer Zweck.
Runde zwei: wie andere Farbe machen
Wenn ein fremdes Skript so viel bringt – warum nur eines? Das offizielle Repository enthält inzwischen rund 65 Python-Skripte, und beim Zusammensetzen von Farbbildern ist der Fundus deutlich reicher als bei der Vorverarbeitung.
Der wichtigste Fund war eine Gegenposition, kein Rezept. In Cyril Richards PalettePicker.py steht eine ausdrückliche Design-Notiz: Diese Fassung setzt bewusst keine linearen Bilder zusammen, sondern erwartet bereits gestreckte Kanäle – sonst hätte das Skript selbst strecken müssen und dem Nutzer die Kontrolle über genau den Schritt genommen, der Geschmackssache ist.
Mein Skript macht es andersherum, weil die Farbkalibrierung lineare Daten braucht. Kein Widerspruch, eine andere Rollenverteilung. Aber die Notiz hat mich dazu gebracht, meine eigene Ha-Beimischung nachzurechnen – und da wurde es interessant.
Die Formel dahinter ist ein sogenannter Screen-Blend, kein simples Addieren. Auf linearen Daten sieht das so aus:
| Rot | Ha | Screen-Blend | schlichte Addition | Unterschied |
|---|---|---|---|---|
| 0,002 | 0,003 | 0,003497 | 0,003500 | 0,09 % |
| 0,02 | 0,03 | 0,034700 | 0,035000 | 0,86 % |
| 0,4 | 0,6 | 0,580000 | 0,700000 | 17,1 % |
Typische lineare Hintergrund- und Nebelwerte liegen zwischen 0,001 und 0,01 – also in den oberen beiden Zeilen. Dort ist mein Screen-Blend rechnerisch nicht von einer schlichten Addition zu unterscheiden; sein eigentlicher Charakter zeigt sich erst bei Helligkeiten, die im Linearen nur Sternkerne erreichen.
Kein Fehler – Addition ist eine völlig legitime Art, Ha beizumischen. Aber der Regler tut etwas anderes, als sein Name nahelegt, und das gehört in die Dokumentation.
Dieselbe Rechnung erklärt auch, warum ich die beliebten dynamischen Paletten nicht übernehmen kann: Ihr Gewichtungsfaktor hängt vom Produkt zweier Kanalwerte ab, und im Linearen liegt dieses Produkt bei etwa 0,000006. Die Formel fällt in sich zusammen, bevor sie irgendetwas gewichtet.
Fremde Kommentare sind manchmal teuer bezahlte Erfahrung. Dasselbe Skript übergibt sein Ergebnis nicht über eine Datei an Siril, sondern schiebt die Pixel direkt hinüber.
Daneben steht eine Warnung, die jemand offensichtlich schmerzhaft gelernt hat: Man darf dafür kein vorhandenes Mono-Bild als Vorlage laden und dessen Daten austauschen – Siril bleibt dann im Einkanal-Zustand, und das fertige Farbbild erscheint sporadisch grau. Man muss ein neues Bild anlegen.
Diese eine Zeile Kommentar hat mir vermutlich einen halben Abend Fehlersuche erspart. Ich habe den direkten Weg übernommen und damit zwei eigene Behelfslösungen entfernt.
Dazu kamen ein paar günstige Erweiterungen: sieben weitere Schmalband-Zuordnungen, zwei gewichtete Mischungen, eine synthetische Luminanz für Nächte ohne L-Filter – und ein hübscher Dreizeiler gegen die lila Sterne, die SHO-Bilder gern haben.
Einen Fund habe ich bewusst liegen lassen, obwohl er der sauberste wäre. Ein anderes Skript bestimmt rechnerisch, wie viel Ha bereits im Rot-Kanal steckt, statt es über einen Regler zu schätzen: Es probiert vierzig Skalierungsfaktoren durch, legt durch die verrauschten Ergebnisse eine geglättete Kurve und nimmt deren Scheitelpunkt.
Das ist die richtige Antwort auf eine Frage, die mein Regler nur umgeht. Es steht auf der Liste, aber es ist der größte Brocken.
Runde drei: quer durch die ganze Pipeline
Danach habe ich die Suche auf alles ausgedehnt, was mein Skript sonst noch tut – Kalibrierung, Registrierung, Stacking, Dateiverwaltung. Sechsundzwanzig Skripte, neunzehn davon in Bereichen, die ich auch abdecke.
Der wichtigste Fund betrifft etwas, das mein Skript bisher schätzt. Drei fremde Skripte benutzen dieselbe Schnittstelle: Siril gibt die Registrierungsdaten strukturiert heraus. Pro Frame stehen dort Halbwertsbreite, Rundheit, Güte, Hintergrundniveau und Sternzahl.
Das trifft ausgerechnet die Stelle, um die ich mich im Bericht seit Wochen herumformuliere: Die Frame-Anzahl im Dateinamen – die 29 in M16_HA_29x300s_G100_-10C – war bislang eine obere Schranke, weshalb im Bericht ein Kleiner-gleich-Zeichen davorstand. Eine Formulierung, die eine Lücke verkleidet, statt sie zu schließen.
Über die Schnittstelle wird daraus eine Messung, und aus „rund 29 Frames integriert“ werden pro Kanal echte Zahlen.
Der zweite Gewinn ist unsichtbar, aber wichtiger für die Haltbarkeit: Die Ausrichtungsqualität las mein Skript bisher als Text aus dem Siril-Protokoll – das funktioniert genau so lange, bis jemand eine Meldung umformuliert.
Eine Zwischenstufe, die zehn Zeilen kostet. Ein anderes Skript legt seine Arbeitskopien in drei Stufen an: erst Symlink, dann Hardlink, dann echte Kopie. Ich hatte nur zwei. Der Hardlink dazwischen belegt keinen zusätzlichen Speicher und greift dort, wo Symlinks nicht erlaubt sind.
Vor allem aber ist er robuster gegen genau den Vorfall, der mich vor einiger Zeit einen Abend gekostet hat: Ein Cloud-Sync-Dienst hatte Sirils Symlinks „repariert“. Ein Hardlink ist kein Verweis, den man reparieren könnte, sondern ein zweiter Name für dieselbe Datei.
Flats werden geprüft, nicht nur benutzt. Der eleganteste Gedanke kam aus einem kleinen Analysewerkzeug: Teilt man zwei Flats durcheinander, muss idealerweise eine gleichförmige Fläche herauskommen. Die Streuung dieses Ergebnisses ist ein Maß dafür, ob sich zwischen den beiden Aufnahmen etwas verändert hat. Eine Perzentil-Betrachtung sagt zusätzlich, in welche Richtung – dunkle Ausreißer deuten auf Staub oder Vignettierung.
Mein Skript hat Flats bisher genommen, wie es sie fand, und über Nächte hinweg zusammengeworfen; der Schalter dafür verlässt sich darauf, dass ich weiß, ob zwischendurch am Aufbau geschraubt wurde. Jetzt rechnet das Skript nach, bevor es zusammenwirft.
Einen vierten Vorschlag habe ich liegen lassen. Ein Skript hängt einen Datei-Überwacher an den Arbeitsordner und löscht jede Zwischengeneration in dem Moment, in dem ihre Nachfolgerin erscheint – bei hundert Subs sind das mehrere Gigabyte Unterschied.
Der Überwacher selbst kommt mir nicht ins Skript: eine zusätzliche Abhängigkeit und ein Wettlauf mit Sirils eigenen Schreibvorgängen. Das deterministische Äquivalent steht auf der Liste.
Bei einem guten Dutzend Skripten war schlicht nichts zu holen: Mosaike aus Smart-Teleskopen, Kometen-Strichspuren, Satellitenspur-Entfernung, mehrere Verbesserungs-Suiten. Sie arbeiten alle nichtlinear oder in Bereichen, die meine Pipeline gar nicht berührt. Auch das ist ein Ergebnis – man muss es nur einmal nachgesehen haben.
Was ich mitnehme
Fremder Code ist ein Prüfer, den man nicht selbst gebaut hat. Meine eigenen Tests finden das, woran ich beim Schreiben gedacht habe. Ein Skript, das dieselbe Aufgabe anders löst, zeigt die Annahmen, die ich nie hinterfragt habe – etwa, dass ein Filter nur eine Belichtungszeit hat.
Der größte Gewinn war nichts, was ich übernommen habe. Die Design-Notiz in einem fremden Farbskript hat an meiner Architektur nichts geändert – sie hat mich nur dazu gebracht, meine eigene Formel nachzurechnen. Ergebnis: Sie rechnet richtig, heißt aber anders, als sie sich verhält. Das hätte ich beim Abschreiben nie erfahren.
Kommentare in fremdem Code sind geschenkte Erfahrung. Eine einzige Warnzeile über einen Zustand, in dem Siril einkanalig bleibt, hat mir einen halben Abend Fehlersuche erspart. Jemand hat diesen Abend bereits bezahlt und aufgeschrieben, was er dabei gelernt hat.
Auch ein Nein ist ein Ergebnis. Ein gutes Dutzend Skripte hatte nichts für mich, und vier gute Ideen habe ich bewusst nicht übernommen – Kalibrierung pro Nacht, Verzeichnungskorrektur, der Datei-Überwacher, die rechnerische Ha-Bestimmung.
Das sind jetzt Entscheidungen mit Begründung statt Lücken, von denen ich nichts wusste.
Am Ende des Vormittags stand kein einziges Feature, das mir selbst eingefallen wäre. In Texas war die Nacht inzwischen vorbei, und die Daten von Sh2-129 warten auf ein Skript, das ein Stück besser ist als am Abend zuvor – größtenteils, weil ich fremden Quelltext gelesen habe statt eigenen.
Ich glaube, ich habe jetzt das für mich optimale Mono-Train-Skript gebaut. Und genau das ist das Schöne an Open Source und der GPL 3: Alles liegt offen, jeder kann hineinsehen, und daraus wird Austausch und gegenseitiges Lernen.
Ohne die Skripte der anderen wäre dieser Vormittag nicht möglich gewesen – und selbstverständlich steht mein Skript allen Interessierten auf GitHub zur Verfügung.
🔭 Worum es bei dem Skript überhaupt geht: Sieben Filter, ein Knopfdruck → · Alle Funktionen: ImageMono Train im Detail