Discussion:
Bildqualität beim Skalieren verbesssern
(zu alt für eine Antwort)
Tobias Stening
2005-06-25 10:11:39 UTC
Permalink
Hallo zusammen,

folgendes Codefragment skaliert mir Bilder, die vorher von Platte
gelesen wurden und danach mit dem JPEGImageEncoder geschrieben werden.

BufferedImage scaledImage = new BufferedImage(
scaledWidth,
scaledHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(image, 0, 0, scaledWidth, scaledHeight, null);

FileOutputStream fos = new FileOutputStream(dest));
BufferedOutputStream out = new BufferedOutputStream(fos);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(scaledImage);
param.setQuality(0.6f, false);
encoder.encode(scaledImage);
out.close();

Ist nicht besonders schnell, funktioniert aber. Leider ist die Qualität
der skalierten Bilder nicht gerade berauschend. Im direkten Vergleich
mit einer Bildverarbeitung findet man in den skalierten Bildern an
schrägen geraden Kanten häufig Treppchen.

Beispiel: http://www.cmaxx.de/temp/test.html

Kann man die Qualität verbessern? Wenn ja, wie?

Viele Grüße,
Tobias
Michael Dänzer
2005-06-25 12:21:11 UTC
Permalink
Hallo Tobias

Ohne grosse Ahnung (um nicht zu sagen keine) von diesem AWT Teil zu
haben, evtl statt

graphics2D.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);

villeicht

graphics2D.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BICUBIC);

benutzen. Bikubische Interpolation liefert normalerweise bessere
Resultate als Bilineare Interpolation, wie du in Photoshop auch gesehen
hast.

Gruss
Michael
Post by Tobias Stening
Hallo zusammen,
folgendes Codefragment skaliert mir Bilder, die vorher von Platte
gelesen wurden und danach mit dem JPEGImageEncoder geschrieben werden.
BufferedImage scaledImage = new BufferedImage(
scaledWidth,
scaledHeight,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = scaledImage.createGraphics();
graphics2D.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphics2D.drawImage(image, 0, 0, scaledWidth, scaledHeight, null);
FileOutputStream fos = new FileOutputStream(dest));
BufferedOutputStream out = new BufferedOutputStream(fos);
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(scaledImage);
param.setQuality(0.6f, false);
encoder.encode(scaledImage);
out.close();
Ist nicht besonders schnell, funktioniert aber. Leider ist die Qualität
der skalierten Bilder nicht gerade berauschend. Im direkten Vergleich
mit einer Bildverarbeitung findet man in den skalierten Bildern an
schrägen geraden Kanten häufig Treppchen.
Beispiel: http://www.cmaxx.de/temp/test.html
Kann man die Qualität verbessern? Wenn ja, wie?
Viele Grüße,
Tobias
Tobias Stening
2005-06-25 12:36:43 UTC
Permalink
Hallo Michael,
Post by Michael Dänzer
Hallo Tobias
[...]
benutzen. Bikubische Interpolation liefert normalerweise bessere
Resultate als Bilineare Interpolation, wie du in Photoshop auch gesehen
hast.
Da habe ich geschlampt, denn bikubische Interpolation hatte ich für das
Beispiel unter http://www.cmaxx.de/temp/test.html auch auf der
Java-Seite verwendet, nur im Beispielcode im Posting nicht angegeben.

Habe es nochmal getestet und es sieht mit beiden Interpolationsarten,
also bilinear und bikubisch nicht so toll aus, während Photoshop es bei
beiden Arten sauber macht.

Viele Grüße,
Tobias
Peter Büttner
2005-06-25 12:54:44 UTC
Permalink
Post by Tobias Stening
Hallo Michael,
Post by Michael Dänzer
Hallo Tobias
[...]
benutzen. Bikubische Interpolation liefert normalerweise bessere
Resultate als Bilineare Interpolation, wie du in Photoshop auch gesehen
hast.
Da habe ich geschlampt, denn bikubische Interpolation hatte ich für das
Beispiel unter http://www.cmaxx.de/temp/test.html auch auf der
Java-Seite verwendet, nur im Beispielcode im Posting nicht angegeben.
Habe es nochmal getestet und es sieht mit beiden Interpolationsarten,
also bilinear und bikubisch nicht so toll aus, während Photoshop es bei
beiden Arten sauber macht.
Bevor du weiter versuchst:
hats du die jpg kompression nicht verschieden stark eingestellt?
das PS Bild hat 52k, das Java 43k.
Speichere sie (für dich) verlustfrei, z.b. png.

PS und Java: die sollten sich eigentlich nicht unterscheiden,
bicubic/-linear sind doch eher altehrwürdige Verfahren an denen
nicht viel gedreht wird?


Ansonsten würde ich die rendering hints weiter untersuchen,
(ich müsste da jetzt auch rumsuchen, aber es ist zu warm und
nicht soviel Zeit:-)

Eine billige Idee:
die RenderingHints sind ja nicht soo viele.
baue alle Kombinationen zusammen (for schleifen), erzeuge 100 Bilder
und such dir das beste raus. ja, das ist dumm, verstehen wäre besser,
aber so'ne massenaktion können Compis nun mal gut.


Ansonsten: Tutorials im Netz suchen


