# Image: Kontrast, Helligkeit und Farben ändern?



## Matrim (25. Aug 2004)

Hallo,

weiss jemand, wie ich die Farben, den Kontrast und die Helligkeit eines Image in Java ändern kann?
Oder einen Hinweis?

Danke, Mat.


----------



## Roar (25. Aug 2004)

schau mal hier: http://java.sun.com/developer/JDCTechTips/2004/tt0406.html#1
und hier: http://java.sun.com/developer/JDCTechTips/2004/tt0210.html#1


----------



## Matrim (26. Aug 2004)

Okay, 

danke erstmal.

Hab es mir angeschaut und das mit der Helligkeit hab ich ganz gut hinbekommen, denk ich.
Keine Ahnung, wie das mit der Farbe geht, also komplett in Grayscale kippen kann ich, aber so stufenweise ... =(

Contrast hab ich im Moment keine Idee.


Weiterhin, in welche Reihenfolge sollte ich die Manipulationen anwenden?

Danke, Mat.


----------



## Matrim1 (29. Aug 2004)

Problem ist auch, wenn ich den Kontrast ändere, dann die Helligkeit, dann den Kontrast wieder zurück und dann die Helligkeit wieder zurück, ob es das gleiche Bild wäre, wie das Ausgangsbild ....
Müsste es nicht dann so eine Gesamtformel geben, in der wir jeden RGB Punkt in seine Farbbestandteile zerlegen und dann eine Zusammenführung basteln, in der Kontrast, Farbe und Helligkeit mit hineinspielen?


----------



## Thorsten (30. Aug 2004)

Okay... das, was du suchst, ist der LuT   
LuT == Lookup-Table

Die Helligkeit und der Kontrast hängen beide fest 
zusammen über eine simple Geradengleichung
(siehe Mathematik).

Also man kann beide Werte auch ohne LuT ändern,
klar. Nur dauert das viel zu lange. Du musst ja
die Formel für alle Pixel im Bild neu berechnen...

Oder auch nicht. Mit dem LuT hast du für jede 
Änderung nur 255 Berechnungen. Okay, bei
einem kleinen Icon ist das Verfahren vielleicht
schlecht. Aber wenn du ein Foto hast, ist der
Unterschied extrem.

Hier eine Klasse von mir. Die Bezeichnungen
sind der Mathematik nach vergeben. 

"a" und "b" sind Steigung und Schnittpunkt
mit der y-Achse. 

Unten sieht man die berühmte Formel,
die jeder auswendig können sollte:
y = a * x + b


```
public class LUT
{
    private int[] Value;
    private int a = 1;
    private int b = 0;
    
    public LUT()
    {
        Value = new int[256];
        create();
    }

    public int getLUTValue(int x)
    {
        return Value[x];
    }

    public void setA(int a)
    {
        this.a = a;
        create();
    }

    public void setB(int b)
    {
        this.b = b;
        create();
    }

    private void create()
    {
        for (int x = 0; x <= 255; x++)
        {
            Value[x] = a * x + b;
            
            if (Value[x] > 255)
            {
                Value[x] = 255;
            }
            
            if (Value[x] < 0)
            {
                Value[x] = 0;
            }
        }
    }
}
```

Wie gehts weiter? Nun hast du ein Foto in einem
BufferedImage. In einer Schleife liest du nun mit
getRGB() die Werte aus dem Bild. Diesen int-Wert
musst du noch in seine R-, G- und B-Teile aufteilen.

Dazu muss man mit BitShifting arbeiten... auch kein
einfaches Thema. Die Klasse Color von Java kannst
du vergessen, weil du für jeden Pixel eine neue Instanz
erzeugen müsstes *lol*

Also noch ein Geschenk von mir:

```
public class RGBColor
{
    private int Farbe;
    
    public RGBColor()
    {
    }

    public void setColor(int RGB)
    {
        Farbe = RGB;
    }

    public int getRed()
    {
        return (Farbe >> 16) & 0xFF;
    }

    public int getGreen()
    {
        return (Farbe >> 8) & 0xFF;
    }

    public int getBlue()
    {
        return (Farbe >> 0) & 0xFF;
    }

    public void setRGB(int R, int G, int B)
    {
        Farbe = ((255 & 0xFF) << 24) | ((R & 0xFF) << 16) | ((G & 0xFF) << 8)  | ((B & 0xFF) << 0);
    }

    public int getRGB()
    {
        return Farbe;
    }   
}
```

Davon eine Instanz erzeugen, und jeden Pixelwert mit setColor()
schreiben. Danach mit getRed, getGreen und getBlue die Anteile
holen.

Für ein Farbbild brauchst du drei LuT. Einen für jeden Farbanteil.


*Nochmal eine Zusammenfassung:*

 *Beim Programmstart:*
 Eine Instanz von RGBColor anlegen.
 Drei Instanzen von LUT anlegen.

 Das Bild muss als BufferedImage vorliegen...

 *Änderungen am Bild:*
 Mit setA und setB deine Helligkeit und den Kontrast
einstellen. 
 Dann in einer Schleife alle Pixel aus dem Bild lesen. Immer
einen nach dem Anderen.
 Jeden Wert mit setColor() in RGBColor schreiben.
 Dann die drei Farbanteile lesen.
 Jeden Farbanteil mit getLUTValue() schreiben. Als Rück-
gabe erhält man den neuen Wert.
 Den Rückgabewert von allen drei Farbanteilen mit setRGB()
in RGBColor schreiben -- du brauchst ja wieder einen int-Wert.
 Mit getRGB() den Wert lesen, und direkt in das BufferedImage
mit setRGB schreiben.


----------



## Matrim (30. Aug 2004)

Hi,

erstmal einmal danke für deine Antwort, super aufgeschrieben :toll:.

Hab nur noch ein paar Fragen, warum brauche ich drei LUT Instanzen? :bahnhof: 

Du hast zwar geschrieben, für jeden Farbanteil einen, aber LUT macht doch eigentlich nichts anderes, als für jeden möglichen Farbwerte (egal welchen Farbanteils) diese lineare Funktion zu berechnen, a*x + b, oder (bzw dann deren Wert nachzuschauen)?

Da a,b, als Werte für a = Helligkeit, b = Kontrast (?) für das gesamte Bild, jeden Pixel und somit jeden Farbwert gleich ist, reicht doch ein Lut, oder?

Trotzdem danke schon Mal,

Mat.


----------



## Thorsten (30. Aug 2004)

Okay, man muss keine drei nehmen  :wink: Aber wenn du drei
nimmst, kannst du eben für jeden Farbanteil die Werte getrennt
ändern ... so wie das ja auch in Photoshop etc. geht...

Übrigens: Photoshop und Co. benutzen auch LuT  :wink: 
Das ist also die gängige Methode


----------



## Matrim (30. Aug 2004)

Okay,

da ich aber nur einen Helligkeitsanteil für das gesamte Bild haben möchte, reicht mir dann eine LuT, schön.

Stimmt es nun, dass a = Helligkeit (mit 1 als Standard) und b für Kontrast steht (mit 0 als Standard)?

Danke noch mal für alles,

Mat.

ps Ich hab gesehen, dass man für Image mit RGBFilter arbeiten kann, aber BufferedImage und dann die Pixels einzeln abarbeiten macht sicher das Gleiche, oder?
Also Pixels holen?

```
int[] pixels = 
         myBufferedImage.getRGB(0, 0, myBufferedImage.getHeight(), 
                                               myBufferedImage.getWidth(), null, 0, 0);
```

Und dann in einer Schleife durcharbeiten.


----------



## Thorsten (30. Aug 2004)

Matrim hat gesagt.:
			
		

> Stimmt es nun, dass a = Helligkeit (mit 1 als Standard) und b für Kontrast steht (mit 0 als Standard)?



Nein, anders herum! Wenn du die Werte (a & b) nicht änderst, und trotzdem alle Pixel durcharbeitest, wird
das Bild nicht geändert!

Der Schnittpunkt (b = 0) liegt unten links in der Ecke. Bei einer Steigung von a = 1 ergibt sich für
jeden Wert der selbe Wert (stell dir eine schräge Linie von unten links nach oben rechts vor):

0 rein (unten links) ==> 0 raus 
255 rein (oben rechts) ==> 255 raus

Wenn du jetzt a = -1 und b = 255 setzt, dann invertierst du das Bild. Jetzt hast du eine Schräge
von oben links nach unten rechts:

0 rein (jetzt oben links) ==> 255 raus
255 rein (jetzt unten rechts) ==> 0 raus

Also...: a = Steigung = Kontrast  &  b = Schnittpunkt = Helligkeit

a > 1 Kontrast höher
a < 1 Kontrast kleiner

b > 1 Helligkeit höher
b < 1 Helligkeit kleiner



> ps Ich hab gesehen, dass man für Image mit RGBFilter arbeiten kann, aber BufferedImage und
> dann die Pixels einzeln abarbeiten macht sicher das Gleiche, oder? Also Pixels holen?



Ich kenne die Filter nicht. Wenn du noch ein Beispiel benötigst, wie man das mit dem LuT macht,
dann sieh mal hier:
http://www.java-forum.org/de/viewtopic.php?t=8022

Unten hat Beni nämlich ein kleines Beispiel  :wink:


----------



## Matrim (30. Aug 2004)

Hi Thorsten,

danke für deine Hilfe, hab es auch so ähnlich wie Beni angewendet, geht ja fast nicht anders =)

