FITS-Bilder rotieren

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Guten Abend,

ich habe da ein Problem Bilder (vom Format FITS/FIT) zu drehen.
Leider kann man das bei FITS Bilder nicht wie JPEG Bilder per rotate()-Methode (oder ähnlichem)..
Deshalb versuche ich die Bilder selber pixelweise zu "drehen".

Code: Alles auswählen

import pyfits

#Ausgangsbild
altBild = pyfits.open('Testbilder\Testbild.fits')
altpix = altBild[0].data

#Ausgangsbild das gedreht werden soll
neuBild = pyfits.open('Testbilder\Testbild.fits')
neupix = neuBild[0].data

#Zu rotierender Winkel
w = 0.5

#Pixelweise drehen
for i in range(255):
    for j in range(255):

        x = round(i * math.cos(w) - j * math.sin(w))
        y = round(i * math.sin(w) + j * math.cos(w))

        if(x < 255 and y < 255):
            neupix[j][i] = altpix[y][x]
Mein Hauptproblem ist nur, dass das Bild an der unteren linken Ecke gedreht wird, und nicht in der Mitte, wie ich es gerne hätte.
Ich hab's schon versucht, indem ich ein wenig an den Indizes spiele, aber hab' es nicht hinbekommen.
Kann mir da einer helfen?
Zuletzt geändert von barisoezcan am Dienstag 9. April 2013, 19:42, insgesamt 2-mal geändert.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Im Prinzip ist es ganz einfach: du verschiebst das Bild so, dass der gewünschte Rotationspunkt p auf (0, 0) liegt. Dann rotierst du das Bild und anschließend verschiebst du das Bild wieder um -p zurück. Das machst du jetzt natürlich nicht wirklich, sondern stellst einfach die dazugehörige Gleichung auf.

Edit: Warum range(254), der spätere Test aber auf 255? Das Erstellen des Zielbildes geht sicher auch ohne erneutes Lesen der Datei.
Das Leben ist wie ein Tennisball.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Hatte mich vertan. :)
Und ich weiss (noch nicht) wie ich ein neues FITS-Bild erzeuge, da wollte ich es erstmal mit einer schnellen, unsauberen Lösung testen.
Ich versuche deinen Lösungsvorschlag nachher mal, danke.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Hallo barisoezcan,
wenn Du versuchst, auf Deine Art und Weise Bilder zu drehen wird es sicher Löcher geben, weil eben ein gedrehtes Raster nicht mehr exakt auf das ursprüngliche Raster passt. Außerdem wird es negative Indizes geben, so dass Du wieder von rechts in das Bild hineinläufst.
Versuch doch die Daten in ein numpy-Array zu konvertieren und mit scipy.ndimage.rotate zu rotieren.
BlackJack

Ich glaube da muss man nicht viel versuchen, denn `pyfits` hat `numpy` als Abhängigkeit. Würde mich sehr wundern wenn die Daten nicht schon als `numpy`-Array zurückgegeben werden.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@Sirius: Es gibt keine Löcher, er iteriert über die Zielpixel. Hier bietet sich vielleicht noch eine Interpolation an, hängt natürlich von den Daten ab. An den Ecken wird es allerdings Probleme geben, da dort die Pixel nicht gesetzt werden, wenn im Quellbild kein Pixel gefunden wurde.
Das Leben ist wie ein Tennisball.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Hallo,
wenn ich ein 255x255 großes Bild mit der "scipy.ndimage.filters.median_filter()"-Methode filtern möchte, bekomme ich einen "MemoryError".
Meine Vermutung: Das Bild ist wahrscheinlich zu groß dafür.
Bei Bildern bis zu der Größe von ca. 130x130 funktioniert es noch.
Gibt es eine elegante Möglichkeit so ein größeres Bild median-zufiltern?
Mir fällt nur die Möglichkeit ein, das Array mit den Bildpunktdaten zweimal (ggf. mehrfach) zu teilen und dann auf jedes dieser Teile den Filter anzuwenden.
BlackJack

@barisoezcan: Selbst wenn die 255×255 Pixel als RGB-Werte mit 96-Bit Gleitkommazahlen gespeichert wären, bräuchte so ein Bild nur cirka 2 MiB Speicher. Das hier läuft problemlos durch und der gesamte Prozess belegt bei mir maximal 60 MiB:

Code: Alles auswählen

#!/usr/bin/env python
from numpy.random import random
from scipy.ndimage.filters import median_filter

def main():
    image = random((3, 255, 255))
    filtered_image = median_filter(image, size=10)


if __name__ == '__main__':
    main()
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Ich hatte als zweiten Parameter bei median_filter die Größe des Bildes angegeben (255, 255).
Das war wohl falsch.
Wofür aber ist der "size"-Parameter sonst?
"size gives the shape that is taken from the input array, at every element position, to define the input to the filter function." sagt mir jetzt nicht wirklich was...
Möglicherweise die Größe der Filtermatrix? Aber die Größe müsste dann 2x2, 3x3, 4x4, usw. sein...

P.S.: Mit size=10 funktioniert es. Je nachdem ob size kleiner oder größer ist, scheint das Bild mehr oder weniger stark gefiltert zu werden.
BlackJack