Ach ja: meiner erfahrung nach sehen kleinskalierte Bilder etwas
besser aus wenn man sie leicht nachschärft.
Und nicht zu stark jpg komprimieren:
was billiges zum gucken
www.peterbuettner.de/projects/jpgoptimizer/


Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Tobias Stening
2005-06-25 13:39:03 UTC
Permalink
Post by Peter Büttner
hats du die jpg kompression nicht verschieden stark eingestellt?
das PS Bild hat 52k, das Java 43k.
Speichere sie (für dich) verlustfrei, z.b. png.
Ich habe jeweils eine Qualitätseinstellung von 60% gewählt.
Post by Peter Büttner
Ansonsten würde ich die rendering hints weiter untersuchen,
(ich müsste da jetzt auch rumsuchen, aber es ist zu warm und
nicht soviel Zeit:-)
Werde wohl kaum drumrum kommen, mal alles möglich zu testen. War sogar
eben schon so weit, JAI zu testen, wobei das ein dicker Brocken Arbeit
geworden wäre.
Post by Peter Büttner
Ach ja: meiner erfahrung nach sehen kleinskalierte Bilder etwas
besser aus wenn man sie leicht nachschärft.
was billiges zum gucken
www.peterbuettner.de/projects/jpgoptimizer/
In meinem Fall dürfte der Treppeneffekt aber wohl eher nicht von der
Komprimierung kommen, sondern eine andere Ursache haben. ACDSee macht
auch bei hohen Kompressionsraten keine Treppen an Kanten.

Habe unter http://www.cmaxx.de/temp/test.html nochmal ein drittes
Testbild abgelegt.

Viele Grüße,
Tobias
Peter Büttner
2005-06-25 13:50:51 UTC
Permalink
Post by Tobias Stening
Post by Peter Büttner
hats du die jpg kompression nicht verschieden stark eingestellt?
das PS Bild hat 52k, das Java 43k.
Speichere sie (für dich) verlustfrei, z.b. png.
Ich habe jeweils eine Qualitätseinstellung von 60% gewählt.
IMHO sagt das nicht so viel aus, nicht standarisiert.
Mach 2 png (ps/java)
nimm mein programm und mach das ps.png von der Datei größe so
groß wie das ps.jpg, wenn das bei 60 ist passt es.
Post by Tobias Stening
Post by Peter Büttner
Ansonsten würde ich die rendering hints weiter untersuchen,
(ich müsste da jetzt auch rumsuchen, aber es ist zu warm und
nicht soviel Zeit:-)
Werde wohl kaum drumrum kommen, mal alles möglich zu testen. War sogar
eben schon so weit, JAI zu testen, wobei das ein dicker Brocken Arbeit
geworden wäre.
Ich weis nicht ob dir das so hilft, bicubic interpolation gibt nicht
viel Spielraum. Machst du denn mit PS noch andere Tricks? Evtl.
hat der 'nen besseren jpg encoder (also verdammt nochmal png zum testen
machen)
Post by Tobias Stening
Post by Peter Büttner
Ach ja: meiner erfahrung nach sehen kleinskalierte Bilder etwas
besser aus wenn man sie leicht nachschärft.
was billiges zum gucken
www.peterbuettner.de/projects/jpgoptimizer/
In meinem Fall dürfte der Treppeneffekt aber wohl eher nicht von der
Komprimierung kommen, sondern eine andere Ursache haben. ACDSee macht
auch bei hohen Kompressionsraten keine Treppen an Kanten.
Kompression hat viele Optionen, da kannst du die verschiedenen
Programme nicht 'einfach mal so' als gleich ansehen.
Post by Tobias Stening
Habe unter http://www.cmaxx.de/temp/test.html nochmal ein drittes
Testbild abgelegt.
An der Tiernase sieht man deutlich Treppen

Und das ist nun nur noch 32k groß, das am Arm würde ich
schon ziemlich wahrscheinlich als Kompressionsartefakte
einschätzen.

Ohne png sag ich nix mehr.


Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Tobias Stening
2005-06-25 16:37:37 UTC
Permalink
Post by Peter Büttner
Post by Tobias Stening
Post by Peter Büttner
hats du die jpg kompression nicht verschieden stark eingestellt?
das PS Bild hat 52k, das Java 43k.
Speichere sie (für dich) verlustfrei, z.b. png.
Ich habe jeweils eine Qualitätseinstellung von 60% gewählt.
IMHO sagt das nicht so viel aus, nicht standarisiert.
Mach 2 png (ps/java)
nimm mein programm und mach das ps.png von der Datei größe so
groß wie das ps.jpg, wenn das bei 60 ist passt es.
Post by Tobias Stening
Post by Peter Büttner
Ansonsten würde ich die rendering hints weiter untersuchen,
(ich müsste da jetzt auch rumsuchen, aber es ist zu warm und
nicht soviel Zeit:-)
Werde wohl kaum drumrum kommen, mal alles möglich zu testen. War sogar
eben schon so weit, JAI zu testen, wobei das ein dicker Brocken Arbeit
geworden wäre.
Ich weis nicht ob dir das so hilft, bicubic interpolation gibt nicht
viel Spielraum. Machst du denn mit PS noch andere Tricks? Evtl.
hat der 'nen besseren jpg encoder (also verdammt nochmal png zum testen
machen)
Keine weiteren Trick mit Photoshop. Nur Bild laden, Größe ändern und als
JPG exportieren.