Weißt du eventuell zufällig auch, wie man die Farbwerte anheben kann? Also, wenn man sie runterschraubt, wird das Bild immer schwarz-weißer und hoch "übersteuern" die Farben dann, ganz analog zu den Einstellungen an einem Fernseher.

Wie man leicht sieht, hab ich einfach mal keine Ahnung von Farben =(

Danke noch mal!
Mat.


----------



## Thorsten (31. Aug 2004)

Matrim hat gesagt.:
			
		

> Weißt du eventuell zufällig auch, wie man die Farbwerte anheben kann? Also, wenn man sie
> runterschraubt, wird das Bild immer schwarz-weißer und hoch "übersteuern" die Farben dann,
> ganz analog zu den Einstellungen an einem Fernseher.



Ja   Ist aber nicht so einfach  :wink: 

Also, ich erkläre mal kurz die Schritte:

 Zuerst von deinem BufferedImage die R, G und B Werte holen. Diesmal aber alle gleichzeitig,
also drei neue int-Arrays erstellen.

 Dann in wieder drei neue int-Arrays die H, S und V Werte dazu schreiben. HSV ist ein anderes
Farmodell als RGB. Es gibt für die Umrechnung drei Formeln. H = Hue, S = Saturation, V = Value / Brightness

 Nun änderst du nur die Werte in dem S-Array. Das machst du wieder mit einem LuT! Wenn das ganze
Array mit schwarz (= 0) gefüllt ist, dann hast du ein schwarz-weiss-Bild. Wenn das ganze Array mit weiss (=255)
gefüllt ist, hast du das übersteuerte Bild.

 Um das Bild sehen zu können, muss man aus den drei H, S und V Arrays nun wieder R, G und B machen.
Danach kann man ein RGB-Array erstellen, und mit der RGBColor-Klasse wieder RGB-Werte erstelen, aus den
drei R, G und B Arrays.

Weil du den LuT zum Beispiel in einer grafischen Swing-Oberfläche mit einem Slider steuern kannst,
kannst du damit das Bild frei zwischen beiden extremen Punkten regeln.  :meld: 

Und nun die Formel:






Die Formeln muss man sich dann noch umstellen, damit man HSV --> RGB bekommt. Viel Spaß
dabei    Dummerweise sind das Formeln mit drei Veränderlichen. Das ist Stoff der Mathematik II
Vorlesung an Hochschulen für Diplom Informatiker etc.  :meld: 

Ich habe zwar diese Prüfung zu Mathematik II auf Anhieb bestanden, aber diese Formeln kann
ich dir ohne Hilfe eines Rechners jetzt auch nicht umstellen, sorry.    Da gehe mal lieber in
ein Matheforum. Das sollen die Diplom Mathematiker mal machen  :lol: Oder haben wir hier
einen? Andere Freiwillige vor...  :wink:

(Ich brauch die Formel für HSV --> RGB demnächst aber auch, und werde sie mir dann noch
umstellen. Wenn du also warten kannst...)


----------



## Matrim (31. Aug 2004)

Hallo,

danke für deine Antwort einmal mehr.
Zu den Umstellungen gibt es zum Glück schon genügend Antworten im Netz, sogar hier: http://de.wikipedia.org/wiki/HSV-Farbraum

Auch wenn die Berechnungen zum Teil von deinen Angaben abweichen. Es gibt da wohl keine glasklaren Definitionen, was wie genau richtig ist, sondern nur Formeln, die mehr oder weniger gut beschreiben. Sicher auch eine Geschmackssache.

Auf jeden Fall war dein Posting einmal mehr sehr hilfreich und gibt mir einen guten Ausgangspunkt für weitere Nachforschungen  :###.

Das einzige, was ich nicht verstanden hab ist: 



> Nun änderst du nur die Werte in dem S-Array. Das machst du wieder mit einem LuT! Wenn das ganze
> Array mit schwarz (= 0) gefüllt ist, dann hast du ein schwarz-weiss-Bild. Wenn das ganze Array mit weiss (=255)
> gefüllt ist, hast du das übersteuerte Bild.



Meinst du hier weiss (=1) ?
S ergibt doch einen Wert aus [0, 1], oder? (Du siehst, ich rechne zumindest mit ;-))

