Java高级图像API中的快速透视变换
为了我的程序的需要,我创建了一个工具来扭曲图像并将其放置在地图上(我的程序是基于地图的程序) 我写了我自己的放置和扭曲图像的机制,使用放置在图像上的三个点,放置在地图上的三个点,然后我简单地创建一个仿射变换,将第一个三角形变换为第二个三角形,实际上,将图像准确放置在我想要的位置,并进行转换以满足用户的需要 问题是,使用仿射变换,您只能执行最基本的变换。您可以平移、旋转、缩放和倾斜图像。这对于大多数情况来说已经足够了,但我最近想实现一个类似于Photoshop的自由变换的4点变换 我做了一些研究,发现了JAI的透视变换,借助透视图,我可以实现我想要的。我最初有一个问题,就是转换后的图像的背景是透明的,但我也找到了一个解决方案。这是我的代码:Java高级图像API中的快速透视变换,java,graphics,image-manipulation,transform,jai,Java,Graphics,Image Manipulation,Transform,Jai,为了我的程序的需要,我创建了一个工具来扭曲图像并将其放置在地图上(我的程序是基于地图的程序) 我写了我自己的放置和扭曲图像的机制,使用放置在图像上的三个点,放置在地图上的三个点,然后我简单地创建一个仿射变换,将第一个三角形变换为第二个三角形,实际上,将图像准确放置在我想要的位置,并进行转换以满足用户的需要 问题是,使用仿射变换,您只能执行最基本的变换。您可以平移、旋转、缩放和倾斜图像。这对于大多数情况来说已经足够了,但我最近想实现一个类似于Photoshop的自由变换的4点变换 我做了一些研究,
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会给出视觉上正常的结果。