Werde mir Deinen Rat nun zu Herzen nehmen und es morgen mit PNG
ausprobieren. Heute komme ich wohl nicht mehr dazu.
Post by Peter Büttner
An der Tiernase sieht man deutlich Treppen
Stimmt. Die sind mir vorhin in der Schnelle nicht aufgefallen.
Post by Peter Büttner
Und das ist nun nur noch 32k groß, das am Arm würde ich
schon ziemlich wahrscheinlich als Kompressionsartefakte
einschätzen.
Aber warum hat es denn nun ne andere Größe, als das vorhergehende
Java-Bild? Habe nur eine andere Skalierungsmethode verwendet, sonst ist
alles gleich geblieben.

Das schreit jetzt nach nem sauberen Vergelichstest. Den werde ich morgen
mal machen.

Viele Grüße,
Tobias
Timo Stamm
2005-06-25 17:33:14 UTC
Permalink
Post by Tobias Stening
Aber warum hat es denn nun ne andere Größe, als das vorhergehende
Java-Bild? Habe nur eine andere Skalierungsmethode verwendet, sonst ist
alles gleich geblieben.
Andere Skalierung heisst anderes Bild heisst der Encoder greift anders.
Das kann auch deutliche Unterschiede in der Dateigrösse ausmachen.
Post by Tobias Stening
Das schreit jetzt nach nem sauberen Vergelichstest. Den werde ich morgen
mal machen.
Teste die beiden Phänomene isoliert. Momentan testest du mit zwei
Variablen, der Skalierung und der Kompression.


Gruss,
Timo
Tobias Stening
2005-06-26 10:06:22 UTC
Permalink
Post by Timo Stamm
Post by Tobias Stening
Das schreit jetzt nach nem sauberen Vergelichstest. Den werde ich
morgen mal machen.
Teste die beiden Phänomene isoliert. Momentan testest du mit zwei
Variablen, der Skalierung und der Kompression.
Habe den Test umgehen können, da ich auf den Tipp von Marco eingegenagen
bin und skaliere in mehreren Schritten. Die Qualität ist dabei recht gut
und die Geschwindigkeit leidet entgegen meiner Erwartung nicht.

Allerdings würde ich gerne noch einen Filter (Scharfzeichnen) auf das
skalierte Bild anwenden. Evtl. auch vor der Skalierung einen
Weichzeichner. Leider fehlt mir da derzeit vollkommen das Wissen, wie
man das in Java macht.

Hat dazu noch jemand nen Tipp oder Link parat?

Viele Grüße,
Tobias
Marco Schmidt
2005-06-26 12:40:48 UTC
Permalink
Tobias Stening:

[...]
Post by Tobias Stening
Allerdings würde ich gerne noch einen Filter (Scharfzeichnen) auf das
skalierte Bild anwenden. Evtl. auch vor der Skalierung einen
Weichzeichner. Leider fehlt mir da derzeit vollkommen das Wissen, wie
man das in Java macht.
Es gibt eine vorgefertigte Operation java.awt.image.ConvolveOp. Der
muß man dann den richtigen Kernel geben. Code-Beispiele finden sich
etwa auf
<http://www.java2s.com/ExampleCode/2D-Graphics-GUI/ImageEffectSharpenblur.htm>
oder
<http://www.vorlesungen.uos.de/informatik/javaapi/Java2D/#Bilder>.

Gruß,
Marco
--
Bitte nur in der Newsgroup antworten, nicht per Email!
Meine Java-Seiten: http://schmidt.devlib.org/java/
FAQ: http://www.faqs.org/faqs/de/comp-lang-java/faq/
de.comp.lang.java Homepage: http://www.dclj.de/
Tobias Stening
2005-06-26 15:22:38 UTC
Permalink
Post by Marco Schmidt
Post by Tobias Stening
Allerdings würde ich gerne noch einen Filter (Scharfzeichnen) auf das
skalierte Bild anwenden. Evtl. auch vor der Skalierung einen
Weichzeichner. Leider fehlt mir da derzeit vollkommen das Wissen, wie
man das in Java macht.
Es gibt eine vorgefertigte Operation java.awt.image.ConvolveOp. Der
muß man dann den richtigen Kernel geben. Code-Beispiele finden sich
etwa auf
<http://www.java2s.com/ExampleCode/2D-Graphics-GUI/ImageEffectSharpenblur.htm>
oder
<http://www.vorlesungen.uos.de/informatik/javaapi/Java2D/#Bilder>.
Danke fürs Futter. Werde ich mir ebenfalls ansehen, wie die Links von Peter.

Viele Grüße,
Tobias
Dennis Cieplik
2005-06-29 12:05:52 UTC
Permalink
Hallo,
Post by Tobias Stening
Allerdings würde ich gerne noch einen Filter (Scharfzeichnen) auf das
skalierte Bild anwenden. Evtl. auch vor der Skalierung einen
Weichzeichner. Leider fehlt mir da derzeit vollkommen das Wissen, wie
man das in Java macht.
bei ähnlicher Problmstellung versuchte ich ebenfalls vor der Skalierung
einen Filter anzuwenden. Dies brachte jeodoch nicht den gewünschten erfolg.

Letzlich bin ich bei JAI gelandet und benutze für die Thumbnailerzeugung
folgendes:

