Pixel im BufferedImage Manipulieren ?

Status
Nicht offen für weitere Antworten.

HaBaLeS

Aktives Mitglied
Hi,
ich möchte gerne die Pixel eines BufferedImages direkt manipulieren. Das bekomme ich prinzipiell auch hin, aber leider ist das total inperformant (300ms für ein 400*400 Bild). Ich poste einfach mal den Code den ich verwendet habe vielleicht kennt ja einer von euch einen performanteren Weg.

Code:
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.awt.image.DataBuffer;
import java.awt.image.SinglePixelPackedSampleModel;
import java.awt.image.WritableRaster;

import javax.swing.JFrame;

public class PixelMaupulatorTest {
	
	static JFrame f ;
	static BufferedImage buffer; 
	
	public static void main(String[] args) {
		f = new JFrame();
		f.setPreferredSize(new Dimension(400,400));
		f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		f.setResizable(false);
		f.setIgnoreRepaint(true);
		f.pack();
		f.setVisible(true);
		
		Graphics graphics = f.getGraphics();
		GraphicsDevice device = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
		GraphicsConfiguration conf = device.getDefaultConfiguration();
		buffer = conf.createCompatibleImage(400, 400);
		
		
		Thread t = new Thread(new Runnable(){
			public void run() {
				while(true){
				doRender((Graphics2D)f.getGraphics());
				try {
					Thread.sleep(20);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				}
				
			}
		});
		t.start();
		
	}

	/**
	 * Test für verschienend Möglichkeiten des manipulierens einzelner Pixel
	 * @param s
	 */
	private static void doRender(Graphics2D s) {
		WritableRaster raster = buffer.getRaster();
		DataBuffer dataBuffer = raster.getDataBuffer();
		
		//doSetPixelInRaster(raster);

		//doSetPixelInSampleModel(raster, dataBuffer);
		
		doSetPixelInDataBuffer(dataBuffer);
		
		//Image Zeichnen
		s.drawImage(buffer, f.getInsets().left,f.getInsets().top,null);
	}


	/**
	 * DataBuffer Manipulieren
	 * @param dataBuffer
	 */
	private static void doSetPixelInDataBuffer(DataBuffer dataBuffer) {
		long cr = System.currentTimeMillis();
		for(int r = 0 ; r < 400*400; r++){
			dataBuffer.setElem(r, r);
		}
		System.out.println(System.currentTimeMillis() -cr);
	}


	/**
	 * SampleModel Manipulieren
	 * @param raster
	 * @param dataBuffer
	 */
	private static void doSetPixelInSampleModel(WritableRaster raster,
			DataBuffer dataBuffer) {
		long cr = System.currentTimeMillis();
		SinglePixelPackedSampleModel sampleModel = (SinglePixelPackedSampleModel)raster.getSampleModel();
		for(int x=0; x<400;x++){
			for(int y=0; y<400;y++){
				sampleModel.setPixel(x, y, new int[]{x,y,10*(int)Math.random()},dataBuffer);
			}
		}
		System.out.println(System.currentTimeMillis() -cr);
	}


	/**
	 * Raster Manipulieren
	 * @param raster
	 */
	private static void doSetPixelInRaster(WritableRaster raster) {
		long cm = System.currentTimeMillis();
		for(int x=0; x<400;x++){
			for(int y=0; y<400;y++){
				raster.setPixel(x, y, new int[]{x,y,10*(int)Math.random()});
			}
		}
		System.out.println(System.currentTimeMillis() -cm);
	}
}
 

Marco13

Top Contributor
Dass die mit "new int[]{x,y,10*(int)Math.random()" langsam sind, ist klar (abgesehen davon, dass (int)Math.random() immer 0 ist). Hast du auch mal bufferedImage.setRGB(x,y,rgb) versucht?
 

HaBaLeS

Aktives Mitglied
new int[]{x,y,10*(int)Math.random() braucht ca. 2ns steht also in absolut keinem Verhältniss zu den 300ms die das setzen der Pixel braucht. Der Cast nach int gehört weiter nach vorne das stimmt spielt aber auch keine Rolle für die Geschwindigkeit. bufferedImage.setRGB(x,y,rgb) ist genauso langsam.
 

Ariol

Top Contributor
Wieso? Kommt doch genau hin.

Du hast eine verschachtelte Schleife mit jeweils 400 Durchläufen.

Also 400*400*2ns = 320000ns = 320ms

Wenn ich mich jetzt nicht gerade verechnet hab.
 

Wildcard

Top Contributor
Deine Schleifen verlaufen ungünstig. 'x' sollte die inner sein, für ein Array of Arrays ist das der günstigere Speicherzugriff.
Davon abgesehen, wozu die Obfuscation?
Was soll der JFrame, was soll der Thread? Was soll es in einem anderen Thread als dem EDT auf das Graphics Objekt des Frames zu zeichnen?
 

HaBaLeS

Aktives Mitglied
@Ariol
1 nanosecond = 1.0 × 10-6 milliseconds
320000ns = 0.32ms

@Wildcard
Ich verstehe das Problem nicht, das du mit JFrame und Thread hast, die Zeitfresser liegen eindeutig beim Schreiben in das BufferedImage, da muss ich mir keine Gedanken darüber manchen aus welchem Thread mein Draw call kommt. Wenn das kein Testcode wäre kann man darüber streiten wie man das Active Rendering umsetzt, aber für mein eigentliches Problem, das ich gerne lösen würde spielt das keine Rolle
 

Wildcard

Top Contributor
HaBaLeS hat gesagt.:
Wenn das kein Testcode wäre kann man darüber streiten wie man das Active Rendering umsetzt, aber für mein eigentliches Problem, das ich gerne lösen würde spielt das keine Rolle
Eben. Es ist Testcode. Du willst uns einen Test vorführen, beschränkst dich aber nicht auf das Wesentliche, sondern lässt die Tür offen für allerlei Seiteneffekte. Du hast nun schon mindestens 4 Threads die sich gegenseitig beinflussen und willst daraus Ergebnisse ableiten.
 

HaBaLeS

Aktives Mitglied
Um genau zu sein 5 Threads. Aber ich hab echt keine Lust mich darüber zu streiten. Es ist klar messbar, das ein kleines 400² Pixel Bild mit den 4 vorgeschlagenen Varianten, die intern im Endeffekt alle das gleiche machen, nicht flüssig als Animation darstellbar ist. Selbst wenn die Threads Einfluss auf das Setzen der Pixel hätten, würden die Ergebnisse nicht im Bereich von mehreren 100ms verfälscht.

Aber was trägt die deine Auseinandersetzung mit meinem Rahmencode jetzt eigentlich zur Lösung des Problems bei Wildcat ?
 

Ariol

Top Contributor
So, ich hab mir dein Programm jetzt mal gezogen.

Du verwendest die Methode doSetPixelInDataBuffer(DataBuffer).

Ich hab da mal nach der Schleife ein

Code:
cr = System.nanoTime();
		dataBuffer.setElem(1, 1);
		System.err.println(System.nanoTime() - cr);

eingefügt.

Die Ausgabe ist bei mir:
Code:
734 //millisekunden
10721 //nanosekunden
720
33543
724
110165
715
10579
724
9702

Und auch wenn ich mich eben verrechnet habe komm ich so auf bei positiv betrachteten 10000ns je Aufruf auf

400*400*10000ns = 1600ms

Den Unterschied schieb ich jetzt mal der Bytecode-Optimierung des Compilers zu.

Meiner Meinung nach sind deine Werte also ganz ok.
 

Ariol

Top Contributor
So, ich hab jetzt noch doSetPixelInSampleModel() und doSetPixelInRaster() versucht. Mit kaum abweichenden Ergebnissen.

Die beiden sind minimal schneller (9000-10000ns/Aufruf mal abgesehen von einigen Ausreissern).

Da wirst du wohl nix verbessern können.
 

HaBaLeS

Aktives Mitglied
Eine Chance habe ich noch.
Wenn es mir gelingt, aus einem ColorModel und einem DataBuffer, welcher im Normalfall bei 16000 Werten in weniger als 1ms gefüllt ist, ein BufferedImage erzeugen kann bekomme ich evtl. noch einen guten Performance zuwachs *g*
 

Wildcard

Top Contributor
HaBaLeS hat gesagt.:
Aber was trägt die deine Auseinandersetzung mit meinem Rahmencode jetzt eigentlich zur Lösung des Problems bei Wildcat ?
Bevor ich die Frage beantworte, möchte ich dich darauf hinweisen, das ich mich nicht als Katze verstehe..
Die Sache ist einfach:
Ich habe keine Lust den Testcase von den Seiteneffekten zu befreien (ihn also quasi neu zu schreiben), bevor ich mich dem eigentlichen Problem zuwende.
Dazu kommt, dass ich in den paar Jahren dich ich mich auf diesem Board herumtreibe schon jede Menge furchtbarer Microbenchmarks gesehen habe. Immer wieder versehen mit Kommentaren wie: 'mein Test zeigt...' 'dies und jenes ist gleich schnell/langsamer/schneller...'.
Aus falschen Prämissen lässt sich beliebiges schließen, warum also nicht ein wenig mehr Zeit in einen sauberen Testcase investieren, bevor man mit anderen über die Ergebnisse diskutiert?

Wird das Ergebnis eines besseren Tests sich von deinem wesentlich unterscheiden?
Kann ich dir nicht sagen ohne es zu versuchen, aber ich wette, dass du das auch nicht sicher sagen kannst ohne es versucht zu haben.
 

Ariol

Top Contributor
HaBaLeS hat gesagt.:
Eine Chance habe ich noch.
Wenn es mir gelingt, aus einem ColorModel und einem DataBuffer, welcher im Normalfall bei 16000 Werten in weniger als 1ms gefüllt ist, ein BufferedImage erzeugen kann bekomme ich evtl. noch einen guten Performance zuwachs *g*

Wie kommst du auf 16000?? 400*400=160000
 

HaBaLeS

Aktives Mitglied
Das mit der Katze war ein Typo Sorry.

Zum Thema Microbenchmark kann ich nur sagen, das es kein Benchmark ist sondern eine Zeitmessung vor und nach einer Schleife mit einem hinreichend genauen Timer, was durchaus eine sinnvolle Quantitive aussage zuläßt.
 

HaBaLeS

Aktives Mitglied
@Ariol, hab ne null vergessen, kommt aber auf das gleiche raus bei der geschwindigkeit.

Welches System und Java Version benutzt du ? Ein Kollege von mir hat die Methode doSetPixelInDataBuffer unter Windoof und Java5 mit <1ms pro RenderLoop am laufen.

Ich selbst bin mit Java6 unter Linux am Start
 

Wildcard

Top Contributor
Ich würde dir zum Beispiel vorschlagen einfach mal ein eigenes ColorModel zu versuchen, das du direkt manipulieren kannst. Einfach um zu sehen wie schnell es ist.
Es ist klar messbar, das ein kleines 400² Pixel Bild mit den 4 vorgeschlagenen Varianten, die intern im Endeffekt alle das gleiche machen, nicht flüssig als Animation darstellbar ist
Low Level Pixel Manipulationen sind in der Regel auch nicht wirklich der effizienteste Weg etwas zu animieren, aber der eigentliche Use-Case ist ja derzeit noch unbekannt.
 

HaBaLeS

Aktives Mitglied
Also ich hab das Problem erkannt und gelöst. Ich hohle mal etwas weiter aus.
Ein BufferedImage besteht Prinzipiell aus 2 Teilen:

Ein ColorModel und dem Raster. Wobei des Raster aus einem DataBuffer und einem SampelModel besteht. Das Colormodel gibt einfach ausgedrückt an, wie Palette und Farbraum aussehen. SampleModel steuert wie die Farbinformationen im DataBuffer verteilt werden. Wenn man also Pixel manipulieren möchte, dann am einfachsten über den DataBuffer.

Jetzt ist es so, das der DataBuffer unter Windows ein DataBufferInt ist und man diesen richtig schnell manipulieren kann. Unter Linux jedoch ist es ein DataBufferNative, der in die X11 Librarys schreibt und das ist, da man im Normalfall keine Pixel direkt manipuliert leider relativ langsam. Eine Lösung die unter Linux und Windoof funktioniert ist, das man das BufferedImage das man manipulieren will nicht über GraphicsConfiguration.createCompatibleImage(b,h); sondern selbst erstellt und es zwingt, einen DataBufferInt zu verwenden. Dazu ein kleines Code Sniplet zugegeben etwas konfus, eine aufgeräumte Version wird bei bedarf nachgeliefert.

Code:
//Kompatible Image als Grundlage
BufferedImage buffer = conf.createCompatibleImage(400, 400);
WritableRaster raster = buffer.getRaster();
DataBuffer dataBuffer = raster.getDataBuffer();


 //RGBA Image Erzeugen mit dem DataBufferInt
DataBufferInt intBuffer = new DataBufferInt(dataBuffer.getSize());
 WritableRaster raster2 = Raster.createPackedRaster(intBuffer,buffer.getWidth(), buffer.getHeight(),
                 buffer.getWidth(),new int[] { 0x00ff0000, 0x0000ff00,0x000000ff, 0xff000000},new Point(0,0));
 buffer = new BufferedImage(ColorModel.getRGBdefault(),raster2,true,null);

for (int r = 0; r < 160000; r++) {
	intBuffer.setElem(r, r | 0xff000000); //ALPHA IMMER OPAQUE!
}

Damit kann ich die Pixel in einem BufferedImage in <1ms bei 400*400 setzen.

War doch garnicht so schwer :lol:
 

Wildcard

Top Contributor
Und so kann sogar ich was damit anfangen. Kein JFrame zu sehen, keine 18 Threads :D :toll:
Genau sowas ist die Crux von zB createCompatibleImage. Alles wunderbar abstrahiert, was man dann aber tatsächlich vorgesetzt bekommt, weiß kein Mensch, bis man sich mit dem Debugger in die Tiefen des Systems gräbt.
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
A BufferedImage einzelne Pixel transparent machen V2.0 Allgemeine Java-Themen 2
Q BufferedImage enzelne Pixel tranzparent machen Allgemeine Java-Themen 2
berserkerdq2 Ein Gamepanel sei in 60x60 Pixel Quadrate aufgeteilt und isgesamt 600 Pixel breit & 300 Pixel hoch. Wie auf Quadrate zugreifen? Allgemeine Java-Themen 5
D Best Practice Gesamten Bildschirminhalt auslesen und Email schicken sobald kein Pixel sich ändert Allgemeine Java-Themen 11
U Koordinaten alle Pixel eines Dreiecks zeichnen ausgeben Allgemeine Java-Themen 5
F hex-farbwert der pixel aus bildern lesen Allgemeine Java-Themen 4
V Pixel-Farbe Allgemeine Java-Themen 10
H2SO3- Pixel länge von String ermitteln Allgemeine Java-Themen 4
M Problem beim Umrechnen von Pixel in cm. Allgemeine Java-Themen 6
U Pixel für Pixel abarbeiten Allgemeine Java-Themen 4
Ark Das effizienteste Pixel der Java-Welt Allgemeine Java-Themen 10
T Image mithilfe von DirectColorModel und Pixel erstellen Allgemeine Java-Themen 3
M JLabel an Textlänge anpassen / Textlänge in pixel Allgemeine Java-Themen 3
D BufferedImage resize Allgemeine Java-Themen 16
RalleYTN JOGL Texture in BufferedImage konvertieren Allgemeine Java-Themen 1
M Input/Output BufferedImage vertauscht width und height Allgemeine Java-Themen 6
G BufferedImage und ByteArray Allgemeine Java-Themen 2
P Threads BufferedImage, Thread Concurrency Allgemeine Java-Themen 1
M Problem mit BufferedImage und PrinterJob im Querformat Allgemeine Java-Themen 1
T BufferedImage verändert sich beim Einlsesen Allgemeine Java-Themen 1
M BufferedImage toString() überschreiben Allgemeine Java-Themen 5
Thallius PDF von einem BufferedImage erstellen Allgemeine Java-Themen 1
S BufferedImage vergleich mit Subimage Allgemeine Java-Themen 1
reibi OutOfMemoryError bei Behandlung von BufferedImage's Allgemeine Java-Themen 6
TheSorm BufferedImage spiegeln Allgemeine Java-Themen 3
S Undoable BufferedImage? Allgemeine Java-Themen 2
lumo 2D-Grafik BufferedImage und operationen darauf Allgemeine Java-Themen 2
K Image zu BufferedImage konvertieren Allgemeine Java-Themen 9
H BufferedImage Invertieren Allgemeine Java-Themen 13
D md5 berechnen für BufferedImage Allgemeine Java-Themen 5
D BufferedImage rotieren Allgemeine Java-Themen 8
TiME-SPLiNTER Binary BufferedImage automatisch croppen Allgemeine Java-Themen 4
F byte[] aus einem BufferedImage Allgemeine Java-Themen 3
0 BufferedImage - Farbton verändern Allgemeine Java-Themen 5
J BufferedImage aus PNG Files haben keinen Type Allgemeine Java-Themen 4
T umwandeln BufferedImage to File Allgemeine Java-Themen 7
reibi BufferedImage nach InputStream Allgemeine Java-Themen 10
S BufferedImage mit Transparenten Hintergrund Allgemeine Java-Themen 4
Z Farbe des Pixels rechts unten in einem BufferedImage? Allgemeine Java-Themen 4
R problem! bufferedimage speichern. Allgemeine Java-Themen 7
S BufferedImage als *.tga speichern Allgemeine Java-Themen 3
Steev BufferedImage und setRGB() Allgemeine Java-Themen 10
P miese performance bei nem BufferedImage + repaint :( Allgemeine Java-Themen 6
M Drucken mit BufferedImage Allgemeine Java-Themen 9
M Problem mit Durchsuchen von BufferedImage Allgemeine Java-Themen 10
I BufferedImage etc Allgemeine Java-Themen 6
F BufferedImage -> Image Allgemeine Java-Themen 4
G BufferedImage benutzen Allgemeine Java-Themen 6
U BufferedImage.getSubimage ? paintComponent ? Allgemeine Java-Themen 4
T Bilder schnell in BufferedImage laden Allgemeine Java-Themen 4
G BufferedImage zeichnen Allgemeine Java-Themen 4
T BufferedImage aus einem byte-Array? Allgemeine Java-Themen 2
T BufferedImage problem Allgemeine Java-Themen 6
K 32-Bit grayscale BufferedImage Allgemeine Java-Themen 2
T Geschwindigkeit bei Polygonen und BufferedImage Allgemeine Java-Themen 9
N svg(xml) parsen und manipulieren? Allgemeine Java-Themen 3
P iTunes Datenbank manipulieren Allgemeine Java-Themen 2
R Problem beim vCard Manipulieren Allgemeine Java-Themen 2
Z 2D-Grafik Webcam-Bilder analysieren und manipulieren Allgemeine Java-Themen 8
S Dynamisches Manipulieren/Laden von Klassen Allgemeine Java-Themen 4
C Bilder automatisch bearbeiten/manipulieren Allgemeine Java-Themen 2
K Elegante Lösung zum Manipulieren von Collections gesucht Allgemeine Java-Themen 16
D mausbewegungungen manipulieren Allgemeine Java-Themen 2
R Einzelne Zeile manipulieren Allgemeine Java-Themen 4
M Array per Reflection manipulieren Allgemeine Java-Themen 5

Ähnliche Java Themen

Neue Themen


Oben