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

Graphics2D placing image with specific corner co-ordinates

我需要将图像放置到 canvas 上,角在特定坐标处。

// 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 个角坐标 canvas。问题是原始图像可能需要旋转。这基本上是我需要实现的目标:

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

  1. 使用坐标计算放置的图像相对于提供的图像的旋转。
  2. 将图片的一个角放在正确的位置。
  3. 围绕该角旋转图像(不旋转背景 canvas)。

如能提供上述任何帮助,我们将不胜感激。

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

但是,如果您 select 四点中的两点,您可以随心所欲,但可能必须缩放图像。因此,假设您只想放置图像的旋转和缩放版本,使其顶部边缘从 A' 到 B'。您需要做的是计算仿射变换,其中包括确定旋转角度、比例因子以及从线段 AB 到 A'B' 的平移。

这是一个应该做到这一点的注释方法。我没有彻底测试它,但它显示了如何在 Java.

中实现算法
package Whosebug;

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]

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