猿问

建立一个匹配3点变换的AffineTransform对象

我知道仿射变换前后 3 个点(p0、p1、p2)的位置(X 和 Y)。我想构建匹配此转换的 AffineTransformation 对象。换句话说,我想找到将已知点 p0、p1、p2 移动到它们已知目的地的仿射变换。


这是我到目前为止所做的:


package image_transformation;


import java.awt.geom.AffineTransform;

import java.awt.image.AffineTransformOp;

import java.awt.image.BufferedImage;

import java.io.File;

import java.io.IOException;


import javax.imageio.ImageIO;


import math.Vector2d;


public class ImageTransformation {


    public static void main(String[] args) throws IOException {


        // the position of the points before the transformation

        Vector2d[] src = new Vector2d[] {

                new Vector2d(486, 191),

                new Vector2d(456, 565),

                new Vector2d(149, 353)

        };


        // the position of the points after the transformation

        Vector2d[] dest = new Vector2d[] {

                new Vector2d(0, 0),

                new Vector2d(0, 600),

                new Vector2d(600, 600)

        };


        // the transformation that we are building

        AffineTransform at = new AffineTransform();


        // the translation to move the p0 to its destination

        Vector2d translationVec = dest[0].sub(src[0]);

        at.translate(translationVec.x, translationVec.y);


        // the rotation around p0 (it will not move) to align p0, p1 and p1's destination

        Vector2d vec0 = src[1].sub(src[0]);

        Vector2d vec1 = dest[1].sub(dest[0]);

        double angle = orientedAngle(vec0, vec1);

        at.rotate(angle, src[0].x, src[0].y);

    }


Vector2d 类做一些关于向量的基本数学运算,它的每个方法都通过它们的名称(sub[stract]、mult[iply]、length、normalize 等)不言自明。


我不知道如何终止这个算法。此外,如果已经存在可以完成所有这些操作的方法,我会非常乐意使用它。


至尊宝的传说
浏览 132回答 1
1回答

波斯汪

这至少与Texture deforming密切相关,4分,但我不会说它可以被认为是重复的。你在那里做了很多数学工作。但也许这不是必需的。使用正确的方法,问题本身是相当微不足道的。考虑二维仿射变换的含义:它将一个空间变换到另一个空间。这里的关键点是:矩阵列是将矩阵应用于单位向量的结果现在,当你有 3 个点时,你可以从它们计算向量:double dx1 = p1.getX() - p0.getX();double dy1 = p1.getY() - p0.getY();double dx2 = p2.getX() - p0.getX();double dy2 = p2.getY() - p0.getY();然后您可以简单地将这些值插入AffineTransform. 最后一列AffineTransform包含由 给出的翻译p0。结果是AffineTransform将点 (0,0)、(1,0) 和 (0,1) 分别转换为点p0、p1和p2。当您反转此变换时,它会将点p0、p1和转换p2为点 (0,0)、(1,0) 和 (0,1)。所以你所要做的就是创建将源点转换为单位向量的变换创建将单位向量转换为目标点的变换将两者连接起来伪代码 (!) 真的很简单    AffineTransform unitToSrc = computeTransform(src[0], src[1], src[2]);    AffineTransform unitToDst = computeTransform(dst[0], dst[1], dst[2]);    AffineTransform at = new AffineTransform();    at.concatenate(unitToDst);    at.concatenate(unitToSrc.inverted());整个事情都在这里实现,作为 MCVE。红色点是“源”点,绿色点是“目的地”点。你可以用鼠标拖动它们:蓝色圆圈表示将变换应用于源点的结果,您可以看到它们最终到达了所需的目标位置。实际计算是通过computeTransform方法完成的。请注意,这是基于java.awt.geom.Point2D类(而不是Vector2d您省略的类)实现的,但这应该很容易更改:点或矢量类唯一使用的是 x/y 坐标。除此之外,实现中根本不涉及(自定义)数学。唯一的数学是反转仿射变换,但有一个内置的功能。import java.awt.BorderLayout;import java.awt.Color;import java.awt.Graphics;import java.awt.Graphics2D;import java.awt.RenderingHints;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.awt.event.MouseMotionListener;import java.awt.geom.AffineTransform;import java.awt.geom.Ellipse2D;import java.awt.geom.NoninvertibleTransformException;import java.awt.geom.Point2D;import java.util.Arrays;import javax.swing.JFrame;import javax.swing.JPanel;import javax.swing.SwingUtilities;public class AffineTransformFromPoints{    public static void main(String[] args)    {        SwingUtilities.invokeLater(() -> createAndShowGUI());    }    private static void createAndShowGUI()    {        JFrame f = new JFrame();        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);        AffineTransformFromPointsPanel panel =             new AffineTransformFromPointsPanel();        f.getContentPane().setLayout(new BorderLayout());        f.getContentPane().add(panel, BorderLayout.CENTER);        f.setSize(1200,900);        f.setLocationRelativeTo(null);        f.setVisible(true);    }}class AffineTransformFromPointsPanel extends JPanel     implements MouseListener, MouseMotionListener{    private Point2D draggedPoint;    // the position of the points before the transformation    Point2D[] src = new Point2D[] {        new Point2D.Double(486, 191),        new Point2D.Double(456, 565),        new Point2D.Double(149, 353)    };    // the position of the points after the transformation    Point2D[] dst = new Point2D[] {        new Point2D.Double(0, 0),        new Point2D.Double(0, 600),        new Point2D.Double(600, 600)    };    public AffineTransformFromPointsPanel()    {        addMouseListener(this);        addMouseMotionListener(this);    }    @Override    protected void paintComponent(Graphics gr)    {        super.paintComponent(gr);        Graphics2D g = (Graphics2D)gr;        g.setColor(Color.WHITE);        g.fillRect(0, 0, getWidth(), getHeight());        g.setRenderingHint(            RenderingHints.KEY_ANTIALIASING,             RenderingHints.VALUE_ANTIALIAS_ON);        g.setColor(Color.RED);        for (Point2D v : src)        {            paint(g, v);        }        g.setColor(Color.GREEN);        for (Point2D v : dst)        {            paint(g, v);        }        g.setColor(Color.BLUE);        AffineTransform at = computeTransform(src, dst);        for (Point2D v : src)        {            draw(g, v, at);        }    }    private static AffineTransform computeTransform(        Point2D src[], Point2D dst[])    {        AffineTransform unitToSrc = computeTransform(src[0], src[1], src[2]);        AffineTransform unitToDst = computeTransform(dst[0], dst[1], dst[2]);        AffineTransform srcToUnit = null;        try        {            srcToUnit = unitToSrc.createInverse();        }        catch (NoninvertibleTransformException e)        {            System.out.println(e.getMessage());            return new AffineTransform();        }        AffineTransform at = new AffineTransform();        at.concatenate(unitToDst);        at.concatenate(srcToUnit);        return at;    }    private static AffineTransform computeTransform(        Point2D p0, Point2D p1, Point2D p2)    {        AffineTransform at = new AffineTransform();        double dx1 = p1.getX() - p0.getX();        double dy1 = p1.getY() - p0.getY();        double dx2 = p2.getX() - p0.getX();        double dy2 = p2.getY() - p0.getY();        at.setTransform(dx1, dy1, dx2, dy2, p0.getX(), p0.getY());        return at;    }    private static void paint(Graphics2D g, Point2D p)    {        double r = 6;        g.fill(new Ellipse2D.Double(            p.getX() - r, p.getY() - r, r + r, r + r));    }    private static void draw(Graphics2D g, Point2D v, AffineTransform at)    {        double r = 8;        Point2D p = new Point2D.Double(v.getX(), v.getY());        at.transform(p, p);        g.draw(new Ellipse2D.Double(            p.getX() - r, p.getY() - r, r + r, r + r));    }    @Override    public void mouseDragged(MouseEvent e)    {        if (draggedPoint != null)        {            draggedPoint.setLocation(e.getPoint());            repaint();        }    }    @Override    public void mousePressed(MouseEvent e)    {        draggedPoint = closest(e.getPoint(), Arrays.asList(src));        if (draggedPoint == null)        {            draggedPoint = closest(e.getPoint(), Arrays.asList(dst));        }    }    private static Point2D closest(        Point2D p, Iterable<? extends Point2D> points)    {        final double threshold = 10;        Point2D closestPoint = null;        double minDistance = Double.MAX_VALUE;        for (Point2D point : points)        {            double dd = point.distance(p);            if (dd < threshold && dd < minDistance)            {                minDistance = dd;                closestPoint = point;            }        }        return closestPoint;    }    @Override    public void mouseReleased(MouseEvent e)    {        draggedPoint = null;    }    @Override    public void mouseMoved(MouseEvent e)    {        // Nothing to do here    }    @Override    public void mouseClicked(MouseEvent e)    {        // Nothing to do here    }    @Override    public void mouseEntered(MouseEvent e)    {        // Nothing to do here    }    @Override    public void mouseExited(MouseEvent e)    {        // Nothing to do here    }}
随时随地看视频慕课网APP

相关分类

Java
我要回答