Jpeg performant skalieren

Status
Nicht offen für weitere Antworten.

UlfL

Mitglied
Hallo zusammen,

suche seit längerem eine Möglichkeit, grosse Jpeg-Dateien (5-8MB) performant zu skalieren. Ohne Interpolation klappt es mit Graphics2D.drawImage() ganz gut, aber mit Interpolation dauert es zwischen zwei und vier Minuten. So sieht mein Code aus:

[highlight=Java]
public BufferedImage createScaledBufferedImage(BufferedImage originalImage, String type, boolean useInterpolation)
{
// ---- Anfang Ausschnitt
BufferedImage bi;
Graphics2D g2;
bi = createCompatibleImage(thumbnailWidth,thumbnailHeight,BufferedImage.TYPE_INT_RGB);
g2 = bi.createGraphics();
if(useInterpolation)
{
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
}

g2.drawImage(originalImage, 0, 0, thumbnailWidth, thumbnailHeight, null);
g2.dispose();
return bi;
// ---- Ende Ausschnitt
}

private BufferedImage createCompatibleImage(int width, int height, int type) {
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsConfiguration gc = ge.getDefaultScreenDevice().getDefaultConfiguration();
BufferedImage image = gc.createCompatibleImage(width, height, type);
return image;
}
[/highlight]

Wenn useInterpolation == false, dann geht das Ganze ziemlich fix, aber mit den RenderingHints.VALUE_INTERPOLATION_BILINEAR wird das Warten zur Geduldsprobe. Mein Entwicklunsrechner: WinXP, Centrino Duo 1.83 GHz, 2 GB RAM.
Hat jemand eine Idee, wie dies performanter gemacht werden könnte? Habe die Hardware-Beschleuniging über System.setProperty("sun.java2d.ddscale", "true"); eingeschaltet, ohne spürbare Verbesserungen. Oder ist drawImage() einfach so langsam? Zugegeben, die Files sind ziemlich gross...
Wenn es hier keinen besseren Weg gibt, muss ich vielleicht doch auf native Bibliotheken, wie z.B. ImageMagick, zurückgreifen.

Viele Grüsse,
Ulf
 
Zuletzt bearbeitet:

Marco13

Top Contributor
Hmja... abgesehen von diesem Link java.net: The Perils of Image.getScaledInstance() kann ich zwar keine konkreten Tipps geben, aber ... ein 5MB JPG-Bild kann eine Auflösung von 2000x2000 haben, oder eine von 50000x50000 ... Schonmal GROB geschaut, wie lange ein natives, spezialisiertes Programm (von IrfanView bis Photoshop...) für so eine Skalierungsaktion braucht?
 

0x7F800000

Top Contributor
grosse Jpeg-Dateien (5-8MB)
...
thumbnail
...
RenderingHints.VALUE_INTERPOLATION_BILINEAR
Aus den ersten beiden stichwörtern schließe ich, dass du das Bild verkleinern willst.
Da ist der Bilineare Filter absolut unbrauchbar: was soll denn der filter machen? Wenn du zB. in einer reihe hundert pixeln uberspringst, macht es die sache nicht besser, wenn du dann zwischen dem 101 und dem 102 pixel linear interpolierst: du kriegst trotzdem nur verrauschten schrott raus, da kannst du genausogut die koordinaten abrunden und einfach den nächstbesten pixel nehmen, also einfach ohne filter skalieren.
Wenn useInterpolation == false, dann geht das Ganze ziemlich fix, aber mit den RenderingHints.VALUE_INTERPOLATION_BILINEAR wird das Warten zur Geduldsprobe.
Nja, lohnt es sich denn? Aus dem oben geschriebenen Grund müsste imho beides ziemlich verrauscht aussehen.
Da müsste man eigentlich mit einem anderen Filter dran, anisotropische wäre natürlich toll, aber ich habe keinen soclhe rendering hint gefunden ???:L Vielleicht muss man einfach antialiasing einschalten, und das bild auf die kleinere Fläche zeichnen, da sollte er auch für jeden Bildpunkt den Mittelwert der drumherum liegenden Pixel ausrechnen: das wäre ja schon genau das was du brauchst.
Mein Entwicklunsrechner: WinXP, Centrino Duo 1.83 GHz, 2 GB RAM.
Ich weiß es nicht genau, aber das Bild wird wahrscheinlich rein Softwaremäßig skaliert. Und womöglich nur auf der einen Hirnhälfte... Hast du schonmal versucht, das bild einfach in der Mitte aufzuteilen und beide Teile in zwei parallelen Threads zu skalieren? Glaube zwar kaum, dass das was bringen würde, aber man kann's ja mal versuchen, dauert ja nicht lange.
Vor dem Versuch aber bitte STRG+Alt+Entf -> Taskmanager -> Leistung guggen, wenn da [100%,3%] statt [99%,100%] angezeigt wird, könnte man es mit 2 threads versuchen.

