Java高级图像API中的快速透视变换

Java高级图像API中的快速透视变换,java,graphics,image-manipulation,transform,jai,Java,Graphics,Image Manipulation,Transform,Jai,为了我的程序的需要,我创建了一个工具来扭曲图像并将其放置在地图上(我的程序是基于地图的程序) 我写了我自己的放置和扭曲图像的机制,使用放置在图像上的三个点,放置在地图上的三个点,然后我简单地创建一个仿射变换,将第一个三角形变换为第二个三角形,实际上,将图像准确放置在我想要的位置,并进行转换以满足用户的需要 问题是,使用仿射变换,您只能执行最基本的变换。您可以平移、旋转、缩放和倾斜图像。这对于大多数情况来说已经足够了,但我最近想实现一个类似于Photoshop的自由变换的4点变换 我做了一些研究,

为了我的程序的需要,我创建了一个工具来扭曲图像并将其放置在地图上(我的程序是基于地图的程序)

我写了我自己的放置和扭曲图像的机制,使用放置在图像上的三个点,放置在地图上的三个点,然后我简单地创建一个仿射变换,将第一个三角形变换为第二个三角形,实际上,将图像准确放置在我想要的位置,并进行转换以满足用户的需要

问题是,使用仿射变换,您只能执行最基本的变换。您可以平移、旋转、缩放和倾斜图像。这对于大多数情况来说已经足够了,但我最近想实现一个类似于Photoshop的自由变换的4点变换

我做了一些研究,发现了JAI的透视变换,借助透视图,我可以实现我想要的。我最初有一个问题,就是转换后的图像的背景是透明的,但我也找到了一个解决方案。这是我的代码:

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点)

我的问题是,到目前为止,使用我的旧方法,我所要做的只是存储一个仿射变换(将图像映射到贴图),然后简单地执行g2.drawImage(img,transform),一切都很好。它真的很快,而且很有魅力。我现在的问题是,创建转换后的平面图像需要很多时间(2-3秒),因此对于实时使用来说没有用处。我知道我可以简单地保存转换后的图像,然后画出速度非常快的图像,但我想要这样做的原因是,在我的3点转换机制中,我提供了结果转换的实时视图。当用户拖动每个点时,他立即看到生成的图像


那么,我的问题是,是否有一种在Graphics2D中使用透视图的快速方法?我要找的是类似于Graphics2D draw(图像,仿射变换)方法的东西。或者,如果您有一个执行速度非常快的第三方图像转换库,也会受到欢迎。

尝试关闭双三次插值-这会节省您一些时间,但会产生较低质量的结果

在3D加速普及之前,游戏使用聪明的技巧绘制透视图。有一篇很好的文章详细解释了这一点。我不知道有基于Java的库使用了这些概念,但是您可以很容易地实现仿射映射版本——只需将原始图像分割为几个三角形,并使用不同的仿射变换映射每个三角形


如果您想要真正平滑、正确、抗锯齿的预览,我建议使用Java3D o JOGL这样的3D库。

我想到了基于三角形的方法,但如果你想一想,就会发现这是不正确的……你假设两个三角形可以相互独立地变换,而事实并非如此。。。通过使用Java图像编辑器中的过滤器库,我找到了一种更好的方法……它稍微快一点,但每一步都需要我创建一个额外的缓冲图像。使用>100个三角形的SavvasDalkitsis会更快,但内存猪…@SavvasDalkitsis会给出视觉上正常的结果。