public static byte[] createThumbnail(byte[] imageData)
{
InputStream istream = new ByteArrayInputStream(imageData);
SeekableStream sstream = SeekableStream.wrapInputStream(istream, true);
RenderedOp simage = (RenderedOp) JAI.create("stream", sstream);
simage = scale2(simage, 192);
ParameterBlock pb = new ParameterBlock();
pb = new ParameterBlock();
pb.addSource(simage);
pb.add(DataBuffer.TYPE_BYTE);
RenderedImage formatedVersion1 = JAI.create("format", pb, null);
JPEGEncodeParam param = new JPEGEncodeParam();
param.setQuality(1.0f);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
JAI.create("encode", formatedVersion1, stream, "jpeg", param);
byte[] b = stream.toByteArray();
stream = null;
return b;
}

private static RenderedOp scale2(RenderedOp img, int wid)
{
ParameterBlock pbs;
while (wid < img.getHeight())
{
float esc = Math.max(((float) (wid) / img.getHeight()), 0.5f);
pbs = new ParameterBlock();
pbs.addSource(img);
pbs.add(esc).add(esc).add(0.0F).add(0.0F);
pbs.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));
RenderingHints renderingHints = new RenderingHints(
JAI.KEY_BORDER_EXTENDER, BorderExtender
.createInstance(BorderExtender.BORDER_COPY));
img = JAI.create("scale", pbs, addScaleTileCacheHint(
renderingHints, img, esc, esc));
}
return img;
}

private static RenderingHints addScaleTileCacheHint(RenderingHints hints,
RenderedOp image, float factX, float factY)
{
int tW = (int) (image.getTileWidth() * factX);
int tH = (int) (image.getTileHeight() * factY);
ImageLayout il = null;
if (hints == null)
{
il = new ImageLayout().setTileWidth(tW).setTileHeight(tH);
hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, il);
} else
{
il = (ImageLayout) hints.get(JAI.KEY_IMAGE_LAYOUT);
if (il == null)
il = new ImageLayout();
il.setTileWidth(tW).setTileHeight(tH);
hints.put(JAI.KEY_IMAGE_LAYOUT, il);
}
return hints;
}


gefunden unter:
http://archives.java.sun.com/cgi-bin/wa?A2=ind0207&L=jai-interest&P=R74468&D=0&I=-3

Ich habe bei den Ergenissen keine Unterschied zu PS festgestellt.
Performance Vergleiche zu anderen Implementierungen in JAI finden sich
im genannten Thread. Vergleiche zu AWT sind dort nicht aufgelistet. Ich
denke jedoch, dass die JAI Lösung sich als performanter erweisen wird.

Gruss

Dennis
Tobias Stening
2005-07-01 00:49:22 UTC
Permalink
Post by Dennis Cieplik
Letzlich bin ich bei JAI gelandet und benutze für die Thumbnailerzeugung
[...]
Post by Dennis Cieplik
http://archives.java.sun.com/cgi-bin/wa?A2=ind0207&L=jai-interest&P=R74468&D=0&I=-3
Danke für den Code und den Link. Muss ich mir mal ansehen und testen.
Post by Dennis Cieplik
Ich habe bei den Ergenissen keine Unterschied zu PS festgestellt.
Performance Vergleiche zu anderen Implementierungen in JAI finden sich
im genannten Thread. Vergleiche zu AWT sind dort nicht aufgelistet. Ich
denke jedoch, dass die JAI Lösung sich als performanter erweisen wird.
Sobald ich dazu komme, werde ich mal meinen Ansatz und den hier
geposteten vergleichen. Eigentlich dürfte es kein Kunsstück sein,
schneller zu sein, als meine aktuelle Implementierung. ;-)

Viele Grüße,
Tobias

Tobias Stening
2005-06-25 12:31:27 UTC
Permalink
Post by Tobias Stening
Kann man die Qualität verbessern? Wenn ja, wie?
Nachtrag:

Verwende ich Image#getScaledInstance(...) ist die Qualität deutlich
besser, aber es scheint noch langsamer zu sein.

Ein Test mit

AffineTransformOp op = new AffineTransformOp(
AffineTransform.getScaleInstance(factor, factor),
AffineTransformOp.TYPE_BICUBIC);
Image scaledImage = op.filter(image, null);

verlief erstmal negativ, weil es sehr speicherhungrig ist.

Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.

Die Skalierung von 10 Digicamfotos (insgesamt 10 MB) mit einer Auflösung
von 1728x2304 Pixel auf 800x600 Pixel dauert mit lesen und schreiben bei
mir ca. 35 Sekunden (Pentium M, 1.4 GHz, 1 GB RAM). Das ist im Gegensatz
zu ACDSee 7 schon eher lahm.

Viele Grüße,
Tobias
Marco Schmidt
2005-06-26 07:04:12 UTC
Permalink
Tobias Stening:

[...]
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren. Photoshop hat angeblich auch Filter als
Vorverarbeitungsschritte beim Skalieren. Wenn die Größe sich kaum
ändern soll, läuft man allerdings Gefahr, die Bildqualität unnötig
verringert zu haben. Ist also mit Vorsicht zu genießen.

- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält. Als letzten Schritt dann auf diese Zielgröße
skalieren. In Deinem Fall also erst auf 864x1152, dann auf 600x800.

Beide Ansätze verlangsamen naturgemäß die Ausführung.