Habe die Hardware-Beschleuniging über System.setProperty("sun.java2d.ddscale", "true"); eingeschaltet, ohne spürbare Verbesserungen.
Achso... Hardwarebeschleunigt... Hmm... Wer weiß, wenn du so ein reines Business-laptop mit einer spartanischen Grafikkarte hast, dann bist du womöglich mit dem hauptprozessorr besser dran (das sind aber echt nur noch mutmaßungen^^)
 
Zuletzt bearbeitet:

UlfL

Mitglied
Hi Marco, und danke für dein Antwort. Der von dir genannten Artikel habe ich schon gelesen, und entsprechend ein paar Anpassungen gemacht, ohne das es viel geändert hat.
Die meisten Jpegs haben eine Auflösung um die 4000x3000 Pixel. Photoshop braucht für dieselbe Aktion etwa 2 Sekunden im Batchmodus, wo die Datei auch von der Platte gelesen, gespeichert und geschlossen wird... :oops:
 

UlfL

Mitglied
Aus den ersten beiden stichwörtern schließe ich, dass du das Bild verkleinern willst.
Da ist der Bilineare Filter absolut unbrauchbar: was soll denn der filter machen? da kannst du genausogut die koordinaten abrunden und einfach den nächstbesten pixel nehmen, also einfach ohne filter skalieren.
Da müsste man eigentlich mit einem anderen Filter dran, anisotropische wäre natürlich toll, aber ich habe keinen soclhe rendering hint gefunden ???:L Vielleicht muss man einfach antialiasing einschalten,
Du hast Recht, ich möchte verkleinern. Das bilineare Filter erzeugt schon ein glatteres Bild als ohne Filter oder nur Antialias (bei den beiden letzteren sehe ich kein Unterschied), wobei der Unterschied nicht wirklich gross ist. Siehe Anhänge. Vielleicht hast du Recht, womöglich brauche ich einfach eine niedrigere Jpeg-Kompression, um die Kompressionsartefakte zu reduzieren.
Achso... Hardwarebeschleunigt... Hmm... Wer weiß, wenn du so ein reines Business-laptop mit einer spartanischen Grafikkarte hast, dann bist du womöglich mit dem hauptprozessorr besser dran (das sind aber echt nur noch mutmaßungen^^)
Habe eine ATI Radeon X1600 256MB.
Bild 1: Antialias. Bild 2: Bilinear. Bild 3: Ohne Filter
 

Anhänge

  • Antialias.jpg
    Antialias.jpg
    53,5 KB · Aufrufe: 68
  • Bilinear.jpg
    Bilinear.jpg
    49,7 KB · Aufrufe: 65
  • Ohne Filter.jpg
    Ohne Filter.jpg
    53,5 KB · Aufrufe: 58

UlfL

Mitglied
Hi zusammen,

habe jetzt ein wenig mit JMagic/ImageMagick experimentiert, und bin von den Ergebnissen überzeugt. Der Skalierungsalgorithmus von ImageMagick muss sich nicht hinter der von Photoshop verstecken (siehe angehängte Bilder) und die Geschwindigkeit lässt nichts zu wünschen übrig.
Ist natürlich schade, das ganze nicht in "pure Java" machen zu können, aber ich finde das schon etwas enttäuschend, wie schlecht drawImage() mit "handelsübliche" Digitalkameraphotos umgeht, sobald man ein bilineares (oder gar bikubisches) Filter hinzufügt.

//Ulf

Bild 1: Photoshop, Bild 2: Imagemagick
 

Anhänge

  • Bilinear - photoshop.jpg
    Bilinear - photoshop.jpg
    51,6 KB · Aufrufe: 48
  • ImageMagick.jpg
    ImageMagick.jpg
    61,3 KB · Aufrufe: 51

Hansdampf

Bekanntes Mitglied
du könntest die Bilder erst ohne Filter etwas kleiner skalieren, dann im zweiten Durchgang MIT Filter weiter verkleinern.
Etwa so:
5000x5000 -> 1000x1000 ohne Filter
1000x1000 -> 200x200 mit Filter

Damit wird das ganze mindestens 10x so schnell und liefert die gleiche Qualität.
 

UlfL

