为了我的程序的需要,我创建了一个工具来扭曲图像并将其放置在地图上(我的程序是基于地图的程序)。
我编写了自己的机制来放置和扭曲图像,使用放置在图像上的三个点,放置在地图上的三个点,然后我简单地创建一个 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) 方法的东西。或者,如果您有一个执行速度非常快的第三方图像转换库,那也将受到欢迎。