Почему это изображение выглядит так плохо после масштабирования в Java? - PullRequest
5 голосов
/ 11 февраля 2011

Вот исходное изображение: http://rank.my/public/images/uploaded/orig-4193395691714613396.png

И здесь оно уменьшено до 300x225:

http://rank.my/public/images/uploaded/norm-4193395691714613396.png

И здесь оно уменьшено до 150x112:

http://rank.my/public/images/uploaded/small-4193395691714613396.png

Как видите, 300x225 выглядит довольно плохо, а 150x112 выглядит ужасно.Вот код, который я использую для уменьшения изображения:

private static BufferedImage createResizedCopy(final BufferedImage source, final int destWidth,
        final int destHeight) {
    final BufferedImage resized = new BufferedImage(destWidth, destHeight, source.getType());
    final Graphics2D bg = resized.createGraphics();
    bg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
    bg.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
    bg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    final float sx = (float) destWidth / source.getWidth();
    final float sy = (float) destHeight / source.getHeight();
    bg.scale(sx, sy);
    bg.drawImage(source, 0, 0, null);
    bg.dispose();
    return resized;
}

Что я здесь не так делаю?Масштабирование изображения не должно быть особенно быстрым, качество определенно является приоритетом над скоростью.Я использую неправильную технику?

Ответы [ 3 ]

5 голосов
/ 11 февраля 2011

Существует три способа решения проблемы уменьшения масштаба. Во-первых, сделать это в несколько этапов, с сокращением не более 75% на каждом этапе. Второе - размыть изображение перед изменением размера; чем больше он сжимается, тем больше вам придется размыть. Третий способ - использовать метод, который фильтрует с использованием блоков пикселей размером более 2x2–4x4, используемых методом наивной билинейной или бикубической интерполяции. По мере увеличения коэффициента сжатия увеличивается и пиксельный блок, используемый фильтром, в противном случае вы получите артефакты сглаживания, как вы видели здесь.

3 голосов
/ 11 февраля 2011

Я никогда не пользовался этими библиотеками, поэтому чувствую, что не отвечаю, но не могу не передать эти ссылки, которые, по моему мнению, могут оказаться полезными.Надеюсь, это поможет.

http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html

http://www.componenthouse.com/article-20

2 голосов
/ 11 февраля 2011

JAI довольно разочаровывает. Я до сих пор удивляюсь, почему, независимо от того, какие настройки вы делаете, он никогда не соответствует скорости, качеству и простоте ImageMagick . Я предпочитаю использовать ImageMagick везде, где могу.

Приведенный ниже код дает мне лучший результат для масштабирования изображения. Обратите внимание, что я использовал RenderingHints.VALUE_RENDER_QUALITY и SubsampleAverage и , а не RenderingHints.VALUE_INTERPOLATION_BICUBIC.

Я завернул обработку JAI в небольшой блок и всегда использую его для уменьшения. Тот же код не дает хороший результат при масштабировании - для этого применяются другие настройки. Я не пробовал с PNG, JPEG - это то, с чем я работал.

Надеюсь, это поможет

//Set-up and load file
PlanarImage image = JAI.create("fileload", absPath);
RenderingHints quality = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Properties p = new Properties(System.getProperties());
p.put("com.sun.media.jai.disableMediaLib", "true");
System.setProperties(p);

//Setup the processes
ParameterBlock pb = new ParameterBlock()
    .addSource(image)
    .add(scaleX)     //scaleX = (double)1.0*finalX/origX
    .add(scaleY);    //scaleY = (double)1.0*finalY/origY
RenderedOp tempProcessingFile = JAI.create("SubsampleAverage", pb, quality);

//Save the file
FileOutputStream fout = new FileOutputStream(file);
JPEGEncodeParam encodeParam = new JPEGEncodeParam();
encodeParam.setQuality(0.92f); //My experience is anything below 0.92f gives bad result
ImageEncoder encoder = ImageCodec.createImageEncoder("JPEG", fout, encodeParam);
encoder.encode(tempProcessingFile.getAsBufferedImage());

Кроме того, статьи, которые мне помогли.

(ссылки выше из моей закладки, отредактируйте их, если обнаружите, что они мертвы)

...