2D-Grafik g2.drawImage() langsam

Eigentlich Edit:

[EDIT]@ Marco
Java:
private BufferedImage createImageFromByteArray(int w, int h, byte input[]) 
    {   
        int output[] = new int[input.length];
        for (int i = 0; i < input.length; i++) 
        {
            byte v = input[i];
            int a = 0xFF000000;
            int r = (v & 0xFF) << 16; 
            int g = (v & 0xFF) <<  8; 
            int b = (v & 0xFF) <<  0; 
            output[i] = a | r | g | b;
        }
        BufferedImage result = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
        long t1=System.currentTimeMillis();
        Image im= createImage(new MemoryImageSource(w, h,output , 0, w));//0  
        result.getGraphics().drawImage(im, 0,0,w,h,null);//32-63  
        //result.setRGB(0,0, w, h, output, 0, w);
        System.out.print("create8bitBI   "); System.out.println(System.currentTimeMillis()-t1); 
        return result;
    }
Ich hab mal deine setRGB Methode auskommentiert und das mit dem Image gesetzt wie ich das meinte. An der Stelle sind vorher bei meinem 6MB tiff etwa 130ms vergangen. Jetzt sinds 30ms-60ms und bei jedem vierten Aufruf sinds 140ms (Warum bei jedem vierten Aufruf 140ms?Wenn mir das jemand beantworten kann immer her damit - das ist auch das was ich bei mir meinte, nur da ist es bei jedem zweiten Aufruf der Fall. Hat das was mit dem Garbage Collector zu tun?)
[/EDIT]



[EDIT]Edit die zweite:
Also ihr habt euch ja die ganze Zeit gefragt warum ich da sone komische Berechnung habe. Mir fiel nicht auf, dass ihr einfach Java implizit eure unsigned Werte in signed Werte umrechnen lasst. Das mache ich explizit mit meinen Abfragen. Bei meinen Tests eben fand ich raus, dass meine zusätzlichen Zeilen Code jedoch keinerlei Geschwindigkeitsnachteil bedeuten. Das was Java da implizit macht ist also keinesfalls schneller. Jedoch fange ich das "spratzeln" ab was durch Rundungsfehler an der weiß schwarz Grenze auftritt. Hier zur Demonstration mal ein Bild was ich meine
[/EDIT]
 

Anhänge

  • interpretation des signed bytes beim Zeichnen.PNG
    interpretation des signed bytes beim Zeichnen.PNG
    10,4 KB · Aufrufe: 26
Zuletzt bearbeitet:
Bei mir z.B. ist dieser Bereich dauerhaft von min (Schwarz) bis max (Weiss) in 16 Bit und von 0 bis min wird Weiss und von max bis 65535 Schwarz ausgeblendet. Bei Marco ist's kaum anders aber halt auf Byteebene so wie bei dir.
Und @Marco: Mit kaum meine ich, dass du bei einer deiner Versionen tatsächlich einen gerinfügigen Fehler hast, wodurch mit 0 statt mit 255 ausgeblendet wird. Liegt anscheinend an jenem hier:[JAVA=182]output = (byte)(f * 256);[/code]statt[JAVA=182]output = (byte)(f * 255);[/code]
 
So wäre Marcos Code "optimal"

Java:
private static byte[] convertShortToByteArrayClamping(short input[], int min, int max)
    {
        float value = 0;
        byte output[] = new byte[input.length];
        float normalization = 1.0f / (max - min);
        for (int i=0; i<input.length; i++)
        {           
            if (input[i]>min&&input[i]<max)
            {
                value = (input[i]-min)*normalization;
                output[i] = (byte)(value * 256);                
            }
            if (input[i] <= min)
            {
                output[i]=0;
            }
            if (input[i] >= max)
            {
                output[i]=-1;
            }           
        }
        return output;
    }
Das spratzeln ist damit weg


@Spacerat: ok. Kannst du mir die Frage bezüglich des Garbage Collectors beantworten?
 
Zuletzt bearbeitet:
Also ich würde auch auf deb GC tippen, genaueres aber kann auch ich nicht sagen. Im übrigen kann das bei Marco auch passieren. Bei mir allerdings nicht, weil ich "new" nicht so exxessiv verwende. Mal schauen, was passiert, wenn ich meine Version auch auf 8 Bit reduziere.
Was ich aber noch sagen kann... bei Marco wäre das "Spratzeln" auch weg, wenn du mal 255 statt mal 256 nehmen würdest. Die zusätzlichen if's sind überflüssig. 0,9999 * 256 ergeben 255 (Weiss) 1.0 * 256 ergibt 256 bzw. 0 (Schwarz) und da f im bereich von 0 bis 1 liegt...
 
