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

2023-12-11

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

我编写了自己的机制,使用放置在图像上的三个点、放置在地图上的三个点来放置和扭曲图像,然后我简单地创建一个 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);


        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 秒),因此对于实时使用来说没有用处。我知道我可以简单地保存变换后的图像,然后绘制图像,这将非常快,但我想要这样做的原因是,在我的 3 点变换机制中,我提供了结果变换的实时视图。当用户拖动每个点时,他会立即看到生成的图像。

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


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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 高级成像 API 中的快速透视变换 的相关文章

随机推荐

  • Google 地图 Android API v2 getVisibleRegion() 返回 0

    我正在使用新的 Google Maps Android API v2 需要检测屏幕视图角落的纬度坐标 我使用 mMap getProjection getVisibleRegion 来执行此操作 第一次加载程序时效果很好 但是如果我离开程序
  • 如何强制实例化 C++ 模板的特定实例?

    见标题 我有一个模板 我想强制实例化模板的特定实例 我该怎么做呢 更具体地说 您可以强制实例化抽象模板类吗 我可能会详细说明 因为我也有同样的问题 就我而言 我正在构建一个库 一些模板实现很大并且包含很多内容 但仅针对几种类型生成 我想在库
  • “您已经拥有此商品”Google Play 应用内错误

    我已经实现了 Google Play 应用内购买的 API 版本 3 我在两台设备上使用同一个 Google 帐户登录 On device 1 我刚刚使用此购买了一件商品 https developer android com google
  • Java - 如果在组合框1中选择了一个值,那么应该在所有其他组合框中禁用它

    你好 我还是java新手 希望学习这个不错的功能 你好 我有 4 个组合盒 它们的内部和内部是相同的 Select Item 1 Item 2 Item 3 Item 4 当我选择时Item 1 on comboBox1 the combo
  • c 中浮动奇怪的不精确错误[重复]

    这个问题在这里已经有答案了 今天发生在我身上的一件奇怪的事情 当我尝试编译和执行这段代码的输出不是我所期望的 下面的代码只是将浮点值添加到浮点数组中 然后将其打印出来 简单的代码 int main float r 10 int z int
  • XML 区分大小写吗?

    简短的问题 XML 区分大小写吗 较长的问题 例如
  • 插件错误:插件 * 与 IntelliJ IDEA 兼容只是因为它没有定义任何显式模块依赖项

    我安装过这样的插件一次 现在出现此错误 我尝试删除与其相关的所有内容 但仍然出现此错误 插件文件夹不包含该插件的文件 插件错误 插件 Google Sceneform Tools Beta 兼容 使用 IntelliJ IDEA 只是因为它
  • Python 中变量和函数的命名约定是什么?

    来自 C 背景的变量和方法的命名约定通常是驼峰命名法或帕斯卡命名法 C example string thisIsMyVariable a public void ThisIsMyMethod 在Python中 我已经看到了上面的内容 但我
  • 通过更改 React-intl 包装器属性切换语言时,我的 redux-form 被重新初始化

    我正在将我的应用程序包装在IntlProvider from react intl v2 像这样
  • 在python中显示jpg图像

    我正在创建一个简单的工具 用于将专辑封面图像添加到 python 中的 mp3 文件中 到目前为止 我只是致力于向亚马逊发送包含艺术家和专辑标题的请求 并获取结果列表 以及查找每个结果的实际图像 我想要做的是显示一个简单的框架 其中每个图像
  • 如何使用 ASP.NET MVC 和 AngularJS 路由?

    我正在开发一个新的 ASP NET MVC 和 AngularJS 应用程序 该应用程序旨在成为 SPA 的集合 我使用 MVC 区域概念来分隔每个单独的 SPA 然后在每个 MVC 区域中使用 AngularJS 来创建 SPA 由于我是
  • 是否可以防止在输出 UTF-8 文件时添加 BOM? (视觉工作室 2005)

    我需要一些帮助 我正在编写一个程序 以 UTF 8 编码打开 2 个不带 BOM 的源文件 第一个包含英文文本和一些其他信息 包括 ID 第二个仅包含字符串 ID 和翻译 该程序通过将第二个文件中的英文字符替换为俄语翻译来更改第一个文件中的
  • 如何解码 Stack Exchange API 响应

    我正在尝试检索堆栈交换 api 的响应 例如 我正在使用以下代码来检索响应 import java io BufferedReader import java io IOException import java io InputStrea
  • Android 2.0 联系人组操作

    我会在 Android 2 O 中操作联系人组 我的代码如下 要获取组列表 带有 id 和标题 final String GROUP PROJECTION new String ContactsContract Groups ID Cont
  • Android 中的语音到文本转换

    您好 我需要在 Android 中进行语音到文本转换的帮助 我已经在谷歌上搜索这个主题一个小时了 我找到的每个帮助都向我展示了如何将文本转换为语音 而不是相反 http android developers blogspot com 200
  • onActivityResult 未在从 ArrayAdapter 扩展的类中调用

    我进行了搜索 但在互联网上找不到有用的答案 这就是我提出质疑的原因 我喜欢加载相机并捕捉图像getView自定义 ArrayAdapter 类的方法 相机已加载并捕获图像 但onActivityResult 从未被调用过 我的代码如下所示
  • 此应用程序与此设备 iOS 不兼容

    When I update my iOS version from 9 3 to 9 3 1 then go to app store to install the app we get popup this app is not comp
  • 如何从 PHP 数组中回显一定数量的元素

    如果我有一个包含 100 个元素的数组 我如何仅回显 显示前 5 个元素 谢谢 See LimitIterator and ArrayIterator array range 1 100 iterator new LimitIterator
  • 如何验证 google openid 响应

    我正在尝试向我的用户添加授权抛出 google openid 我收到了 ID https www google com accounts o8 id id AIt Ew Bo 但我如何检查它是否合法 我的意思是用户可以使用另一个用户的电子邮
  • Java 高级成像 API 中的快速透视变换

    为了满足我的程序的需要 我创建了一个工具来扭曲图像并将其放置在地图上 我的程序是基于地图的程序 我编写了自己的机制 使用放置在图像上的三个点 放置在地图上的三个点来放置和扭曲图像 然后我简单地创建一个 AffineTransform 实际上