Быстрое преобразование перспективы в Java Advanced Imaging API - PullRequest
3 голосов
/ 23 марта 2010

Для нужд моей программы я создал средство искажения изображения и размещения его на карте (моя программа - это программа на основе карты).

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

Проблема в том, что с AffineTransforms вы можете выполнять только самые базовые преобразования.Вы можете переводить, вращать, масштабировать и искажать изображение.Этого достаточно для большинства случаев, но недавно я хотел реализовать 4-точечное преобразование, аналогичное бесплатному преобразованию в Photoshop.

Я провел некоторое исследование и обнаружил преобразование перспективы JAI, которое с помощью WarpPerspective позволяет достичь того, чего я хочу,У меня изначально была одна проблема с прозрачностью результирующего фона преобразованного изображения, но я также нашел решение этой проблемы.Вот код, который у меня есть:

package com.hampton.utils;

import java.awt.Dimension;
import java.awt.RenderingHints;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.awt.image.ColorModel;
import java.awt.image.DataBuffer;
import java.awt.image.SampleModel;
import java.awt.image.renderable.ParameterBlock;

import javax.media.jai.ImageLayout;
import javax.media.jai.Interpolation;
import javax.media.jai.JAI;
import javax.media.jai.PerspectiveTransform;
import javax.media.jai.PlanarImage;
import javax.media.jai.RasterFactory;
import javax.media.jai.RenderedOp;
import javax.media.jai.WarpPerspective;
import javax.media.jai.operator.CompositeDescriptor;

/**
 * @author Savvas Dalkitsis
 */
public class PerspectiveTransformation {


    public static PlanarImage getPrespective(PlanarImage img) {

        int numBands = img.getSampleModel().getNumBands();

        ParameterBlock pb = new ParameterBlock();
        pb.add(new Float(img.getWidth())).add(new Float(img.getHeight()));
        pb.add(new Byte[]{new Byte((byte)0xFF)});
        RenderedOp alpha = JAI.create("constant", pb);


        pb = new ParameterBlock();
        pb.addSource(img).addSource(img);
        pb.add(alpha).add(alpha).add(Boolean.FALSE);
        pb.add(CompositeDescriptor.DESTINATION_ALPHA_LAST);
        SampleModel sm =
            RasterFactory.createComponentSampleModel(img.getSampleModel(),
                                                     DataBuffer.TYPE_BYTE,
                                                     img.getTileWidth(),
                                                     img.getTileHeight(),
                                                     numBands + 1);
        ColorSpace cs =
            ColorSpace.getInstance(numBands == 1 ?
                                   ColorSpace.CS_GRAY : ColorSpace.CS_sRGB);
        ColorModel cm =
            RasterFactory.createComponentColorModel(DataBuffer.TYPE_BYTE,
                                                    cs, true, false,
                                                    Transparency.BITMASK);
        ImageLayout il = new ImageLayout();
        il.setSampleModel(sm).setColorModel(cm);
        RenderingHints rh = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, il);
        RenderedOp srca = JAI.create("composite", pb, rh);


        Dimension d = new Dimension(img.getWidth(),img.getHeight());
        PerspectiveTransform p =  PerspectiveTransform.getQuadToQuad(0, 0, d.width, 0, d.width, d.height, 0, d.height, 100, 0, 300, 0, d.width, d.height, 0, d.height);
        WarpPerspective wp = new WarpPerspective(p);

        pb = (new ParameterBlock()).addSource(srca);
        pb.add(wp);
        pb.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC));

        PlanarImage i = (PlanarImage)JAI.create("warp",pb);
        return i;
    }

}

Это работает (я для простоты жестко закодировал преобразование, позже я включу его в свою систему преобразования только на этот раз, вместо этого я буду использовать 4 очка)из 3).

Проблема, с которой я столкнулся, заключается в том, что до сих пор с моим старым методом все, что мне нужно было сделать, это сохранить AffineTransform (который отображает изображение на карту) и просто выполнить g2.drawImage (imgтрансформируй) и все было хорошо.Это было действительно быстро, и это работало как очарование.Моя проблема сейчас заключается в том, что создание преобразованного PlanarImage занимает много времени (2-3 секунды) и, следовательно, бесполезно для использования в реальном времени.Я знаю, что могу просто сохранить преобразованное изображение, а затем нарисовать то, что будет действительно быстрым, но причина, по которой я этого хочу, заключается в том, что в моем механизме преобразования из 3 точек я предоставляю представление о результирующем преобразовании в реальном времени.Когда пользователь перетаскивает каждую из точек, он сразу видит полученное изображение.

Мой вопрос: есть ли быстрый способ использовать WarpPerspectives в Graphics2D?Я ищу что-то похожее на метод Graphics2D draw (Image, AffineTransform).Или, если у вас есть сторонняя библиотека преобразования изображений, которая работает очень быстро, это также приветствуется.

1 Ответ

2 голосов
/ 25 марта 2010

Попробуйте отключить бикубическую интерполяцию - это должно сэкономить вам время, но это приведет к снижению качества результатов.

До того, как 3D-ускорение стало широко распространенным, игры использовали умные приемы для рисования изображений в перспективе. Википедия имеет отличную статью, подробно объясняющую это. Мне неизвестна библиотека на основе Java, использующая эти концепции, но вы могли бы реализовать версию аффинного отображения довольно легко - просто разбейте исходное изображение на несколько треугольников и отобразите каждый треугольник с помощью другого аффинного преобразования.

Если вы хотите действительно плавный, правильный, сглаженный предварительный просмотр, я бы предложил использовать 3D-библиотеку, такую ​​как Java3D или JOGL.

...