Ansonsten ist JAI einen Versuch wert. Angeblich arbeitet das teilweise
mit optimiertem plattformabhängigen Code für wichtige Operationen. Auf
die Schnelle finde ich allerdings nur einen Thread der
Java2D-Mailingliste, in dem ein qualitativ hochwertiges aber langsames
Ergebnis gefunden wird:
<http://forum.java.sun.com/thread.jspa?threadID=611545&messageID=3367104>.

[...]

Gruß,
Marco
--
Bitte nur in der Newsgroup antworten, nicht per Email!
Meine Java-Seiten: http://schmidt.devlib.org/java/
FAQ: http://www.faqs.org/faqs/de/comp-lang-java/faq/
de.comp.lang.java Homepage: http://www.dclj.de/
Tobias Stening
2005-06-26 10:00:51 UTC
Permalink
Post by Marco Schmidt
[...]
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren. Photoshop hat angeblich auch Filter als
Vorverarbeitungsschritte beim Skalieren. Wenn die Größe sich kaum
ändern soll, läuft man allerdings Gefahr, die Bildqualität unnötig
verringert zu haben. Ist also mit Vorsicht zu genießen.
Das müsste ich mir mal ansehen, weil ich jetzt spontan nicht weiss, wie
und wo ich nen Filter herbekomme und wie man den auf ein Image anwendet.
Post by Marco Schmidt
- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält. Als letzten Schritt dann auf diese Zielgröße
skalieren. In Deinem Fall also erst auf 864x1152, dann auf 600x800.
Habe ich erfolgreich durchgespielt. Die Ergebnisse werden deutlich
besser. Bin noch einen Schritt weiter gegangen und lasse immer nur um
25% verkleinern. Dauert zwar etwas länger, liefert aber nochmals
verbesserte Qualität.
Post by Marco Schmidt
Beide Ansätze verlangsamen naturgemäß die Ausführung.
Erstaunlicherweise wurde der Vorgang trotz mehrer Durchgänge sogar etwas
schneller, als mit einer direkten Skalierung auf die Zielgröße.
Post by Marco Schmidt
Ansonsten ist JAI einen Versuch wert. Angeblich arbeitet das teilweise
mit optimiertem plattformabhängigen Code für wichtige Operationen. Auf
die Schnelle finde ich allerdings nur einen Thread der
Java2D-Mailingliste, in dem ein qualitativ hochwertiges aber langsames
<http://forum.java.sun.com/thread.jspa?threadID=611545&messageID=3367104>.
Werde ich mir wohl nicht mehr ansehen, da ich mit der aktuellen Version
jetzt recht zufrieden bin.

Viele Grüße,
Tobias
Peter Büttner
2005-06-26 12:55:53 UTC
Permalink
Post by Tobias Stening
Post by Marco Schmidt
[...]
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren. Photoshop hat angeblich auch Filter als
Vorverarbeitungsschritte beim Skalieren. Wenn die Größe sich kaum
ändern soll, läuft man allerdings Gefahr, die Bildqualität unnötig
verringert zu haben. Ist also mit Vorsicht zu genießen.
Das müsste ich mir mal ansehen, weil ich jetzt spontan nicht weiss, wie
und wo ich nen Filter herbekomme und wie man den auf ein Image anwendet.
Es gibt bestimmt noch bessere links als die:
<http://java.sun.com/docs/books/tutorial/2d/>
<http://java.sun.com/docs/books/tutorial/2d/images/filtering.html>


Auf deiner Platte ist auch was wo paar Filter verwendet werden:
%jdk%\demo\jfc\Java2D

Wenn's reicht ist gut, ansonsten gibt es bestimmt haufenweise fertiges
Zeugs im Großpack.
Post by Tobias Stening
Post by Marco Schmidt
- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält. Als letzten Schritt dann auf diese Zielgröße
skalieren. In Deinem Fall also erst auf 864x1152, dann auf 600x800.
Habe ich erfolgreich durchgespielt. Die Ergebnisse werden deutlich
besser. Bin noch einen Schritt weiter gegangen und lasse immer nur um
25% verkleinern. Dauert zwar etwas länger, liefert aber nochmals
verbesserte Qualität.
Post by Marco Schmidt
Beide Ansätze verlangsamen naturgemäß die Ausführung.
Erstaunlicherweise wurde der Vorgang trotz mehrer Durchgänge sogar etwas
schneller, als mit einer direkten Skalierung auf die Zielgröße.
zum einen Überrascht es mich das es besser wird, zum anderen das es
schneller ist. Vielleicht ist da irgendwo eine Optimierung eingebaut
wenn die Pixel gerade so aufgehen, z.B. integer vs. float arithmetik?
Müsste man mal in die quellen gucken.
Post by Tobias Stening
Post by Marco Schmidt
Ansonsten ist JAI einen Versuch wert. Angeblich arbeitet das teilweise
mit optimiertem plattformabhängigen Code für wichtige Operationen. Auf
die Schnelle finde ich allerdings nur einen Thread der
Java2D-Mailingliste, in dem ein qualitativ hochwertiges aber langsames
<http://forum.java.sun.com/thread.jspa?threadID=611545&messageID=3367104>.
In dem link steht auch das pure java etwas schneller als
'plattform optimiert' sei. Sowas muß man natürlich mit Vorsicht
sehen, es könnten auch andere Algorithmen sein.