Zuletzt bearbeitet von einem Moderator:
Java:
....
        Image im= createImage(new MemoryImageSource(w, h,output , 0, w));//0  
        result.getGraphics().drawImage(im, 0,0,w,h,null);//32-63  
        //result.setRGB(0,0, w, h, output, 0, w);
...
    }
Ich hab mal deine setRGB Methode auskommentiert und das mit dem Image gesetzt wie ich das meinte. An der Stelle sind vorher bei meinem 6MB tiff etwa 130ms vergangen. Jetzt sinds 30ms-60ms....

Aha... das ist interessant. Kann mir kaum vorstellen, was die MemoryImageSource da schneller machen sollte als setRGB... vielleicht spart sie irgendwie geschickt Konvertierungen...?

Auch wenn man bei solchen "einzelnen" Zeitmessunge SEHR vorsichtig sein sollte: Wenn das ein Microbenchmark sein sollte, müßte man das ggf. mehrfach in einer Schleife mit verschiedenen Bildgrößen laufen lassen, und die Gesamtzeit messen.

Dass bestimmte Operationen regelmäßig (also wirklich GENAU(!!!) jedes n-te mal) länger brauchen hatte ich auch bei einem der Tests beobachtet, und konnte es mir spontan auch nicht erklären.... ???:L Am GC kann's kaum liegen, der läuft i.a. nicht so regelmäßig und würde bei größerem Xmx eh erst viel später zuschlagen. Ich würde eher darauf tippen, dass eine bestimmte Anzahl Bilder irgendwo in bestimmten bereichen des VRAM gehalten (also "managed" gehalten) werden können, aber das ist wilde Spekulation....
 
Also ich würde auch auf deb GC tippen, genaueres aber kann auch ich nicht sagen. Im übrigen kann das bei Marco auch passieren. Bei mir allerdings nicht, weil ich "new" nicht so exxessiv verwende. Mal schauen, was passiert, wenn ich meine Version auch auf 8 Bit reduziere.
Was ich aber noch sagen kann... bei Marco wäre das "Spratzeln" auch weg, wenn du mal 255 statt mal 256 nehmen würdest. Die zusätzlichen if's sind überflüssig. 0,9999 * 256 ergeben 255 (Weiss) 1.0 * 256 ergibt 256 bzw. 0 (Schwarz) und da f im bereich von 0 bis 1 liegt...

Nein, ich glaub da hast du unrecht
du meinst so?
Java:
private static byte[] convertShortToByteArrayClamping(short input[], int min, int max)
    {   
        float value = 0;
        byte output[] = new byte[input.length];
        float normalization = 1.0f / (max - min);
        for (int i=0; i<input.length; i++)
        {           
            if (input[i]>min&&input[i]<max)
            {
                value = (input[i]-min)*normalization;
                output[i] = (byte)(value * [B]255[/B]);                
            }          
        }
        return output;
    }
das sprazelt
 
Dass bestimmte Operationen regelmäßig (also wirklich GENAU(!!!) jedes n-te mal) länger brauchen hatte ich auch bei einem der Tests beobachtet, und konnte es mir spontan auch nicht erklären.... ???:L Am GC kann's kaum liegen, der läuft i.a. nicht so regelmäßig und würde bei größerem Xmx eh erst viel später zuschlagen.

Ich habe aufGrund von nur 2GB Ram und einem nicht gescheit funktionierenden Netbeans keine Möglichkeit per Xmx den Heap zu vergrößern. Mein Heap ist bei 384MB also wollte ich das nicht ausschließen. Wie gesagt mein 28MB Tiff kann ich erst gar nicht reinladen weil der Heap zu klein ist.
 
384MB Klingt nach dem, was für NetBeans selbst allokiert ist, aber nicht für das zu startende Programm. Sicher, dass du an der richtigen Stelle gesucht hast? Auf einer 32bit VM sollten 1.2 GB drin sein, auf einer 64bittigen "beliebig" viel (wie viel RAM die Kiste hat ist prinzipiell egal, notfalls wird auf die Platte ausgelagert, wodurch es ein paar tausend mal langsamer wird...)
 
@bERt0r: Gut gemacht... Aber hast du dir mal die Anwendungen von Marco und mir angesehen? Da kommt bei dem grossen PNG-Bild im mittleren Abschnitt bei einigen vielen Einstellungen der Regler so ein Gebilde zum Vorschein, dass an "Fischgräten" erinnert (siehe Anhang). Bei deiner Version kann ich einstellen, was ich will, das Gebilde will sich nicht zeigen.

