Java Advanced Imaging API中的快速透视转换 [英] Fast Perspective transform in Java Advanced Imaging API

查看:153
本文介绍了Java Advanced Imaging API中的快速透视转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我用自己的机制来放置和扭曲图像,使用三个放置在图像上的点,三个点放在地图上,然后我简单地做它会创建一个AffineTransform,将第一个三角形转换为第二个三角形,实际上将图像放置在我想要的位置并进行转换,以适合用户需要的内容。

问题是通过AffineTransforms,您只能执行最基本的转换。您可以翻译,旋转,缩放和倾斜图像。这对大多数情况来说已经足够了,但是我最近想要实现类似于Photoshop的自由变换的4点变换。



我做了一些研究,发现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);


尺寸d =新尺寸(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);
返回i;
}

}

为简单起见,后来我将它与我的转换系统结合起来,这次我将用4分而不是3分)。

我有问题到目前为止,用我以前的方法,我所要做的就是存储AffineTransform(将图像映射到地图),并简单地执行g2.drawImage(img,transform),并且都很好。这真的很快,它像一个魅力。我现在的问题是,创建转换后的PlanarImage需要很多时间(2-3秒),因此对实时使用没有用处。我知道我可以简单地保存转换后的图像,然后绘制出真正快速的图像,但我希望这一点的原因是,在我的3点转换机制中,我提供了实时转换结果的视图。当用户拖动每个点时,他立即看到最终的图像。

接下来我的问题是,在Graphics2D中使用WarpPerspectives有没有一种快速方法?我正在寻找的东西类似于Graphics2D绘制(Image,AffineTransform)方法。或者如果你有一个第三方图像转换库,它的执行速度非常快,这也是值得欢迎的。

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



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



如果您想要真正流畅,正确,反锯齿的预览,我会建议使用像Java3D或JOGL这样的3D库。


For the needs of my program I have created a facility to distort an image and place it on a map (my program is a map based program).

I wrote my own mechanism for placing and distorting the image using three points that are placed on the image, three points that are placed on the map and then what I simply do it create an AffineTransform that transforms the first triangle to the second, in effect placing the image exactly where I want it and transformed to fit what the user wanted.

The problem is that with AffineTransforms you can only perform the most basic of transformations. You can translate, rotate, scale and skew your image. This is enough for most cases but I recently wanted to implement a 4 point transform similar to Photoshop's free transform.

I did some research and found JAI's Perspective transform which with the help of a WarpPerspective I can achieve what I want. I initially had one issue with having the resulting background of the transformed image transparent but i found a solution to that as well. This is the code i have:

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;
    }

}

It works (I have hard coded the transformation for the sake of simplicity, later on i will incorporate it with my transformation system only this time i will use 4 points instead of 3).

The problem i have is that so far with my old method all i had to do is store an AffineTransform (that maps the image to the map) and the simply do a g2.drawImage(img,transform) and all was good. It was really fast and it worked like a charm. My problem now is that creating the transformed PlanarImage takes a lot of time (2-3 seconds) and thus is is not useful for real-time use. I know i can simply save the transformed image and then draw that which will be really fast but the reason i want this is that in my 3 point transformation mechanism i provide real time view of the resulting transformation. When the user drags each of the points he immediately sees the resulting image.

My question then is, is there a fast way to use WarpPerspectives in Graphics2D? What I am looking for is something similar to Graphics2D draw(Image,AffineTransform) method. Or if you have a third party image transformation library that performs really fast that would be welcome as well.

解决方案

Try switching off the bicubic interpolation - that should save you some time, but it would produce lower quality results.

Before 3D acceleration became widespread, games used smart tricks for drawing images in perspective. Wikipedia has a great article explaining this in detail. I am not aware of a Java-based library utilizing those concepts, but you could implement the affine-mapping version quite easily - just split the original image into several triangles and map each triangle using a different affine transform.

If you want really smooth, correct, anti-aliased preview, I would suggest using a 3D library like Java3D o JOGL.

这篇关于Java Advanced Imaging API中的快速透视转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