Es müsste halt nur der Bereich angepasst werden oder entsprechend durch 255 teilen, falls ich recht hätte.

Gruß, 
Mat.

Edit: Anmerkung
Also, der Plan für die Änderungen am gesamten Bild ist immer erst Helligkeit und Kontrast (mit LuT) am RGB ändern, dann umrechnen auf HSV, dort S anpassen, zurückrechnen und darstellen.


----------



## Matrim (31. Aug 2004)

Also,

besser ist es natürlich, zu einem Farbmodel zu stehen und dort all die Änderungen durchzuziehen.
Die Helligkeit im HSV Model zu verändern ist einfach, denke ich mir. Entsprechend V ändern, erhöhen oder erniedrigen.

Bleibt nur noch zu klären, wie das mit dem Kontrast funktioniert 

Sehr interessant der Thread, auch wenn es nicht mehr wirklich nur um Java geht, aber falls es jemanden interessiert, kann ich es ja mal in Java Source Code verpacken, wenn es komplett ist.

Mat.


----------



## Thorsten (31. Aug 2004)

Also zunächst muss ich da mal was klar stellen. Die Sache mit dem LuT und Helligkeit etc., war klar.
Das wusste ich auch genau, weil ich dazu schon eine Vorlesung hatte :wink:

Aber diese Sache war mir nicht bekannt. Ich habe das heute morgen um 01:00 für dich ausprobiert.



			
				Matrim hat gesagt.:
			
		