Hmmm weis nicht, Marcos Programm liefert bei mir die gleichen Ergebnisse wie meins und deines zeigt nur Schwarz an bzw. wirft eine NPE. Vielleicht stimmt auch was mit meinem Rechner nicht... Ich bin aber draufgekommen dass ich vielleicht noch einen Fehler in der Berechnung hatte.

Ich poste jetzt nicht nochmal den ganzen Code aber sollte das nicht funktionieren? Mit dem bitweisen & umgehe ich die unsigned Problematik ohne komplizierte Umrechnung und erhalte eine Farbskala wie die von Planich - also 0=Schwarz, 32767=grau, -1=weiß. Als Ergebnis bekomme ich wieder ein shortArray welches ich einfach wieder in den Raster meines Images schreibe.

Java:
private short[] processPixels(short[] imgData, int upper, int lower)
	{
		int ug = Math.min(upper, lower);
		int og = Math.max(upper, lower);
		
		double normalisierung= 0xFFFF/(og - ug);
		short[] pixels = new short[imgData.length];
		int pixel;
		
		for (int i = 0; i < imgData.length; i++)
		{
			pixel = imgData[i] &0xFFFF;
			
			if (pixel >= ug && pixel <= og)
			{
				pixel = (int) (((pixel - ug) * normalisierung));
				
			} else if (pixel < ug)
			{
				pixel = 0;
			} else
			{
				pixel = -1;
			}
			
			pixels[i] = (short) pixel;
		}
		return pixels;
	}

	private synchronized void updateImage()
	{
		long start = System.nanoTime();
		if (image != null)
		{
			int w = image.getWidth();
			int h = image.getHeight();
			
			short[] pixelData = processPixels(shortData, lowerBound, upperBound);
			image.getRaster().setDataElements(0, 0, w, h, pixelData);
			lblImage.repaint();
		}
		long end = System.nanoTime();
		System.out.println("Time to calculate: " + (end - start) / 1e6 + " ms");
	}
[EDIT]Was ich noch vergas, als upper und lower Parameter kommen Werte im Bereich von 0 - 65535[/EDIT]
 

Anhänge

Zuletzt bearbeitet:
@Planich: Okay, jetzt hab' ich kapiert, was du mit "spratzeln" meinst. Klar, wenn Marco und ich unsere Formeln anwenden, invertieren wir die Werte ausserhalb von ug und og sozusagen nur weil sie noch weiter aufgespreizt werden und es zu Bereichsüberschreitungen kommt. Okay, einverstanden, das Ausblenden macht Sinn. Ich mach's zwar nun etwas anders, kommt aber auf's selbe raus.
@Marco_13: Dein Fehler mit der 255 statt der 256 bleibt aber bestehen. Erst recht dann, wenn du in etwa wie ich ausblendest, weil dann bei der anschliessenden Berechnung als Höchstwert wie gesagt 0 statt 255 herauskommt.
@bERt0r: Bei deiner Version kann ich diese Gräten immer noch nicht sehen, kann mir allerdings nicht erklären warum.

Ich habe meine Version nun noch einmal abgeändert (zip im Anhang), weil mir etwas nicht einleuchten wollte. Warum eigentlich immer die Daten des Rasters (backUp) bei jeder Änderung erneut in das 16Bit-Raster schreiben, wo sich diese Daten doch erst dann ändern, wenn man per Graphics-Object oder per setRGB in dieses Raster zeichnet. Beides tun wir hier ja nicht. Bei einer Änderung sollte also ein "notifyChanged()" auf das SunWritableRaster genügen (ohne dies, schaffe ich den Repaint in 0,nix, leider tut sich dann auch nur genau so viel: null komma nix), damit sich die JVM die neu berechneten Daten beim Repaint über das ColorModel holt. Tatsächlich, es funktioniert. Bei meiner Version werden, wenn überhaupt, nur geringfügig neue Objekte (am allerwenigsten Images, Arrays oder sonstwas) erstellt. Kurzum, ich muss "OwnImage" bei jeder Änderung nur noch neuzeichnen. Das dauert aber immernoch konstant zwischen 130 bis 150ms. Je nachdem wie hoch der Weiss- bzw. Schwarzanteil bei den Einstellungen ist geht es schneller. Das ist aber wie zuvor die Zeit für den gesammten Repaintvorgang. Was mir immer noch nicht einleuchtet, ist, wie Marcos oder bERt0rs Versionen mit all ihren Neuinstanzierungen und ArrayCopys performanter sein können.
 

Anhänge

Zuletzt bearbeitet von einem Moderator:

Neue Themen


Zurück
Oben