# farben auf ähnlichkeit untersuchen



## darkeye2 (26. Mrz 2011)

Hallo,

in meinen programm wird eine statistik erstellt, und für diese zeichne ich einen pie-graph (runder graph, also kreis, in dem prozentual etwas dargestellt wird, hoffe es ist klar, was ich meine).

Auf jeden fall weiß ich erst zur laufzeit, wie viele farben ich benötige, also kann ich auch nicht von vornherein farben festlegen, sondern muss diese zur laufzeit generieren. Nun hab ich das so gelöst, dass ich farben per zufall generiere und in einem Array abspeichere, um beim nächsten generieren zu prüfen, ob farbe bereits vorhanden ist. Das Problem ist, dass z.b. zwischen den farben (250,128,128) und (251,128,128) kein großer unterschied besteht und diese, im graph nicht zu unterscheiden sind, jetzt wollte ich wissen, wie man am besten farben auf ihre Ähnlichkeit überprüfen kann.

MfG
darkeye


----------



## ARadauer (26. Mrz 2011)

Differenz der einzelnen Farbwerte? Wenn dieser Wert sehr klein ist wird die Farbe sehr ähnlich sein... nehm ich mal an...


----------



## XHelp (26. Mrz 2011)

Wenn du dir die RGB Palette als 3D Raum vorstellst, dann kannst du einfach die Entfernung bestimmen. Anschließend kannst du es noch normieren und dann hast du die Ähnlichkeit, wobei 1.0 völlig unterschiedliche Farben darstellt.
Nur zur Verdeutlichung:

```
private static double maxLength = Math.sqrt(65025+65025+65025); //entfernung von (0,0,0) bis (255,255,255)
public static double getColorDifference(Color c1, Color c2) {
  //euklidischer Abstand
  double result = Math.pow((c1.getRed()-c2.getRed()), 2) + Math.pow(c1.getGreen()-c2.getGreen(), 2) + Math.pow(c1.getBlue()-c2.getBlue(), 2);
  result = Math.sqrt(result);
  //Normierung
  result = result / maxLength;
  return result;
}
```

Aber generell solltest du dir vllt überlegen ob du nicht eine Palette an vordefinierten Farben abspeicherst, die du selber aussuchst. Sonst bekommst du unter Umständen Graphen in dunkelbraun, neongrün und sonnengelb. Ob das so optisch ansprechbar ist....


----------



## ThreadPool (26. Mrz 2011)

Geht auch einfacher da man Farben gut in einem int unterbringen kann und dafür auch IMHO nur die L1-Metrik genügt.


```
public int getRGB(int r, int g, int b){
    	return r * 0x10000 + g * 0x100 + b;
    }


    int a = getRGB(250, 128, 128);
    int b = getRGB(251, 128, 128);
    int dist = Math.abs(a-b)
```

Edit: Ich bemerke soeben das Color schon eine Methode getRGB() anbietet...


----------



## darkeye2 (26. Mrz 2011)

also die idee von XHelp war bis jetzt am besten, bin zwar grad noch am suchen für einen vernünftigen wert, aber ansonsten bin ich mit den Ergebnissen ganz zufrieden.

Wegen den festgelgten Farben hab ich auch schon überlegt, aber das mache ich nur, wenn ich wirklich merke, dass die generierten farben optisch überhaupt nicht passen.


----------



## XHelp (26. Mrz 2011)

Nein, die Metrik genügt nicht. Der Unterschied zwischen 
	
	
	
	





```
255,0,0
```
 und 
	
	
	
	





```
255,0,1
```
 ist 1 und zwischen 
	
	
	
	





```
255,0,0
```
 und 
	
	
	
	





```
254,0,0
```
 ist es 65536. Wie willst du die Daten denn auswerten?


----------



## Dow Jones (26. Mrz 2011)

Die gestellte Aufgabe (x möglichst gut unterscheidbare Farben zu erzeugen) lässt sich wahrscheinlich einfacher lösen wenn man vom RGB- in das HSV-Modell wechselt. Dort wird die eigentliche Farbe nur durch einen einzigen Wert im Interval [0 - 360[ festgelegt, so das man leicht x "möglichst unterschiedliche" Farben angeben kann. Falls x zu groß ist, die einzelnen Farben also doch zu ähnlich werden, kann man sie ja immer noch durch den Helligkeits- oder Sättigungswert unterscheidbar machen.
Die Umrechnungsformeln, um nachher aus den HSV-Werten RGB-Werte zu machen, stehen irgendwo in der Wikipedia...


----------



## Ark (26. Mrz 2011)

Ergänzend zu Dow Jones' Ansatz (den ich sehr gut finde) hier ein paar Zeilen, die dir die verschiedenen Farbtöne als Winkel im Farbkreis ausgeben, sodass du sie fürs HSV-Farbmodell benutzen kannst:

```
public static void main(String[] args) {

		final int anzahl = 10;// Anzahl verschiedener Farben
		final double abstand = 360.0 / anzahl;
		final int verschiebung = 0;// "Phasenverschiebung" zwischen 0 und abstand (exklusive)

		for(int i = 0;i < anzahl;i++){
			int y = (int)(Math.round(abstand * i + verschiebung));
			// Ausgabe der Winkel
			System.out.println(y);
		}
	}
```

Ark


----------



## darkeye2 (29. Mrz 2011)

Die Lösung mit dem HSV format geht auch (ausprobiert) aber ich nutze jetzt die Methode von XHelp, da es damit auch sehr gut funktioniert.


```
private double maxLength = Math.sqrt((255*255)+(255*255)+(255*255)); //entfernung von (0,0,0) bis (255,255,255)
	public double getColorDifference(Color c1, Color c2) {
		double res = Math.sqrt(Math.pow((c2.getRed()-c1.getRed()),2)+Math.pow((c2.getGreen()-c1.getGreen()),
				2)+Math.pow((c2.getBlue()-c1.getBlue()),2));
		return (res/maxLength);
	}
```

und dann einfach schauen, ob das ergebniss größer 0.4 ist, wenn ja Farbe zulassen, ansonsten Methode nochmal aufrufen. Geht zimlich schnell, und macht bei mir keine Probleme.


----------



## XHelp (29. Mrz 2011)

musst nur aufpassen, dass du nicht in einer Endlosschleife gerätst.


----------

