PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Histogrammanpassung


Pinoccio
2010-10-26, 10:18:41
Hallo,

um automatisch Fotos aufzuhellen* nutze ich derzeit eine Gammakorrektur. Den dafür nötigen Parameter gamma berechne ich derzeit aus dem Mittelwert m des Helligkeitshistogramms (von 0 bis 255) mittels gamma= log(m)/log(140). Das liefert ganz brauchbare Ergebnisse, aber leider nicht immer. Da das Histogramm ja keine einfache Zahl ist, sondern eine Fläche ist, und die Gammakorrektur nicht linear funktioniert, liegt der neue Mittelwert mal richtig (also bei etwa 128) und mal nicht. Nun könnte ich iterativ vorgehen, d.h. mein Gammakorrektur immer wieder neu anwenden, bis mein Mittelwert am Ziel ist, aber das ist irgendwie unschön. Gibt es da nicht vielleicht eine tolle Idee?

* unterbelichtet wegen schwindendem Tageslicht bei fester Blende und Belichtungsszeit. Histogramme sind also i. d. R. mit einer Spitze und nicht bimodal oder sonstwas Kompliziertes.

Beispiel:
Start-Mittelwert 10, Automatischer Gammawert: 0,466, neue Mittelwert: 56.
Darauf wiederum angewandt wird das nächste Gamma zu 0,815 bestimmt, mit dann neuem Mittelwert 75.
Nächstes Gamma 0,874 führt zum Mittelwert 88.
Das ganze geht dann weiter, bis irgendwann der Mittelwert bei 120 stehen bleibt. Dorthin geht er übrigens unabhängig vom Startbild, wenn es denn vorher deutlich dunkler war. Ein zu helles Startbild geht gegen 136, fast ausgeglichenene Bilder (d. h. Mittelwert um 140) bleiben meist so. Die Differenz liegt wohl an Rundungsfehlern, da ich ja nur 8 bit habe zum Rechnen.

Histogramme:
http://www.abload.de/img/h11ne8.gif (http://www.abload.de/image.php?img=h11ne8.gif) Start
http://www.abload.de/img/h2gur2.gif (http://www.abload.de/image.php?img=h2gur2.gif) Nach einer Anwandung
http://www.abload.de/img/h355ul.gif (http://www.abload.de/image.php?img=h355ul.gif) nach zwei Schritten
http://www.abload.de/img/h0duwf.gif (http://www.abload.de/image.php?img=h0duwf.gif) Fixpunkt


mfg

Pinoccio
2010-10-26, 20:44:51
Niemand?

mfg

Gast
2010-10-26, 23:02:58
Muss es zwingend mit Gamma gemacht werden?
Was mir sonst auf die Schnelle einfällt: min und max Grauwert bestimmen und diesen Bereich auf den kompletten Grauwertbereich aufblasen. Z.b. min Grauwert=0, max Grauwert = 57, dann hast du die Range 0-57 die kannst du jetzt auf 0-255 aufblasen. Wenn dein Histogramm nicht auf einer Seite des Mittelwerts viel stärker/schwächer abfällt als auf der anderen ist der neue Mittelwert nachher immer ungefähr bei 128.

elianda
2010-10-26, 23:36:37
Mir wird irgendwie nicht klar, warum du gerade mit gamma bzw. log(m-140) arbeitest.
Weil Du eine quasi verlustfreie Abbildung der Helligkeitsverteilung rausbekommen willst?
Gamma verzerrt Dir deine Helligkeitsverteilung.

Du kannst doch zunaechst erstmal annehmen, dass es für 1 bis x% der Bildpixel nicht schlimm wäre, wenn sie zu dunkel oder zu hell waeren. Dann kannst Du die Grenzen deines Histogramms so setzen, dass Du links x% und rechts y% der Fläche (aka Bildpixelanzahl) abschneidest.
Danach machst Du ein Autolevel innerhalb dieser Grenzen. Man kann ja vorsichtig mit 0.1% anfangen. Wenn Die Fotos unterbelichtet sind, würd ich am oberen Ende des Histogramms mehr Anteil wählen.
Und dann kann man sich Gedanken machen, ob man den Punkt mittlerer Helligkeit weiter verschiebt. Da muss man jedoch aufpassen, weil das abhängig vom dargestellten Bildinhalt ist, ob das sinnvoll ist oder nicht.
Da kannst Du jetzt eine geeignete Skalierungsfunktion nehmen, die linear, logarithmisch oder Polynom 2x-ten Grades deine Helligkeitsverteilung im Histogramm verschiebt. Sobald man aber einen Anstieg in der Funktion hat, werden Helligkeitsverteilungen die vorher symmetrisch waren asymmetrisch. Das sieht man entsprechend schon oben in deinem letzten Bild.

