# Durchschnittliche Farbe eines Bildes



## Granjow (2. Jul 2006)

Hallo zusammen,

Ich habe vor, ein Programm zu schreiben, welches eine Bilddatei einliest. Raus soll dann ein neues Bild (beliebiger Grösse) kommen, einfarbig. Die Farbe soll der Durchschnittswert des Bildes sein, also Summe der R-Werte aller Pixel geteilt durch Anzahl Pixel, Summe der G-Werte durch Anz. Pixel und die der B-Werte.

Ist das aufwändig zu programmieren? Für welche Dateien lässt es sich mit vertretbarem Aufwand realisieren &ndash; auch für jpg-Dateien?

Ich will evtl. damit meine Bilder in Bildergalerien ordnen. Darum kommt später eventuell sogar eine Sortierung von Bildern in Frage.

Granjow


----------



## 0xdeadbeef (2. Jul 2006)

Sollte keine große Sache sein. Obwohl sich mir der Sinn dieser "einfarbigen" JPEGs jetzt gerade irgendwie verschließt. Wozu ein Bild abspeichern, bei dem alle Pixel die gleiche Farbe haben? Oder habe ich da was nicht kapiert?


----------



## lin (2. Jul 2006)

naja, ich denke er will seine Bilder ganz einfach nach Helligkeit ordnen, oder?


----------



## Granjow (2. Jul 2006)

Genau. Und verschiedene Grössen, damit man auch was von der Farbe sieht, wenn du nur ein 1 Pixel grosses Bild hast, kannst du nur raten oder vergrössern, um die Farbe zu erkennen.

Womit würde man denn die Bilder einlesen und schreiben? Steht das in der Java-Insel?

Granjow


----------



## The_S (3. Jul 2006)

steht bestimmt in der Java-Insel  .

Ansonsten ImageIO.write bzw. ImageIO.read . Die Pixel bekommst du mit bufferedimage.getRGB


----------



## Granjow (4. Jul 2006)

Ich bin zu blöd dafür. Warum geht bei mir Image.getWidth() nicht, warum will er dort einen ImageObserver? Und überhaupt, wie bekomme ich von einem Image ein BufferedImage?

Granjow

edit: Ja, zu blöd ... hier


----------



## Granjow (4. Jul 2006)

Momentan sieht es so aus:


```
import java.awt.Color;
import java.awt.Image;
import java.awt.image.ImageObserver;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class GetImageValue {
	static String[] extensions = {".jpg", ".jpeg", ".png", ".bmp" };

	public static void main(String[] args) throws IOException {
		BufferedImage bimg = ImageIO.read(IOUtils.openInFileDialog(extensions, false));
		Color color;

		int w = bimg.getWidth(),
			h = bimg.getHeight();
		
		int xR,
			xG,
			xB,
			R = 0,
			G = 0,
			B = 0;
		for (int y = 0; y < h; y++) {
			xR = 0;
			xG = 0;
			xB = 0;
			for (int x = 0; x < w; x++) {
				color = new Color(bimg.getRGB(0,0));
				xR += color.getRed();
				xG += color.getGreen();
				xB += color.getBlue();
			}
			R += (xR / w);
			G += (xG / w);
			B += (xB / w);
		}
		R = R / h;
		G = G / h;
		B = B / h;
		
		System.out.println(R + "/" + G + "/" + B);
	}

}
```

Jetzt fehlt mir noch etwas schnelles, um ein neues Bild zu erzeugen und mit der berechneten Farbe zu füllen. Wie macht man das? Über das g2d?

Granjow


----------



## lin (5. Jul 2006)

BufferedImage erzeugen

```
BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
```


```
Graphics2D g2d = bimage.createGraphics();
g2d.setColor(new Color(x, y, z));
g2d.fill(new Rectangle2D.Double(0, 0, width, height));
g2d.dispose();
```


----------



## The_S (5. Jul 2006)

Mit ImageIO.read(file) haste automatisch nen BufferedImage und da kannste auch ohne ImageObserver getWidth ausführen . Ansosnten einfach this mitübergeben.


----------



## thE_29 (5. Jul 2006)

Ich würds so machen


```
public void average_color_picture(String old_file, String new_file) throws Exception
  {
    BufferedImage img = ImageIO.read(new File(old_file));
    Raster raster = img.getRaster();
    int height = img.getHeight();
    int width = img.getWidth();
    double ar[] = new double[4];    
    double r = 0, g = 0, b = 0,a = 0;
    for(int x = 0; x != width; x++)
    {
      for(int y = 0; y != height; y++)
      {
        raster.getPixel(x,y,ar);
        r += ar[0];
        g += ar[1];
        b += ar[2];
        a += ar[3];
      }
    }
    double all = height * width;
    r /= all;
    g /= all;
    b /= all;
    a /= all;
    ar[0] = r;
    ar[1] = g;
    ar[2] = b;
    ar[3] = a;
    WritableRaster writer = img.getRaster();
    for(int x = 0; x != width; x++)
    {
      for(int y = 0; y != height; y++)
      {
        writer.setPixel(x,y,ar);
      }
    }
    ImageIO.write(img,"png",new File(new_file));
  }
```

