亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

建立一個匹配3點變換的AffineTransform對象

建立一個匹配3點變換的AffineTransform對象

至尊寶的傳說 2023-06-04 11:23:22
我知道仿射變換前后 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 等)不言自明。我不知道如何終止這個算法。此外,如果已經存在可以完成所有這些操作的方法,我會非常樂意使用它。
查看完整描述

1 回答

?
波斯汪

TA貢獻1811條經驗 獲得超4個贊

這至少與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、p1p2。當您反轉此變換時,它會將點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。紅色點是“源”點,綠色點是“目的地”點。你可以用鼠標拖動它們:

http://img3.sycdn.imooc.com/647c03e00001305202740287.jpg

藍色圓圈表示將變換應用于源點的結果,您可以看到它們最終到達了所需的目標位置。


實際計算是通過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

? ? }


}



查看完整回答
反對 回復 2023-06-04
  • 1 回答
  • 0 關注
  • 169 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號