Grüße
Peter
--
Shell&Jar : Individual icons for jars
jMineSweeper : extended
www.PeterBuettner.de
Tobias Stening
2005-06-26 15:21:21 UTC
Permalink
Post by Peter Büttner
Post by Tobias Stening
Das müsste ich mir mal ansehen, weil ich jetzt spontan nicht weiss, wie
und wo ich nen Filter herbekomme und wie man den auf ein Image anwendet.
<http://java.sun.com/docs/books/tutorial/2d/>
<http://java.sun.com/docs/books/tutorial/2d/images/filtering.html>
Dankeschön. Das werde ich mir mal ansehen.
Post by Peter Büttner
Post by Tobias Stening
Post by Marco Schmidt
Beide Ansätze verlangsamen naturgemäß die Ausführung.
Erstaunlicherweise wurde der Vorgang trotz mehrer Durchgänge sogar etwas
schneller, als mit einer direkten Skalierung auf die Zielgröße.
zum einen Überrascht es mich das es besser wird, zum anderen das es
schneller ist. Vielleicht ist da irgendwo eine Optimierung eingebaut
wenn die Pixel gerade so aufgehen, z.B. integer vs. float arithmetik?
Müsste man mal in die quellen gucken.
Der Geschwindigkeitsvorteil hat sich in Luft aufgelöst. Nachdem ich
Eclipse neu gestartet hatte, sehen die Ergebnisse (10 Testbilder) nun so
aus:
Direkter Durchlauf: 20 Sekunden
Zwei Durchgänge: 24 Sekunden
Vier Durchgänge: 33 Sekunden

Und zum Vergleich der Qualität hier nochmal zwei Beispiele (1 Durchgang
<-> 5 Dürchgänge) im PNG-Format (ohne weitergehende Filter):

http://www.cmaxx.de/temp/test2.html

Man sieht v.a. an den Kanten der Querbalken die Treppen im linken Bild.
Die sind im rechten Bild so gut wie nicht vorhanden.

Als nächstes werde ich dann mal mit einigen Filtern experimentieren, da
mir das skalierte Bild doch etwas weichgezeichnet scheint.

Viele Grüße,
Tobias
Wanja Gayk
2005-06-26 20:18:17 UTC
Permalink
Marco Schmidt said...
Post by Marco Schmidt
[...]
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren.
Ich neige eher dazu ein Ild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Post by Marco Schmidt
- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält.
Begründung?

Gruß,
-Wanja-
--
"Gewisse Schriftsteller sagen von ihren Werken immer: 'Mein Buch, mein
Kommentar, meine Geschichte'. [..] Es wäre besser, wenn sie sagten:
'unser Buch, unser Kommentar, unsere Geschichte'; wenn man bedenkt, dass
das Gute darin mehr von anderen ist als von ihnen." [Blaise Pascal]
Sven Köhler
2005-06-26 21:09:08 UTC
Permalink
Post by Wanja Gayk
Post by Marco Schmidt
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren.
Ich neige eher dazu ein Ild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Wie bitte? Das ist komplett verkehrt. Bevor man ein Bild verkleinern
kann, muss man einen Tiefpassfilter darüber laufen lassen, damit beim
verkleinern keine Aliasing-Effekte auftreten.

Erklären kann man es am besten an Audio-Daten:
Wenn du eine 44.1kHz Audio-Datei hast, dann können in dieser Datei
maximal Frequenzen bis zu 22kHz gespeichert sein. Bevor du diese Datei
z.B. in eine 10kHz-Datei umwandelst, musst du alle Frequenzen > 5kHz
rauskicken, da diese in einer 10kHz nicht darstellbar sind und beim
runtersamplen Aliasing-Effekte erzeugen würden.

AFAIK ist beim JDK _keine_ korrekte Implementierung dabei, die beim
Runterskalieren entsprechende Tiefpassfilter anwendet. Verkleinerte
Bilder sehen daher sehr kantig/pixelig/rauschig aus.

Lediglich das Rausskalieren ist mit dem Tools vom JDK machbar, denn zum
Raufskalieren braucht man fast nur Interpolation.
Wanja Gayk
2005-06-26 21:52:30 UTC
Permalink
Sven Köhler said...
Post by Sven Köhler
Post by Marco Schmidt
Post by Tobias Stening
Hat noch jemand Ideen? Eigentlich will ich nur einen Haufen Bilder
automatisch skalieren lassen und zwar einigermaßen flott und in guter
Qualität.
- Zuerst einen Blur- oder Median-Filter anwenden, dann
runterskalieren.
Ich neige eher dazu ein Bild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Wie bitte? Das ist komplett verkehrt.
Ansichtssache, oder nennen wir es "Geschmackssache", oder nennen wir es
eine Unzulänglichkeit an dem Skaling-Algorithmus von PSP, ich kann das
nicht genau definieren.
Beim Herunterskalieren werden dort oft feinere Linien einfach
verschluckt - das liegt in der Natur der Sache. Wenn ich das Bild vorher
schärfe verbleiben sie aber stärker im verkleinerten Bild. Ich bevorzuge
diese Art der Optik.