Ansonsten rechne mit double ! Wenn Du mit Fliesskommafunktionen rechnest und dann immer wieder auf 8 Bit Ganzzahl speicherst, hast Du einen recht zerstoererischen Genauigkeitsverlust.
Es reicht vollkommen aus ganz am Ende wieder auf 8 Bit herunterzuskalieren.

Ach und - Wo sind denn die Zwischenwerte oben in deinen gerechneten Histogrammen hin? Warum laeuft der ursprüngliche Peak da zeilenweise auf der x-Achse auseinander?
Da stimmt schon irgendetwas nicht.

Pinoccio
2010-10-26, 23:55:56
Muss es zwingend mit Gamma gemacht werden?
Was mir sonst auf die Schnelle einfällt: min und max Grauwert bestimmen und diesen Bereich auf den kompletten Grauwertbereich aufblasen. Z.b. min Grauwert=0, max Grauwert = 57, dann hast du die Range 0-57 die kannst du jetzt auf 0-255 aufblasen. Wenn dein Histogramm nicht auf einer Seite des Mittelwerts viel stärker/schwächer abfällt als auf der anderen ist der neue Mittelwert nachher immer ungefähr bei 128.Gamma ist nicht zwingend, ich habe da praktisch freie Wahl*.
Die von dir vorgeschlagene Variante läuft allgemein unter (linearer) Kontrastanhebung. Problem ist hierbei, daß ein mögliches bzw. das vorhandene Rauschen max und min verdirbt. Ich werde es mal mit den 1%- bzw. 99%-Quantilen versuchen. Ich probiers mal aus, Ergebnisse gleich.
Und abhängig davon mache ich hinterher bei zu schmalem Histogramm eine Kontrastanhebung, in dem ich die Mitte auseinanderziehe.* Setz allerdings voraus, daß ich halt in der Mitte bin ...

