Graphics2D放置具有特定角坐标的图像

时间:2015-07-20 13:56:28

标签: java graphics2d

我需要将图像放在画布上,角点位于特定坐标上。

// Blank canvas
BufferedImage img = new BufferedImage(2338, 1654, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = img.createGraphics();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setBackground(Color.WHITE);
g2d.clearRect(0, 0, width, EXTRA_HEADER_HEIGHT);

我有4个角坐标,图像角必须放在背景画布上。问题是原始图像可能需要旋转。这基本上就是我需要实现的目标:

enter image description here

我对Graphics2D没有太多经验,但基于对API的快速回顾,我看不到实现这一目标的方法。我希望我在这里错了,有人可以节省我一些时间,但我现在的想法是:

  1. 使用坐标计算放置图像相对于提供图像的旋转。
  2. 将图像的一个角放在正确的位置。
  3. 围绕该角旋转图像(不旋转背景画布)。
  4. 对此有任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

正如tucuxi评论的那样,如果你真的有4个点并希望变换将图像角放置在这些精确的点上,并且仿射变换不会 - 你将需要透视变换。

但是,如果您选择四个中的两个点,则可以执行所需的操作,但可能需要缩放图像。因此,假设您只想放置图像的旋转和缩放版本,使其顶边从A'变为B'。您需要做的是计算仿射变换,其中包括确定旋转角度,缩放因子以及从AB段到A'B'的平移。

这是一个应该做的评论方法。我没有对它进行彻底的测试,但它展示了如何用Java实现该算法。

package stackoverflow;

import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

public class ComputeImageTransform
{
    public static AffineTransform computeTransform(
            Rectangle2D imageBounds, Point2D a2, Point2D b2) {
        double dx = b2.getX() - a2.getX();
        double dy = b2.getY() - a2.getY();

        // compute length of segment
        double length = Math.hypot(dx, dy);

        // compute scaling factor from image width to segment length
        double scaling = length / imageBounds.getWidth();
        // compute rotation angle
        double rotation = Math.atan2(dy, dx);

        // build the corresponding transform
        // NOTE: the order of the individual transformations are applied is the
        // reverse of the order in which the transform will apply them!
        AffineTransform transform = new AffineTransform();
        transform.translate(a2.getX(), a2.getY());
        transform.rotate(rotation);
        transform.scale(scaling, scaling);
        transform.translate(-imageBounds.getX(), -imageBounds.getY());

        return transform;
    }

    public static void main(String[] args) {
        // transform top edge of image within this axis-aligned rectangle...
        double imageX = 20;
        double imageY = 30;
        double imageWidth = 400;
        double imageHeight = 300;

        Rectangle2D imageBounds = new Rectangle2D.Double(
                imageX, imageY, imageWidth, imageHeight);

        // to the line segment a2-b2:
        Point2D a2 = new Point2D.Double(100, 30);
        Point2D b2 = new Point2D.Double(120, 200);

        System.out.println("Transform image bounds " + imageBounds);
        System.out.println("  to top edge " + a2 + ", " + b2 + ":");

        AffineTransform transform = computeTransform(imageBounds, a2, b2);

        // test
        Point2D corner = new Point2D.Double();
        corner.setLocation(imageX, imageY);
        System.out.println("top left:     " + transform.transform(corner, null));

        corner.setLocation(imageX + imageWidth, imageY);
        System.out.println("top right:    " + transform.transform(corner, null));

        corner.setLocation(imageX, imageY + imageHeight);
        System.out.println("bottom left:  " + transform.transform(corner, null));

        corner.setLocation(imageX + imageWidth, imageY + imageHeight);
        System.out.println("bottom right: " + transform.transform(corner, null));
    }
}

这是输出:

Transform image bounds java.awt.geom.Rectangle2D$Double[x=20.0,y=30.0,w=400.0,h=300.0]
  to top edge Point2D.Double[100.0, 30.0], Point2D.Double[120.0, 200.0]:
top left:     Point2D.Double[100.0, 30.0]
top right:    Point2D.Double[119.99999999999999, 199.99999999999997]
bottom left:  Point2D.Double[-27.49999999999997, 44.999999999999986]
bottom right: Point2D.Double[-7.499999999999986, 214.99999999999997]

如您所见,由于浮点计算的性质,您将得到一些舍入误差。