Gruß,
-Wanja-
--
"Gewisse Schriftsteller sagen von ihren Werken immer: 'Mein Buch, mein
Kommentar, meine Geschichte'. [..] Es wäre besser, wenn sie sagten:
'unser Buch, unser Kommentar, unsere Geschichte'; wenn man bedenkt, dass
das Gute darin mehr von anderen ist als von ihnen." [Blaise Pascal]
Marco Schmidt
2005-06-27 04:42:59 UTC
Permalink
Post by Wanja Gayk
Ich neige eher dazu ein Ild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Aber damit führst Du doch Artefakte in das Bild ein, die beim
Skalieren dann zu Verfälschungen führen können.
Post by Wanja Gayk
Post by Marco Schmidt
- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält.
Begründung?
Dabei entstehen weniger "harte" Kanten, siehe auch
<http://www.imagecommunications.de/tutorials/scaling_in_ps.html>.
Verwendet man bilineares oder bikubisches Filtern beim Skalieren (was
üblicherweise der Fall ist), führt das mehrfache Skalieren vermutlich
zu einem ähnlichen Effekt wie der Verwischen-Filter, es wird immer
ordentlich "gemittelt" zwischen den Ausgangspixeln und im Zielbild
landen weniger häßliche Artefakte.

Ich würde jetzt eigentlich in Google Groups stöbern, u. a. in
<news:sci.image.processing>, habe aber wenig Zeit. Auf Anhieb finde
ich <news:***@news.ne.mediaone.net> /
<http://groups.google.es/group/sci.image.processing/browse_frm/thread/29434f1617c3b33e/052b685bf9fc72e6>.

Gruß,
Marco
--
Bitte nur in der Newsgroup antworten, nicht per Email!
Meine Java-Seiten: http://schmidt.devlib.org/java/
FAQ: http://www.faqs.org/faqs/de/comp-lang-java/faq/
de.comp.lang.java Homepage: http://www.dclj.de/
Wanja Gayk
2005-06-27 09:19:09 UTC
Permalink
Marco Schmidt said...
Post by Marco Schmidt
Post by Wanja Gayk
Ich neige eher dazu ein Ild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Aber damit führst Du doch Artefakte in das Bild ein, die beim
Skalieren dann zu Verfälschungen führen können.
Ich sehe das ganz pragmatisch: wenn mir das Resultat mit Artefakten
besser gefällt, ziehe es dem ohne vor :-)

[Weichzeichner]
Post by Marco Schmidt
Post by Wanja Gayk
Begründung?
Dabei entstehen weniger "harte" Kanten, siehe auch
<http://www.imagecommunications.de/tutorials/scaling_in_ps.html>.
Mag sein, in manchen Bildern (nehmen wir z.B. mal eine Wiese, Haare oder
oder Schotter, wie in einem der genannten Beispiele) Wünsche ich mir
allerdings dass die Struktur nicht so stark verloren geht, sprich: dort
wünsche ich mir persönlich etwas härtere Kanten, ich ziehe dann ggf eine
verfälschte, aber deutlich strukturiertere Darstellung vor. Wenn sich
dann eine oder andere "Treppe" ergibt, wo ich sie nicht haben will, kann
ich dort immernoch mit nem Weichzeichner nachziehen.

Gruß,
-Wanja-
--
"Gewisse Schriftsteller sagen von ihren Werken immer: 'Mein Buch, mein
Kommentar, meine Geschichte'. [..] Es wäre besser, wenn sie sagten:
'unser Buch, unser Kommentar, unsere Geschichte'; wenn man bedenkt, dass
das Gute darin mehr von anderen ist als von ihnen." [Blaise Pascal]
Sven Köhler
2005-06-28 00:30:09 UTC
Permalink
Post by Marco Schmidt
Post by Wanja Gayk
Ich neige eher dazu ein Ild vorher zu schärfen, damit das
herunterskalierte Bild nicht so verwaschen aussieht.
Aber damit führst Du doch Artefakte in das Bild ein, die beim
Skalieren dann zu Verfälschungen führen können.
Ein "Schärfe-Filter" ist die Umkehrung eines Tiefpassfilters. Er
verstärkt also die hohen Frequenzen im Bild. Allerdings werden die hohen
Frequenzen beim ordentlichen Verkleinern sowieso aus dem Bild entfernt.
Er fügt dem Bild also Informationen hinzu, die sowieso wieder entfernt
werden - na ja, sie würden entfernt, wenn exakt gerechnet würde und wenn
solche Filter nicht immer Bereiche hätten, in denen Sie Signale eben
nicht zu 100% Filtern oder zu 100% durchlassen.

Dummerweise fügt das ganze Rumrechnen den Daten im unteren
Frequentspektrum mehr schaden zu als das es nützt. Ich will nicht sagen,
dass es nicht den Effekt hat, den Wanja beschrieben hat, aber das ganze
würde ich nicht zur Nachahmung empfehlen. Vielmehr sollte man statt dem
AreaAveragingScaleFilter den Image.getScaledInstance() benutzt, einen
richtigen ordentlich Filter implementieren mit Tiefpass und allem. Dann
landet man recht zielstrebig bei PhotoShop-Qualität.

