2011-02-11 3 views
5

Вот оригинальное изображение: http://rank.my/public/images/uploaded/orig-4193395691714613396.pngПочему это изображение выглядит так плохо после сокращения на Java?

И вот он масштабируется до 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; 
} 

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

+1

@MusiGenesis: Я думаю, что ваш ответ удален отличный, и я хочу, чтобы ты его восстановить , –

+0

Ссылки мертвы, пожалуйста, принимайте imgur или аналогичные :) – alex

+0

Ссылки сейчас резервные копии - извините – sanity

ответ

5

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

3

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

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

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

+0

Ссылка today.java.net выглядит довольно хорошо для меня, особенно раздел «Создание масштабированных экземпляров» и образец «getScaledInstance (...)». – msandiford

2

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()); 

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

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

+0

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

+0

, что потеряло ссылку на форумы Sun, не может ли это быть: https://forums.oracle.com/forums/thread.jspa?threadID=1270119? Этот поток начинается с _ «Кажется, это самая простая вещь в JAI (или любом графическом API, если на то пошло), но дает мне головную боль. Задача: уменьшить изображение с лучшим качеством. Результат: JAI имеет низкую производительность по сравнению к стандартным приложениям, таким как GIMP ... »_ Затем он продолжается с помощью« RenderingHints KEY_RENDERING, VALUE_RENDER_QUALITY »и с« MemoryCacheSeekableStream »и заканчивается предложением использовать« ImageReadParam setSourceRegion, setSourceSubsampling » – gnat

Смежные вопросы