@barisoezcan: Du wendest einen Filter an, ohne zu wissen was der eigentlich macht? Für jedes Pixel wird ein neuer Wert berechnet, nämlich der Median aller Pixel im `size` grossen Rechteck bei dem das Pixel im Mittelpunkt liegt.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Doch, ich weiss schon was der macht, aber nicht genau was "size" beschreibt.
Das Rechteck ist also ein Quadrat mit der Seitenlänge von "size"?
Wenn ja, dann muss die Seitenlänge des Quadrats doch eine ungerade Zahl sein, damit der Pixel in der Mitte auch wirklich in der Mitte liegen kann.
BlackJack

@barisoezcan: Das und was mit Pixeln am Rand passiert, ist sicher irgendwo dokumentiert.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Wenn ich z.B. dieses Bild automatisch drehen möchte, so dass die dicke "Linie" waagerecht ist, wie muss ich dann vorgehen?
Bild

Mein Ansatz:
1.Durch das Bild laufen und die Koordinaten des linkesten und des rechtesten weissen Pixels abspeichern.
2.Mit diesen beiden Koordinaten die "Steigung" der Figur berechnen.
3.Aus der "Steigung" den Winkel berechnen.
4.Das Bild um diesen Winkel mit der rotate()-Methode drehen.

Am 2.Punkt hakt es leider, weil ich keine Formel dafür aufstellen konnte, mit der man aus beiden Koordinaten die Steigung berechnet.
Habe es mit

Code: Alles auswählen

steigung = (k2[0]/k2[1]) / (k1[0]/k1[1]) #zB fuer k2 = 160,155 und k1 = 10,15
und ähnlichem versucht.

PS: Mir ist klar, dass die Linie nach einmaligem Ausführen von diesem Algorithmus nicht genau waagerecht sein wird, aber nach 3-4 maligem Durchlaufen müsste es relativ genau sein.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Das Stichwort lautet Hauptkomponentenanalyse. Das musst du auch nicht selber implementieren, matplotlib hat da schon etwas Fertiges. Ansonsten ist es eine ganze nette Übung, die Mathematik dahinter ist nicht sonderlich schwer. Damit bekommst du dann auch die optimale Rotation.

Edit: Um noch auf deine Frage einzugehen: Die Drehung kannst du mittels atan2 bestimmen. Wenn du zwei Punkte (x1, y1) und (x2, y2) hast, dann ist der Winkel atan2(y2-y1, x2-x1). Dabei "rotiert" der zweite Punkt um den ersten.
Das Leben ist wie ein Tennisball.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

EyDu hat geschrieben:Hallo.

Das Stichwort lautet Hauptkomponentenanalyse. Das musst du auch nicht selber implementieren, matplotlib hat da schon etwas Fertiges. Ansonsten ist es eine ganze nette Übung, die Mathematik dahinter ist nicht sonderlich schwer. Damit bekommst du dann auch die optimale Rotation.

Edit: Um noch auf deine Frage einzugehen: Die Drehung kannst du mittels atan2 bestimmen. Wenn du zwei Punkte (x1, y1) und (x2, y2) hast, dann ist der Winkel atan2(y2-y1, x2-x1). Dabei "rotiert" der zweite Punkt um den ersten.
Hab mir das nun ein wenig durchgelesen, aber da mir das vollkommen neu ist, komme ich nicht wirklich weiter.
Beim Erzeugen des Objektes übergibt man der Klasse PCA das gesamte numpy-Array mit den Bildpunktdaten, oder?
Und inwiefern hilft mir das die passende Rotation für mein Bild zu finden?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Ja, du steckst das Bild (binarisiert oder in Graustufen, das hängt von deinem Problem ab) in den PCA, bekommst zwei Haupkomponenten, nimmst die Hauptkomponente mit dem größten Eigenwert und drehst dann nur noch. Um welchen Winkel du rotieren musst, sollte nach dem Wikipedia-Artikel (durch pures anschauen der Bilder) doch offensichtlich sein.
Das Leben ist wie ein Tennisball.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

EyDu hat geschrieben:Ja, du steckst das Bild (binarisiert oder in Graustufen, das hängt von deinem Problem ab) in den PCA, bekommst zwei Haupkomponenten, nimmst die Hauptkomponente mit dem größten Eigenwert und drehst dann nur noch. Um welchen Winkel du rotieren musst, sollte nach dem Wikipedia-Artikel (durch pures anschauen der Bilder) doch offensichtlich sein.
Bild
Wenn ich dieses binarisierte, median-gefilterte Bild dem PCA übergebe mittels:

Code: Alles auswählen

result = PCA(pix)
erhalte ich die Fehlermeldung:
numpy.linalg.linalg.LinAlgError: SVD did not converge

Wenn ich aber das gleiche Bild unbinarisiert und ungefiltert (unteres Bild) dem PCA übergebe, funktioniert es.
Bild

Was genau habe ich unter dieser Fehlermeldung "SVD konvergierte nicht" zu verstehen?

Ich habe es einige Male mit verschieden starker Binarisierung und Filterung getestet und erst wenn das Bild weniger "Rauschen" enthält, bekomme ich diese Fehlermeldung.
Für mich ist es wichtig, so wenig wie möglich Störung im Bild zu haben, deshalb ist also eine Binarisierung und Filterung notwendig.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Hat niemand eine Idee? :/
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Ich tippe mal auf NaNs oder INFs in den binarisierten Bildern, das verursacht ganz gerne Probleme.
Das Leben ist wie ein Tennisball.
barisoezcan
User
Beiträge: 73
Registriert: Freitag 15. März 2013, 19:38

Habe das gesamte Bild nach der Bildvorverarbeitung (Binarisierung & Filterung) auf NaN und INF überprüft. Es gibt keine.
Antworten