Ich verwende nun als Beispiel folgendes unterbelichtete Bild (http://de.wikipedia.org/w/index.php?title=Datei:Belichtung_01.jpg&filetimestamp=20100522104404) aus der Wikpedia:
http://upload.wikimedia.org/wikipedia/commons/8/87/Belichtung_01.jpg

Bild geladen
Mean: 18 (grün)
Quartile (http://de.wikipedia.org/wiki/Quartil#Quartil): 1/3/19 (rot)
1%/99% (http://de.wikipedia.org/wiki/Quartil#Perzentil): 0/128
Maximum at: 1 (gelb)
http://www.abload.de/thumb/1l6nn.png (http://www.abload.de/image.php?img=1l6nn.png)

Autogamma mit gamma= log(m)/log(180) = 0,56
Mean: 39
Quartile: 11/21/55
1%/99%: 0/168
Maximum at: 0
http://www.abload.de/thumb/2zuim.png (http://www.abload.de/image.php?img=2zuim.png)

Weitere Ideen sind lokale Anpassungen, die ich aber eigentlich ungern vornehmen würde.

* solange es in realistischer Zeit, hier ca. 1 s für 1 Megapixel, berechenbar ist. Gamma benötigt ~100 ms.
* Gradiationskurve ist kubisches Spline durch (0,0) - (32,64) - (191,223) - (255,255)

mfg

Pinoccio
2010-10-27, 00:20:55
Hat sich etwas überschnitten mit meinem vorhergehenden Beitrag.
Mir wird irgendwie nicht klar, warum du gerade mit gamma bzw. log(m-140) arbeitest.
Weil Du eine quasi verlustfreie Abbildung der Helligkeitsverteilung rausbekommen willst?
Gamma verzerrt Dir deine Helligkeitsverteilung.Die 140 (jetzt: 180) sind frei gewählt, eigentlich hätte ich da 128 stehen haben sollen, da das ja der Zielwert ist.
Und Gamma, weil's schön glatt ist. ><Du kannst doch zunaechst erstmal annehmen, dass es für 1 bis x% der Bildpixel nicht schlimm wäre, wenn sie zu dunkel oder zu hell waeren. Dann kannst Du die Grenzen deines Histogramms so setzen, dass Du links x% und rechts y% der Fläche (aka Bildpixelanzahl) abschneidest.Das ist, wenn ich dich richtig verstehe, in etwa der Vorschlag des Gastes. Siehe unten.Danach machst Du ein Autolevel innerhalb dieser Grenzen. Man kann ja vorsichtig mit 0.1% anfangen. Wenn Die Fotos unterbelichtet sind, würd ich am oberen Ende des Histogramms mehr Anteil wählen.
Und dann kann man sich Gedanken machen, ob man den Punkt mittlerer Helligkeit weiter verschiebt. Da muss man jedoch aufpassen, weil das abhängig vom dargestellten Bildinhalt ist, ob das sinnvoll ist oder nicht.
Da kannst Du jetzt eine geeignete Skalierungsfunktion nehmen, die linear, logarithmisch oder Polynom 2x-ten Grades deine Helligkeitsverteilung im Histogramm verschiebt. Sobald man aber einen Anstieg in der Funktion hat, werden Helligkeitsverteilungen die vorher symmetrisch waren asymmetrisch. Das sieht man entsprechend schon oben in deinem letzten Bild.Was genau meinst du mit Autolevel? Eine Histogramspreizung? Wenn ja: Linear: siehe unten, Polynom aka kubisches Spline habe ich, wenn auch (noch) nicht flexibel, auch drin. Und dann halt Gamma. :-)Ansonsten rechne mit double ! Wenn Du mit Fliesskommafunktionen rechnest und dann immer wieder auf 8 Bit Ganzzahl speicherst, hast Du einen recht zerstoererischen Genauigkeitsverlust.
Es reicht vollkommen aus ganz am Ende wieder auf 8 Bit herunterzuskalieren.

Ach und - Wo sind denn die Zwischenwerte oben in deinen gerechneten Histogrammen hin? Warum laeuft der ursprüngliche Peak da zeilenweise auf der x-Achse auseinander?
Da stimmt schon irgendetwas nicht.Ebend darum, weil ich nur 8 bit habe. Die vorher dichtgerdängten Nadeln trennen sich auf.
Aber wie soll ich mit double rechnen, das ist mir nicht ganz klar.

Eine Spreizung des Histograms, so daß 1%/99%-Quantil auf 0/255 verschoben werden + lineare Zwischenwerte:
http://www.abload.de/thumb/1gnmu.png (http://www.abload.de/image.php?img=1gnmu.png)
(min/max sieht praktisch genauso aus - wenn das Bild nicht verrauscht ist).
Ein wirklich gutes Ergebnis, dem noch eine nicht-lineare Anpassung mittels Gamma nachgeschaltet dürfte mich zum Ziel führen. Bei meinen eigentlichen Bildern sieht es noch deutlich besser als als bei dem Beispielbild.

Und danach geht's dem dadurch verstärkten Farbrauschen von JPEG an den Kragen. :redface:


Danke für den Input! :smile:

mfg

Jotta
2010-10-27, 01:26:01
Nur so eine Idee zwischen Party und gleich Schlafengehen plus Bier:

Gamma-Korrektur ist ja I_out = I_in^gamma,
also I_out = exp( log(I_in)*gamma ),
also I_out = exp( exp(log(log(I_in)+log(gamma)) ).

Trage also dein Histogramm statt über x (Helligkeit) einfach mal
über log(log(x)) auf und berechne dann den Durchschnitt d_loglog.
Wenn du also 128 als Durchschnitt im Standard-Histogramm erreichen
willst, erhälst du
log(log(128)) = d_loglog + log(gamma)
bzw.
gamma = exp(log(log(128) - d_loglog).

Kleine Fehler sind der späten Zeit geschuldet, hoffe aber meine Idee
ist einigermaßen verstädnlich beschrieben.

Gruss Jotta

Pinoccio
2010-10-27, 09:23:05
Nur so eine Idee zwischen Party und gleich Schlafengehen plus Bier:

Gamma-Korrektur ist ja I_out = I_in^gamma,
also I_out = exp( log(I_in)*gamma ),
also I_out = exp( exp(log(log(I_in)+log(gamma)) ).

Trage also dein Histogramm statt über x (Helligkeit) einfach mal
über log(log(x)) auf und berechne dann den Durchschnitt d_loglog.
Wenn du also 128 als Durchschnitt im Standard-Histogramm erreichen
willst, erhälst du
log(log(128)) = d_loglog + log(gamma)
bzw.
gamma = exp(log(log(128) - d_loglog).

Kleine Fehler sind der späten Zeit geschuldet, hoffe aber meine Idee
ist einigermaßen verstädnlich beschrieben.Klingt auch nach einer Idee, schau ich mir auch mal an.
Resultat später.

mfg

Gast
2010-10-27, 16:53:47
Eine Spreizung des Histograms, so daß 1%/99%-Quantil auf 0/255 verschoben werden + lineare Zwischenwerte:
http://www.abload.de/thumb/1gnmu.png (http://www.abload.de/image.php?img=1gnmu.png)
(min/max sieht praktisch genauso aus - wenn das Bild nicht verrauscht ist).

Gegen das Rauschen (glaube aber nicht dass das hier so ein Problem darstellt wie du selbst gemerkt hast) kannst ja vor dem berechnen von min/max einmal mit Gauss drüberglätten (bzw. besser noch mit Median).

Ein wirklich gutes Ergebnis, dem noch eine nicht-lineare Anpassung mittels Gamma nachgeschaltet dürfte mich zum Ziel führen. Bei meinen eigentlichen Bildern sieht es noch deutlich besser als als bei dem Beispielbild.

Noch besser dürfte es werden wenn du die Spreizung nicht linear machst sondern eben abhängig von der tatsächlichen Grauwertverteilung z.B. indem du den Histogrammwert als "Gewicht" für die Spreizung verwendest - in dem Beispielbild würde dann im unteren Bereich wo das Histogramm hohe Werte hat stärker gespreizt werden.


Und danach geht's dem dadurch verstärkten Farbrauschen von JPEG an den Kragen. :redface:


Danke für den Input! :smile:

mfg

Pinoccio
2010-10-28, 11:50:27
Gegen das Rauschen (glaube aber nicht dass das hier so ein Problem darstellt wie du selbst gemerkt hast) kannst ja vor dem berechnen von min/max einmal mit Gauss drüberglätten (bzw. besser noch mit Median).Ja, sinnvolle Werte für die Grenzen zu suchen geht ganz gut.
Ich nutze momentan die 0,1%- und 99,9%-Quantile. Vorher glätten, egal ob Gauß oder sonstwie, und dann min/max geht aber auch. Der Unterschied bei meinen Bildern ist praktisch nicht vorhanden.
Noch besser dürfte es werden wenn du die Spreizung nicht linear machst sondern eben abhängig von der tatsächlichen Grauwertverteilung z.B. indem du den Histogrammwert als "Gewicht" für die Spreizung verwendest - in dem Beispielbild würde dann im unteren Bereich wo das Histogramm hohe Werte hat stärker gespreizt werden.abhängig von der tatsächlichen Grauwertverteilung - genau dafür suche ich ja eine Formel. ;-)

Das mit der Reduzierung des Farbrauschens ohne die Helligkeits anzufassen läuft übrigens nicht zufriedenstellend. Ich nehme von einer geblurten Version (7x7 Gauß) die Farbinfos und von einer geschärften Version* die Helligkeitsinformation (jeweils HSL-Farbraum) und packe das dann zusammen. Sieht im Ergebnis leider nicht brauchbar aus - z. T. im Gegenteil.

* 1/16* [[1,2,1], [2, -28, 2], [1, 2, 1]]

mfg