2010-11-18 18 views
7

Muszę przeskalować obraz za pomocą Java JAI. W chwili obecnie używam następujący kod:Skalowanie obrazów za pomocą Java JAI

private static RenderedOp scale(RenderedOp image, float scale) { 
    ParameterBlock scaleParams = new ParameterBlock(); 
    scaleParams.addSource(image); 
    scaleParams.add(scale).add(scale).add(0.0f).add(0.0f); 
    scaleParams.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC_2)); 

    // Quality related hints when scaling the image 
    RenderingHints scalingHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); 
    scalingHints.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY); 
    scalingHints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 
    scalingHints.put(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY); 
    scalingHints.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); 
    scalingHints.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); 
    scalingHints.put(JAI.KEY_BORDER_EXTENDER, BorderExtender.createInstance(BorderExtender.BORDER_COPY)); 

    return JAI.create("scale", scaleParams, scalingHints); 
} 

Niestety, prowadzi to do bardzo złe wyniki, zwłaszcza dlatego, że często muszą skalować obrazy ze współczynnikiem skali mniejszej niż 0,5 ...

Any Rada?

+0

Ta linia wygląda podejrzane skalaParams.add (skala) .add (skala) .add (0.0f) .add (0.0f); – whatnick

+0

Niektóre przykładowe wyniki, które ilustrują, co masz na myśli przez złe, pomogą również w zidentyfikowaniu rodzaju artefaktu, którego doświadczasz. – whatnick

+0

Jakieś powody, by nie używać 'AffineTransformOp'? Zobacz także http://stackoverflow.com/questions/4216635 – trashgod

Odpowiedz

15

Zgaduję, że próbujesz przeskalować większy obraz w dół do rozmiaru miniatur lub jakiejś równie dużej różnicy od oryginału do skalowanego obrazu?

Jeśli-tak, ten temat był rzeczywiście adresowany przez Chrisa Campbella z Java2D w 2007 roku (nie spodziewam się, że o tym wiesz, po prostu wskazując, że jest to częste pytanie), ponieważ nowe podejście skalowania Java2D (RenderingHints.VALUE_INTERPOLATION_ *) nie zapewniał odpowiednika przyjętego wówczas podejścia Image.getScaledInstance(SCALE_AREA_AVERAGING or SCALE_SMOOTH).

Okazuje się, że podejście SCALE_AREA_AVERAGING lub SCALE_SMOOTH w starym podejściu Image.getScaledInstance w wersji Java 1.1 było dość kosztowną, wieloetapową operacją, która wymagała dużo pracy w tle, aby wygenerować ładnie wyglądający obraz.

Chris zwrócił uwagę, że nowy i "poprawny" sposób, za pomocą Java2D, aby uzyskać ten sam wynik, to przyrostowy proces skalowania obrazu w połowie i na wskroś, aż do uzyskania pożądanego rozmiaru obrazu, najlepiej przy użyciu wyższej wartości. Skala jakości, taka jak RenderHints.VALUE_INTERPOLATION_BICUBIC lub BILINEAR.

Rezultat jest prawie identyczny z oryginalnym podejściem Image.getScaledInstance, którego ludzie chcą.

Właściwie polowałem na tę odpowiedź kilka miesięcy temu, pisząc usługę hostingu obrazów i byłem zaskoczony, jak skomplikowane jest proste pytanie "Jak zrobić ładną miniaturę w Javie?" stał się.

W końcu utworzę małą bibliotekę Java (Apache 2, open sourced), która implementuje 3 różne podejścia do skalowania obrazu w Javie przy użyciu "najlepszych praktyk", w tym podejścia przyrostowego, które zasugerował Chris. Ta biblioteka nazywa się imgscalr. Można pobrać i używać go tak proste, jak:

BufferedImage thumbnail = Scalr.resize(srcImage, 150); 

Istnieje więcej opcji do ustawienia i użytkowania (np Quality lub Szybkość skalowania), ale po wyjęciu z pudełka są inteligentne domyślne dla wszystko zrobić ładny szukam skalowanego obrazu, więc nie musisz się martwić o więcej, jeśli nie chcesz. Biblioteka dokłada również wszelkich starań, aby pozbyć się i uniknąć przydzielania obiektów, która nie jest absolutnie niezbędna, i natychmiast usuwać instancje BufferedImage, jeśli nie jest to potrzebne - ma to być kod jako część długo działającej aplikacji serwera, więc to było krytyczny.

Zrobiłem już kilka wydań biblioteki, a jeśli wolisz po prostu wyrwać "dobre rzeczy" i samemu coś z tym zrobić, idź do tego. Wszystko jest na poziomie GitHub i żadna z nich nie jest ściśle tajna, tylko próbą ułatwienia życia ludziom.

Nadzieję, że pomaga.

+0

Ta biblioteka brzmi bardzo intrygująco. Uwielbiam pisać/motywować, moje wczesne przykłady zadziałały dobrze. Nie przyjęliśmy go (jeszcze) do czasu dalszej analizy. –

+0

@MichaelEaster Cieszę się, że słyszę jak do tej pory; Czekam na wszelkie dodatkowe informacje zwrotne! –

3

Osiągnąłem dobre wyniki z Thumbnailator. Nie wiem, co powinien zrobić JAI.KEY_BORDER_EXTENDER, ale przypuszczam, że reszta funkcjonalności (antyaliasing, dithering, itp.) Jest obsługiwana. Używałem go do generowania szarości miniatury dość dużych czarnych i białych obrazów

1

Jeśli masz szczęście i masz tylko czarny & białych obrazów, a następnie można użyć bardzo szybką i dobrą pracę Jakość: SubsampleBinaryToGray