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 的快速回顾,我看不出实现此目的的方法。我希望我在这里错了,有人可以节省我一些时间,但我目前的想法是:
- 使用坐标计算放置的图像相对于提供的图像的旋转。
- 将图片的一个角放在正确的位置。
- 围绕该角旋转图像(不旋转背景 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]
如您所见,由于浮点计算的性质,您会得到一些舍入误差。
我需要将图像放置到 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 的快速回顾,我看不出实现此目的的方法。我希望我在这里错了,有人可以节省我一些时间,但我目前的想法是:
- 使用坐标计算放置的图像相对于提供的图像的旋转。
- 将图片的一个角放在正确的位置。
- 围绕该角旋转图像(不旋转背景 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]
如您所见,由于浮点计算的性质,您会得到一些舍入误差。