14

嗨,我正在尝试创建仿射变换,这将允许我将三角形转换为另一个三角形。我所拥有的是 2 个三角形的坐标。你能帮助我吗?

根据 Adam Rosenfield 的回答,我想出了这段代码,以防有人厌倦了自己求解方程:

public static AffineTransform createTransform(ThreePointSystem source,
            ThreePointSystem dest) {        
    double x11 = source.point1.getX();
    double x12 = source.point1.getY();
    double x21 = source.point2.getX();
    double x22 = source.point2.getY();
    double x31 = source.point3.getX();
    double x32 = source.point3.getY();
    double y11 = dest.point1.getX();
    double y12 = dest.point1.getY();
    double y21 = dest.point2.getX();
    double y22 = dest.point2.getY();
    double y31 = dest.point3.getX();
    double y32 = dest.point3.getY();

    double a1 = ((y11-y21)*(x12-x32)-(y11-y31)*(x12-x22))/
                ((x11-x21)*(x12-x32)-(x11-x31)*(x12-x22));
    double a2 = ((y11-y21)*(x11-x31)-(y11-y31)*(x11-x21))/
                ((x12-x22)*(x11-x31)-(x12-x32)*(x11-x21));
    double a3 = y11-a1*x11-a2*x12;
    double a4 = ((y12-y22)*(x12-x32)-(y12-y32)*(x12-x22))/
                ((x11-x21)*(x12-x32)-(x11-x31)*(x12-x22));
    double a5 = ((y12-y22)*(x11-x31)-(y12-y32)*(x11-x21))/
                ((x12-x22)*(x11-x31)-(x12-x32)*(x11-x21));
    double a6 = y12-a4*x11-a5*x12;
    return new AffineTransform(a1, a4, a2, a5, a3, a6);
}
4

4 回答 4

14

我假设您在这里谈论的是 2D。仿射变换矩阵有 9 个值:

    | a1 a2 a3 |
一个 = | a4 a5 a6 |
    | a7 a8 a9 |

有 3 个输入顶点x1, x2, 和x3, 变换后应变为y1, y2, y3。但是,由于我们在齐次坐标中工作,因此应用Atox1并不一定会给出y1- 它会给出y1. 因此,我们也有未知乘数k1,k2k3, 等式:

A*x1 = k1*y1
A*x2 = k2*y2
A*x3 = k3*y3

每一个都是一个向量,所以我们真的有 12 个未知数的 9 个方程,所以解将是欠约束的。如果我们要求a7=0, a8=0, 和a9=1, 那么解将是唯一的(这个选择很自然,因为这意味着如果输入点是 ( x, y, 1),那么输出点将始终具有齐次坐标 1,因此得到的变换是只是一个 2x2 变换加上一个翻译)。

因此,这将方程简化为:

a1*x11 + a2*x12 + a3 = k1*y11
a4*x11 + a5*x12 + a6 = k1*y12
                   1 = k1
a1*x21 + a2*x22 + a3 = k2*y21
a4*x21 + a5*x22 + a6 = k2*y22
                   1 = k2
a1*x31 + a2*x32 + a3 = k3*y31
a4*x31 + a5*x32​​ + a6 = k3*y32
                   1 = k3

所以,k1= k2= k3= 1。将这些插入并转换为矩阵形式会产生:

| x11 x12 1 0 0 0 | | a1 | | y11 |
| x21 x22 1 0 0 0 | | a2 | | y21 |
| x31 x32 1 0 0 0 | * | a3 | = | y31 |
| 0 0 0 x11 x12 1 | | a4 | | y12 |
| 0 0 0 x21 x22 1 | | a5 | | y22 |
| 0 0 0 x31 x32 1 | | a6 | | y32 |

求解这个 6x6 方程组可以得到仿射变换矩阵A。当且仅当源三角形的 3 个点不共线时,它将有一个独特的解决方案。

于 2009-07-11T18:04:22.167 回答
2

嘿,伙计们,不失一般性,使两个三角形的原点为一个顶点(您可以稍后进行仿射移位),因此它们由点0、a、b、c、d定义,然后乘以您的通过矩阵 NM点x

在哪里

M = inverse( ab ) <--- 这是 2x2 矩阵,以点ab作为其列

N = (光盘)

那应该这样做。

于 2009-07-11T18:10:26.413 回答
1

如果我理解正确的话,你的三角形有相同的大小和角度,所以你应该能够转换它们,使它们(至少)有一个共同点。在此之后,它们应该仅在旋转方面有所不同或可以被镜像,因此您可以获取三角形线之间的角度并尝试这些角度进行旋转,如果没有一个角度可以镜像,则可以镜像其中一个三角形。

编辑:好的,这还不够,仿射变换也可以包含剪切和缩放...缩放可以很容易地完成,只需划分线的长度,这也会为您提供有关三角形对应线的一些信息,但剪切会再难一点……

OTOH,你不能为此求解一些方程系统吗?毕竟应该有一个变换矩阵和3个点(新旧)……

于 2009-07-11T17:59:01.010 回答
1

只需将问题表述为一组方程,然后求解:

P1 * M = P1'
P2 * M = P2'
P3 * M = P3'

M是一个 3x3 矩阵,如:

[m00, m01, m02;
 m10, m11, m12;
 0  ,   0,   1]

并且P_i是一个元组[k*x_i, k*y_i, k](齐次坐标)...

您现在可以尝试扩展上面显示的 3 个矩阵方程并创建一个新系统,使用m_ijas incognits 并解决它,但如果我没有遗漏任何东西(也许我是),您需要多一点来完全指定转换,否则您将拥有额外的自由度(当然您可以修复它)。

于 2009-07-11T18:03:41.047 回答