当前位置: 首页 > 面试题库 >

Java Advanced Imaging API中的Fast Perspective转换

申屠英韶
2023-03-14
问题内容

为了满足程序的需要,我创建了一种使图像变形并将其放置在地图上的工具(我的程序是基于地图的程序)。

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

问题在于,使用AffineTransforms只能执行最基本的转换。您可以平移,旋转,缩放和倾斜图像。对于大多数情况而言,这已经足够了,但是我最近想实现类似于Photoshop的免费变换的4点变换。

我进行了一些研究,发现了JAI的Perspective转换,借助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,transform),一切都很好。这真的非常快,而且就像一种魅力。我现在的问题是创建转换后的PlanarImage会花费很多时间(2-3秒),因此对于实时使用没有用。我知道我可以简单地保存转换后的图像,然后绘制出非常快的图像,但是我想要这样做的原因是,在我的三点转换机制中,我提供了所产生转换的实时视图。当用户拖动每个点时,他会立即看到生成的图像。

那么我的问题是,是否有一种在Graphics2D中使用WarpPerspectives的快速方法?我正在寻找的是类似于Graphics2D
draw(Image,AffineTransform)方法的东西。或者,如果您具有运行速度非常快的第三方图像转换库,也将受到欢迎。


问题答案:

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

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

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



 类似资料:
  • 和RDD类似,transformation允许从输入DStream来的数据被修改。DStreams支持很多在RDD中可用的transformation算子。一些常用的算子如下所示: Transformation Meaning map(func) 利用函数func处理原DStream的每个元素,返回一个新的DStream flatMap(func) 与map相似,但是每个输入项可用被映射为0个或者

  • 问题内容: 我想知道如何将转换到在Struts2。我有一个简单的表格,其中用户以这种格式提供日期。提交后,将Sturts2映射表单发送到Bean。我在日期转换中出错。我在很多地方都使用Google进行搜索,并指出必须为此使用自定义类型转换器。我不想编写用于日期转换的自定义类型转换器。我认为Struts2中应该有一种简单的数据转换机制,因为数据转换是非常常见的功能。 JSP 这是用户输入输入的JSP

  • 问题内容: 有人可以向我解释一下,编译器在第一次强制转换时不会抱怨,而在第二次强制转换时会抱怨吗? 问题答案: 在和一起使用时,您告诉编译器该对象的类实际上是其声明类型的子类,并且该子类实现。 该班是 最后的 ,所以不可能是一个子类的实例:编译器知道你在说谎。但是不是最终的,所以 可以 是该Implements 的子类型的实例。 如果您使用final,编译器也会抱怨:

  • 问题内容: 有没有免费的Java库,可以将一种编码格式的字符串转换为其他编码格式,例如iconv?我正在使用Java版本1.3。 问题答案: 你不需要标准库以外的库,只需使用Charset即可。(你可以只使用String构造函数和getBytes方法,但就我个人而言,我不喜欢仅使用字符编码的名称。输入错误的空间太大。) 编辑:正如注释中指出的那样,你仍然可以使用Charset实例,但是可以轻松使用

  • 问题内容: 如果我有带签名的元组,则无法将其强制转换为。编译器说: 错误:无法表示元组转换((String,Bool)’到’(String,Any)’ 但这应该可行,因为可以安全地使用它。如果执行类似的操作,几乎会引发相同的错误: 错误: 无法将类型’(Swift.String,Swift.Bool)’的值强制转换为’(protocol <>,protocol <>)) 那么,有什么变通办法,尤其

  • 问题内容: 是否有Java的框架或开源项目可以将视频从任何视频格式转换为任何视频格式。类似于Panda Video Conversion框架。 问题答案: 您是说JMF吗?- ( Java的媒体框架 )检查 这个 出来。

  • 问题内容: 谁能建议一种简单的方法来将日期和时间转换为php中的不同时区? 问题答案: 您可以为此使用datetime对象或其函数别名: 编辑评论 但我无法使用此方法,因为当用户从不同位置登录时,我需要在不同时区显示日期 那不是问题。用户登录后,您将确定其时区并将其设置为DateTime对象,如图所示。我在我的一个项目中使用了类似的方法,它的工作原理很吸引人。 在数据库中,我需要获取任何单个时区中