Mitglied
Sorry, habe zuviel anderes um die Ohren, bin noch nicht dazu gekommen, Hans' Vorschlag auszuprobieren. Melde mich sobald ein Ergebnis vorliegt.

//Ulf
 

0x7F800000

Top Contributor
könnte feine horizontale bzw. vertikale Strukturen verschlucken... Wenn da jemand ein Photo eines Spinnennetzes hochlädt, könnte es bei diesem verfahren dazu kommen, dass nur die schrägen striche zu sehen sind, und das Netz aus vier Segmenten zu bestehen scheint... Pixel vielleicht nicht zeilen bzw Spaltenweise weglassen, sondern irgendwie ein wenig verstreut ;)
 

UlfL

Mitglied
Interessanter Hinweis. Werde ein feines Raster photographieren, und das als Versuchsbild verwenden.
 

eskimo328

Aktives Mitglied
ist zwar schon ein weilchen her der letzte beitrag aber egal.

Der Kommentar von mrsteve (Submitted On 10-MAR-2004) unter folgendem Link: Bug ID: 4705399 drawImage can be extremely slow for drawing scaled instances hat mir bei einem ähnlichen Problem geholfen

Hier die wichtige Stelle aus dem Link:

After extensive research into this problem I've found the
evaluation correct. A perfect workaround is to force the
reader to read in the normal color space. See below.
This is 20x quicker for a thumbnail generating
application than using ImageIO.read().

und hier der Code dazu:

Java:
public static BufferedImage readImage(Object source) throws IOException {
        ImageInputStream stream = ImageIO.createImageInputStream(source);
        ImageReader reader = (ImageReader) ImageIO.getImageReaders(stream).next();
        reader.setInput(stream);
        ImageReadParam param = reader.getDefaultReadParam();
        
        ImageTypeSpecifier typeToUse = null;

        for (Iterator i = reader.getImageTypes(0); i.hasNext(); ) {
            ImageTypeSpecifier type = (ImageTypeSpecifier) i.next();

            if (type.getColorModel().getColorSpace().isCS_sRGB()) 
                typeToUse = type;
        }

        if (typeToUse!=null) 
            param.setDestinationType(typeToUse);
            
        BufferedImage b = reader.read(0, param);
        
        reader.dispose();
        stream.close();
        return b;
    }
 

UlfL

Mitglied
Hi Eskimo,

und vielen Dank für dein Post, es hat tatsächlich die Probleme behoben. Auch große Dateien werden performant und in guter Qualität skaliert.

Unglaublich das es hierzu kein Best-Practices von Sun gibt. Man stochert ja buchstäblich im Nebel bei diesen vielen Klassen und Möglichkeiten in Java2d.

Viele Grüße,
Ulf
 
Status
Nicht offen für weitere Antworten.
Ähnliche Java Themen
  Titel Forum Antworten Datum
E Alternative zu import com.sun.image.codec.jpeg.JPEGCodec ? Spiele- und Multimedia-Programmierung 1
S JPEG und RGB Farben Spiele- und Multimedia-Programmierung 14
G JPEG mit transparentem PNG versehen Spiele- und Multimedia-Programmierung 8
H Jpeg Bildinformation in ein Char Array speichern? Spiele- und Multimedia-Programmierung 4
C JPEG oder BMP Bild erstellen Spiele- und Multimedia-Programmierung 5
R JPEG aus HexString erstellen Spiele- und Multimedia-Programmierung 2
turing JOGL Cubes performant Spiele- und Multimedia-Programmierung 17
A bilder performant und unhässlich skalliert darstellen? Spiele- und Multimedia-Programmierung 10
S Vektor skalieren Spiele- und Multimedia-Programmierung 15
J Bild ohne Quallitätsverlust skalieren Spiele- und Multimedia-Programmierung 11
E Java3D Objekt skalieren per JSlider/JButton Spiele- und Multimedia-Programmierung 10
C 2D Sprites an die JPanel Größe (Auflösung) anpassen/skalieren Spiele- und Multimedia-Programmierung 3
F Programm für Bildbearbeitung gesucht: Skalieren und Speichern Spiele- und Multimedia-Programmierung 6
A Bilder (auf JPanels) auf komplette Zellengröße (GridBagLayout) skalieren Spiele- und Multimedia-Programmierung 2
A Richtungsabhängiges Skalieren mit Interpolator Spiele- und Multimedia-Programmierung 2
M Skalieren mit AffineTransform und SCALE_SMOOTH? Spiele- und Multimedia-Programmierung 3
G Objekt nicht ins negative oder null skalieren Spiele- und Multimedia-Programmierung 2

Ähnliche Java Themen


Oben