> Auch wenn die Berechnungen zum Teil von deinen Angaben abweichen. Es gibt da wohl keine glasklaren Definitionen,
> was wie genau richtig ist, sondern nur Formeln, die mehr oder weniger gut beschreiben. Sicher auch eine
> Geschmackssache.



Ja, ich kenne die Lösungen im Netz. Aber...



> S ergibt doch einen Wert aus [0, 1], oder? (Du siehst, ich rechne zumindest mit ;-))



... deshalb hab ich den Link verschwiegen :wink: Bei Wikipedia steht auch, dass die R-, G- und B-Werte
zwischen 0,0 und 1,0 annehmen. Technisch gesehen, in Java, liegen die R-, G- und B-Werte zwischen
0 und 255.

Daher muss man mit dem Wikipedia-Artikel aufpassen. Dort steht die Theorie, ohne den technischen
Hintergrund. 

Das mit dem 0 bis 1 für S und V kam mir heute morgen um 01:00 Uhr schon komisch vor, weil ich
das alles (die Punkte oben) in einer Bildverarbeitung getestet hatte. Und dort erhält man nach der
Umwandlung RGB --> HSV drei Graubilder. Und ein Graubild hat auch Werte von 0 bis 255....

Daher war mir die Sache bei Wikipedia nicht so geheuer :wink:


Zurück zu meiner Formel:
Ein Professor an meiner Hochschule hatte mir extra wegen der RGB-->HSV Umrechnung eine PDF-Datei
gegeben (ich brauche das für ein Projekt jetzt nämlich auch). Und dort standen diese Formeln, siehe oben.

Mittlerweile kommt mir das alles komisch vor... ???:L Ich werde nochmal bei Google nach Formeln suchen :wink:


----------



## Thorsten (31. Aug 2004)

Matrim hat gesagt.:
			
		

> besser ist es natürlich, zu einem Farbmodel zu stehen und dort all die Änderungen durchzuziehen.



Naja, so darf man das nicht sehen. Ein Bild stufenlos ins Graubild zu regeln, scheint mir mit RGB nicht
möglich. Zumindest ist es nicht so einfach wie in HSV. Ich musste auch feststellen, dass manche Dinge
eben nur in bestimmten Farbmodellen funktionieren. 



> Die Helligkeit im HSV Model zu verändern ist einfach, denke ich mir. Entsprechend V ändern,
> erhöhen oder erniedrigen.



Wenn du die Helligkeit in "HSV" ändern willst, solltest du nicht HSV nehmen. Dann wandle lieber
RGB --> HSB um. B == Brightness == Helligkeit. Der Unterschied V => B ist mir im Moment nicht
bekannt. Hab gestern im Web aber irgendwo gelesen, dass es wohl nicht weiter Interessant ist.
Muss man sich mal anlesen, wie das ist.



> Bleibt nur noch zu klären, wie das mit dem Kontrast funktioniert



Eben drum bleibe doch bei RGB für Helligkeit und Kontrast. RGB musst du eh "in die Hände nehmen", weil
ein BufferedImage nunmal die Methode getRGB hat, und nicht getHSV :wink:



> Sehr interessant der Thread, auch wenn es nicht mehr wirklich nur um Java geht,



Ja, schöne Sammlung zum Thema Bilddatenverarbeitung   Könnte man noch fortsetzen... Thresholding,
Bildeffekte etc. ...


----------



## Guest (1. Sep 2004)

In der Tat wirft Googeln eine Auswahl von Formel für RGB <-> HSV / HSB / HSL auf.

Mal schaun, ob ich mich da morgen für eine entscheiden kann.


----------

