FFT anwenden auf Pixelwerte

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • FFT anwenden auf Pixelwerte

    Hi,

    ich sitze hier an einem recht komplexen Thema was meine Physik-Kenntnisseübersteigt. Ich hoffe jemand von euch kann mir dabei helfen.

    Es geht dabei darum, die Qualität (Hochkontrast-Auflösung) eines 16bit Graustufenbildes zu ermitteln. Ein Beispiel eines solchen Bildes habe ichangehängt. Der weiße Punkt in dem Bild ist die Aufnahme eines sehr dünnen Drahtes mitder Dichte von 500HU (hounsfield Units) und drum herum ist Wasser mit der Dichte von 0. Der Punkt strahlt jetzt aus und daraus kann man die Qualität des Bildes errechnen.
    Das geht, indem man zunächst die Point-Spread-Function ermittelt und daraus dann die Line-Spread-Function. Diese ergibt dann eine Kurve die ungefähr so aussieht wie Bild2 (Nur mal eben von Hand gezeichnet). Im Prinzip also eine ausschwingende Kurve (Überstrahlung des Punktes)
    Aus diesen Werten kann man nun den MTF ermitteln, indem man eine FourierTransformation darauf anwendet. Das Ergebnis sollen Werte sein in dem Format lp/cm also LinePairs/cm, was der Auflösung des Bildes und damit der Qualität entspricht.
    Da hört es bei mir aber auf. Ich bekomme einfach kein sinnvolles Ergebnis. Das wird daran liegen, dass ich die FFT nie richtig verstanden habe. Ich gehe da mit 2 Werte-Arrays rein. Mit einem Array der reellen Zahlen und einem der imaginären Zahlen und heraus bekomme ich wieder ein Array mit 2*N Werten mit denen ich aber einfach nichts anzufangen weis. Ich weiß auch nichtwas der imaginäre Anteil meiner Pixelwerte eigentlich sein soll. Alles lesen im Internet bringt mich auch nicht wirklich weiter. Ich verstehe zwar prinzipiell was FFT macht, wie man es praktisch anwendet kapier ich aber einfach nicht. Vieelicht stimmt auch schon miene Normierung der LSF Werte nicht und ich gebe der FFT falsche Werte rein?

    Hat jemand da eine Idee oder hat sowas eventuell sogar schonmal gemacht oder kann mir einfach mal erklären wie das mit der FFT so richtig gemacht wird?

    Danke

    Claus
    Dateien
    • 1.bmp

      (270,05 kB, 345 mal heruntergeladen, zuletzt: )
    • 2.bmp

      (153,53 kB, 331 mal heruntergeladen, zuletzt: )
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Genau. LSF ist eindimensional. Ich habe also nur ein einfaches Wertearray, das so aussieht wie Bild 2 und ich habe keine Ahnung wie ich das jetzt der FFT geben soll...
    Wobei ich natuerlich noch als zweiten Wert die Pixelgröße habe. Sprich ich weiß, das ein Pixel 0.488281mm groß ist. Das könnte dann mein zweiter Wert sein.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Die X-Achse auf dem Graph ist die Pixelposition in X. Also in denm Fall geht das über 48 Pixel. Das kann ich natürlich auch genauso gut in mm ausdrücken. Das wären dann eben 48*0.488281mm (Also ca. 23mm)

    Ja da ist eben schluß mit meinem Verständnis. Ich bekomme als Rückgabe aus der FFT Funktion ein Array das 2x die Anzahl meiner Input-Werte enthält. Ich dachte auch das wären vielleicht Komplexe Zahlen in Form von Reaal,Imaginär im Wechsel aber die Zahlen die ich bekomme sehen eher so aus

    0.031183954246518084 - 0.0
    -0.03113002403369004 - -2.1289168403511785E-4
    0.03097092978837511 - 4.230270114714979E-4
    -0.030714597873733266 - -6.278819155487159E-4
    0.030373706205823654 - 8.253762954672708E-4
    -0.029964919700599772 - -0.0010140461560676967
    0.02950788663010056 - 0.0011931605386727453
    -0.02902405755782321 - -0.001362772127028036
    0.02853539927926883 - 0.0015236959186662152
    -0.02806308241487459 - -0.001677416376860694
    0.027626222612738255 - 0.0018259295470343605
    -0.027240751654403733 - -0.001971532252518238
    0.026918486371142924 - 0.002116575226180493
    -0.02666645072175183 - -0.0022632004993927454
    0.026486490468799445 - 0.0024130852652735667
    -0.02637520163980932 - -0.00256721458393643
    0.026324174536025074 - 0.002725703660389191
    -0.026320535683500575 - -0.0028876870942837573
    0.026347752025562013 - 0.0030512876995413517
    -0.026386645957611993 - -0.0032136715613775373
    0.026416557467811838 - 0.00337118937040544
    -0.02641658141062574 - -0.003519597240645618
    0.026366804276494196 - 0.0036543436970851314

    und damit kann ich gar nichts anfangen.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • FFT liegt bei mir auch schon eine Weile zurück, so alles weiß ich das auch nicht mehr. Aber da Du nur 48 diskrete Werte hast, also nicht zwei hoch irgendwas, müsstest Du ja eine DFT machen und keine FFT. Was mittlerweile auch für größere Datenreihen in ordentlicher Geschwindigkeit möglich ist.
  • Thallius schrieb:

    Ich fülle die restlichen werte einfach mit 0 auf bis ich 512 Werte habe. Deshalb müßte FFT ja funktionieren.

    Ach du Schande, das ist mal ein Fauxpas. Also bis 68 wäre besser gewesen. Erklärt aber nicht warum du die doppelte Anzahl an Werten zurück bekommst (so hab ich dich verstanden). Wie lautet deine FFT-Funktion denn die du verwendest?
    [self setSignature:null];
    [[self postCount] increment];
  • Mike schrieb:

    Thallius schrieb:

    Ich fülle die restlichen werte einfach mit 0 auf bis ich 512 Werte habe. Deshalb müßte FFT ja funktionieren.

    Ach du Schande, das ist mal ein Fauxpas. Also bis 68 wäre besser gewesen. Erklärt aber nicht warum du die doppelte Anzahl an Werten zurück bekommst (so hab ich dich verstanden). Wie lautet deine FFT-Funktion denn die du verwendest?


    Du meinst sicher 64 oder? Ich nehme die 512 absichtlich weil es so in einem Doc beschrieben ist. Warum die das so machen ist mir auch nicht ganz klar.

    Wenn Du Lust hast Kannst du dir das ja mal durchlesen. Ist nicht besonders lang

    jacmp.org/index.php/jacmp/article/viewFile/3905/2941

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Wenn ich das richtig verstanden habe sind die 512 aber nicht die Anzahl der Werte der LSF sondern die Auflösung der LSF in der Abszisse. Was mir heute Abend noch nicht wirklich klar ist und auch nicht klar werden wird heute Abend ist, warum man da überhaupt ein Zero-Padding der LSF macht. Nach der Normierung der LSF auf sich selbst ist das IMO überflüssig, zumindest sehe ich da grade keinen Vorteil.
    [self setSignature:null];
    [[self postCount] increment];
  • Ein paar hoffentlich hilfreiche Anmerkungen:

    - Die FFT ist komplex, daher brauchst Du Real- und Imaginärteil. In deinem Eingangsbild hast Du natürlich keine imaginären Werte, daher ist es vollkommen korrekt, den Imaginärteil jeweils auf 0 zu setzen.

    - Weil Du keinen Imaginärteil im Input hast, ist deine Ausgabe symmetrisch, Du brauchst also nur die ersten N/2 Werte anzuschauen. Je nach benutzter Bibliothek für die FFT kann das Ergebnis aber verschoben sein, so dass der Gleichanteil (DC) nicht der 0te Wert bzw. nicht genau in der Mitte liegt.

    - Zero-padding ist kritisch, ich weiss nicht genau, warum sie das in dem Paper machen (habs aber auch nur überflogen), da man eben künstlich Frequenzen ins Bild hinzufügt. Stell auf jeden Fall sicher, dass Du nicht einfach am Ende mit 0 auffüllst, sondern links und rechts gleichermassen.

    - Im transformierten bekommst Du mit sqrt(Re*Re+Im*Im) die Magnitude (Amplitude), also wie stark die entsprechende Frequenz ist

    - Mit atan2(Re,Im) bekommst Du den Phasenwinkel

    Nebenbemerkung: In die FFT kommen keine Pixelwelte (laut Paper) sondern die LSF, die Du durch integrations des ROI erhälts.

    Mit etwas konkreteren Fragen kann ich vielleicht auch konkreter Antworten :) Sieht aber nicht sonderlich komplex aus. So eine Aufgabe würde ich aber evtl lieber in MATLAB prototypen und dann auf C++ (oder was-auch-immer) portieren.

    EDIT: Soweit ich das Paper richtig verstehe, hast Du im Eingangsbild auch negative Werte (klingt auch ein wenig schlüssig, dadurch kann man die PSF auch besser ermitteln..) Evtl. musst Du also Dein Graustufenbild shiften. Weiss nicht, ob Du das gemacht hast.
    C++

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von zerm ()

  • Hi Zerm,

    danke für Deine Antwort. Ich schreibe mal bischen was dazu.

    zerm schrieb:


    - Weil Du keinen Imaginärteil im Input hast, ist deine Ausgabe symmetrisch, Du brauchst also nur die ersten N/2 Werte anzuschauen. Je nach benutzter Bibliothek für die FFT kann das Ergebnis aber verschoben sein, so dass der Gleichanteil (DC) nicht der 0te Wert bzw. nicht genau in der Mitte liegt.


    Das habe ich mittlerweile auch schon herausgefunden.


    - Zero-padding ist kritisch, ich weiss nicht genau, warum sie das in dem Paper machen (habs aber auch nur überflogen), da man eben künstlich Frequenzen ins Bild hinzufügt. Stell auf jeden Fall sicher, dass Du nicht einfach am Ende mit 0 auffüllst, sondern links und rechts gleichermassen.


    Das habe ich sebstverständlich so gemacht. Ich kann mir in diesem Fall eigentlich auch nicht vorstellen das es kritisch ist, da die Kurve ja eh ausflachen würde.


    - Im transformierten bekommst Du mit sqrt(Re*Re+Im*Im) die Magnitude (Amplitude), also wie stark die entsprechende Frequenz ist
    - Mit atan2(Re,Im) bekommst Du den Phasenwinkel


    Das sind mal ganz wichtige Informationen für mich. Damit kann ich jetzt mal ein wenig rumspielen und die Ergebniswerte umrechnen.


    Nebenbemerkung: In die FFT kommen keine Pixelwelte (laut Paper) sondern die LSF, die Du durch integrations des ROI erhälts.


    Sicher, das habe ich ja auch gemacht.


    EDIT: Soweit ich das Paper richtig verstehe, hast Du im Eingangsbild auch negative Werte (klingt auch ein wenig schlüssig, dadurch kann man die PSF auch besser ermitteln..) Evtl. musst Du also Dein Graustufenbild shiften. Weiss nicht, ob Du das gemacht hast.


    ja, ich habe die LSF Werte die ich ermittelt habe geschiftet. Denke das sieht man auch in bild2. Sonst wären ja alle Werte im Plus, denn negative Pixelwerte gibt es nicht :)

    Nochmal danke, ich spiele jetzt mal ein wenig mit den Ergebnisswerten rum und melde mich dann wieder wie weit ich gekommen bin.

    Gruß

    Claus
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Thallius schrieb:



    - Zero-padding ist kritisch, ich weiss nicht genau, warum sie das in dem Paper machen (habs aber auch nur überflogen), da man eben künstlich Frequenzen ins Bild hinzufügt. Stell auf jeden Fall sicher, dass Du nicht einfach am Ende mit 0 auffüllst, sondern links und rechts gleichermassen.


    Das habe ich sebstverständlich so gemacht. Ich kann mir in diesem Fall eigentlich auch nicht vorstellen das es kritisch ist, da die Kurve ja eh ausflachen würde.



    Ob hinten oder vorne oder beides mit Null auffüllen, dürfte doch nur einen Unterschied in der Phasenlage und nicht in der Amplitude geben. Bin mir nicht mehr sicher ob es die Fourier-Transformation oder die FFT war, jedenfalls funktioniert das eigentlich nur bei periodischen Signalen.
  • manoh schrieb:

    Thallius schrieb:



    - Zero-padding ist kritisch, ich weiss nicht genau, warum sie das in dem Paper machen (habs aber auch nur überflogen), da man eben künstlich Frequenzen ins Bild hinzufügt. Stell auf jeden Fall sicher, dass Du nicht einfach am Ende mit 0 auffüllst, sondern links und rechts gleichermassen.


    Das habe ich sebstverständlich so gemacht. Ich kann mir in diesem Fall eigentlich auch nicht vorstellen das es kritisch ist, da die Kurve ja eh ausflachen würde.



    Ob hinten oder vorne oder beides mit Null auffüllen, dürfte doch nur einen Unterschied in der Phasenlage und nicht in der Amplitude geben. Bin mir nicht mehr sicher ob es die Fourier-Transformation oder die FFT war, jedenfalls funktioniert das eigentlich nur bei periodischen Signalen.

    Uh, ja, Du hast natürlich recht :) Weiss nicht mehr, warum ich mir das so angewöhnt hatte...
    C++