AreaAveraging hört sich jedenfalls nicht nach einem Ordentlichen System an.
Post by Marco Schmidt
Post by Wanja Gayk
Post by Marco Schmidt
- In mehreren Schritten jeweils auf die Hälfte skalieren, zunächst auf
50%, dann auf 25%, u.s.w., solange man noch größere Bilder als die
Zielgröße erhält.
Begründung?
Dabei entstehen weniger "harte" Kanten, siehe auch
<http://www.imagecommunications.de/tutorials/scaling_in_ps.html>.
Verwendet man bilineares oder bikubisches Filtern beim Skalieren (was
üblicherweise der Fall ist), führt das mehrfache Skalieren vermutlich
zu einem ähnlichen Effekt wie der Verwischen-Filter, es wird immer
ordentlich "gemittelt" zwischen den Ausgangspixeln und im Zielbild
landen weniger häßliche Artefakte.
Vor allem beim Verkleinern auf 50% sollte man nicht zwischen Pixeln
mitteln. Hier bietet sich ein Tiefpassfilter grade zu an. Ein solcher
Tiefpassfilter mit 6 Koeffizienten bezieht übrigens in die Berechnung
eines Pixels des neuen Bilds 36 Pixel mit ein (vertikal und horizontal 6).

Das mitteln zwischen Pixeln ist übrigens auch ein Tiefpassfilter, nur
ein fürchterlich schlechter, da er grade mal 2 Koeffizienten besitzt.
Tobias Stening
2005-06-28 11:40:02 UTC
Permalink
Post by Sven Köhler
Vielmehr sollte man statt dem
AreaAveragingScaleFilter den Image.getScaledInstance() benutzt, einen
richtigen ordentlich Filter implementieren mit Tiefpass und allem. Dann
landet man recht zielstrebig bei PhotoShop-Qualität.
Also sollte man sich einfach mal ein gutes Buch besorgen und die dort
beschriebenen Algorithmen mit Java umsetzen. Wäre sicherlich eine schöne
Hobbyaufgabe. Andererseits wollte ich ja nur "Bilder skalieren" und zwar
mit wenig Aufwand! :-)

Im Endeffekt bin ich auf einen Mangel gestoßen, der eigentlich keiner
ist. Durch die riesige Klassenbibliothek von Java ist man daran gewöhnt,
so ziemlich alles vorgefertigt zu finden. Die Frage ist dann immer nur,
wie die Qualität der Umsetzung ist? Und die könnte in diesem Fall besser
sein.

Man ist so verwöhnt, dass man garnicht mehr davon ausgeht, selber etwas
implementieren zu müssen.

Gruss, Tobias
Sven Köhler
2005-06-28 18:57:48 UTC
Permalink
Post by Tobias Stening
Post by Sven Köhler
Vielmehr sollte man statt dem
AreaAveragingScaleFilter den Image.getScaledInstance() benutzt, einen
richtigen ordentlich Filter implementieren mit Tiefpass und allem. Dann
landet man recht zielstrebig bei PhotoShop-Qualität.
Also sollte man sich einfach mal ein gutes Buch besorgen und die dort
beschriebenen Algorithmen mit Java umsetzen. Wäre sicherlich eine schöne
Hobbyaufgabe. Andererseits wollte ich ja nur "Bilder skalieren" und zwar
mit wenig Aufwand! :-)
Im Endeffekt bin ich auf einen Mangel gestoßen, der eigentlich keiner
ist. Durch die riesige Klassenbibliothek von Java ist man daran gewöhnt,
so ziemlich alles vorgefertigt zu finden. Die Frage ist dann immer nur,
wie die Qualität der Umsetzung ist? Und die könnte in diesem Fall besser
sein.
Man ist so verwöhnt, dass man garnicht mehr davon ausgeht, selber etwas
implementieren zu müssen.
getScaledInstance aufgerufen mit Image.SCALE_SMOOTH ist wohl die beste
Wahl. AFAIk wird das in JDK 1.4 und 1.5 zwar mit AreaAveraging
umgesetzt, aber die Qualität ist annehmbar.

Allerdings finde ich es _sehr_ komisch, dass die Methode
getScaledInstance lediglich ein Image zurück gibt. Ich brauchte in
meinem Fall nunmal ein BufferedImage, und ich bin letzendlich daran
gescheitert, den AreaAveraging dazu zu bewegen, seine Resultate in ein
BufferedImage zu schreiben.
Tobias Stening
2005-06-28 20:39:04 UTC
Permalink
Post by Sven Köhler
getScaledInstance aufgerufen mit Image.SCALE_SMOOTH ist wohl die beste
Wahl. AFAIk wird das in JDK 1.4 und 1.5 zwar mit AreaAveraging
umgesetzt, aber die Qualität ist annehmbar.
Allerdings finde ich es _sehr_ komisch, dass die Methode
getScaledInstance lediglich ein Image zurück gibt. Ich brauchte in
meinem Fall nunmal ein BufferedImage, und ich bin letzendlich daran
gescheitert, den AreaAveraging dazu zu bewegen, seine Resultate in ein
BufferedImage zu schreiben.
Nachdem Du von getScaledInstance() ein Image zurückbekommen hast,
erzeugst Du Dir ein BufferedImage,,von dem Du Dir den Graphics-Kontext
holst. In den malst Du dann Dein Image hinein.

Image scaledImage =
origImage.getScaledInstance(-1, 600, Image.SCALE_SMOOTH);
BufferedImage image = new BufferedImage(
width,
height,
BufferedImage.TYPE_INT_RGB);
Graphics2D graphics2D = image.createGraphics();
graphics2D.setRenderingHint(
RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
graphics2D.drawImage(scaledImage, 0, 0, width, height, null);

Dauert zwar teilweise recht lang, aber ist wohl die einzige Möglichkeit,
ein Image wieder in ein BufferedImage zu bekommen.

Gruss, Tobias
Loading...