Für was gibts diese ganzen Pixel set/get Methoden wennst mit paint rumpfuscht :bae:


----------



## Granjow (6. Jul 2006)

```
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class GetImageValue {
	static String[] extensions = { ".bmp", ".png", ".jpeg", ".jpg" };

	public static void main(String[] args) {
		Timer timer = new Timer();
		File f = null;
		BufferedImage bimg = null;
		Raster raster = null;

		try {
			f = IOUtils.openInFileDialog(extensions, false);
			bimg = ImageIO.read(f);
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}

		timer.start();

		raster = bimg.getRaster();
		int w = bimg.getWidth(), h = bimg.getHeight(), p = w * h;
		double R = 0, G = 0, B = 0, A = 0;
		double[] rgba = new double[4];

		R = 0;
		G = 0;
		B = 0;
		A = 0;

		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				raster.getPixel(x, y, rgba);
				R += rgba[0];
				G += rgba[1];
				B += rgba[2];
				A += rgba[3];
			}
		}

		System.out.println("Calc: " + Mathe.formatTime(timer.reset(), true));

		R /= p;
		G /= p;
		B /= p;
		A /= p;

		System.out.println(R + "/" + G + "/" + B + "/" + A);

		writeImage(f, bimg, "_value2.png", (int) R, (int) G, (int) B, (int) A);
		System.out.println("Write: " + Mathe.formatTime(timer.reset(), true));

	}

	public static void writeImage(File f, BufferedImage bimg, String newExt,
			int R, int G, int B, int A) {
		int w = bimg.getWidth();
		int h = bimg.getHeight();
		WritableRaster writer = bimg.getRaster();

		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				writer.setPixel(x, y, new int[] { (int) R, (int) G, (int) B,
						(int) A });
			}
		}
		try {
			ImageIO.write(bimg, "png", IOUtils.addFileExtension(IOUtils
					.removeFileExtension(f), newExt));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
```

Ende, funktioniert. Leider nicht so schnell wie erwartet:



> Calc:  641 ms
> 113.24467086791992/110.10273170471191/50.895527839660645/0.0
> Write: 1 s 125 ms



Und kann man das Ausgabebild auf diese Art auch auf eine sinnvolle Grösse reduzieren?

tnx, Granjow

edit: Die anderen Quellen kann ich auch posten, wenns jemanden interessiert


----------



## The_S (7. Jul 2006)

Fürs skallieren bitte das nächste mal die Forensuche verwenden, wurde schon ziemlich oft verwendet  :roll: 

Zauberwort hierfür lautet Image#getScaledInstance ich würds aber skallieren bevor dus bearbeitest, dann geht das bearbeiten auch schneller


----------



## lin (7. Jul 2006)

Das Ausgabebild? Da kannste ja einfach die Werte von w und h verändern, also z.B. 
	
	
	
	





```
int w = (int) (0.5 * bimg.getWidth());
```


----------



## Granjow (7. Jul 2006)

Aber dann wird es doch trotzdem gleich gross, einfach ist nur das obere linke Viertel farbig?

Manchmal sollte ich vielleicht etwas mehr schlafen.


```
public static void writeImage(File f, String newExt,
			int R, int G, int B, int A) {
		int w = 50;
		int h = 50;
		BufferedImage bimg2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
		WritableRaster writer = bimg2.getRaster();

		if (A == 0) A = 255;
		for (int x = 0; x < w; x++) {
			for (int y = 0; y < h; y++) {
				writer.setPixel(x, y, new int[] { (int) R, (int) G, (int) B,
						(int) A });
			}
		}
		try {
			ImageIO.write(bimg2, "png", IOUtils.addFileExtension(IOUtils
					.removeFileExtension(f), newExt));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
```


----------



## Granjow (7. Jul 2006)

Jetzt habe ich ein neues Problem. Wenn ich mehrere Bilder auswähle, meldet er einen Memory overflow (o. ä.). Ich habe ein Jar raufgeladen, mit dem Quellcode:
http://livingshadow.uttx.net/uploads/ImageValue.jar

Was nun? Würde das mit Threads funktionieren?

Granjow


----------



## lin (7. Jul 2006)

hm, der link funzt bei mir nicht oder er ist tödlich langsam..

Aber wahrscheinlich sammelst du irgendwelche Bilder im Memory an.


----------



## Granjow (9. Jul 2006)

Jetzt sollte es gehen ... ich glaube, der Server war kurzfristig tot.

Granjow


----------



## Granjow (14. Jul 2006)

@lin: War der Fall.
Neue Version
(Mit Quellcode)


```
for (int i = 0; i < f.length; i++) {
				System.out.println(f[i].getAbsolutePath());
				bimg[i] = ImageIO.read(f[i]);

				//[...]

				bimg[i] = null;
			}
```

Die letzte Zeile war die Rettung. 

Granjow


----------



## thE_29 (14. Jul 2006)

Da stellt sich die Frage, warum du das in einem Array abspeicherst, wenn du es in der for schleife wieder auf null setzt :bae:

Kannst gleich 1 Objekt nehmen ^^


----------

