正方形转梯形

12

我知道将正方形变换成梯形是一种线性变换,可以使用投影矩阵完成,但我有点难以构建这个矩阵。

使用投影矩阵进行平移、缩放、旋转和剪切是简单明了的。是否有一个简单的投影矩阵可以将正方形变换为梯形呢?

3个回答

11

a、b、c、d是2D正方形的四个角落。

a、b、c、d以齐次坐标表示,因此它们是3x1矩阵。

alpha、beta、gamma、delta是2D梯形的四个角落。

alpha、beta、gamma、delta以齐次坐标表示,因此它们是3x1矩阵。

H是您要查找的3x3矩阵,也称为单应性矩阵。

    h1 h2 h3
H = h4 h5 h6
    h7 h8 h9

H将a、b、c、d映射到alpha、beta、gamma、delta中,因此您有以下四个方程式

alpha=H*a
beta=H*b
gamma=H*c
delta=H*d

假设您已知a、b、c、d和alpha、beta、gamma、delta,则可以解决前面四个方程组,求得九个未知数h1、h2、h3、h4、h5、h6、h7、h8、h9。这里我只是描述了一个“原始”的解决方案,原则上可以工作;有关上述方法的详细说明,您可以查看例如此页面http://www.corrmap.com/features/homography_transformation.php,他们放置h9=1(因为H可以用8个参数表示),然后解决一个包含8个未知数的线性方程组中的8个方程。您可以在Elan Dubrofsky的论文第2节Homography Estimation by Elan Dubrofsky中找到类似的说明。另一个解释是David Austin的《使用射影几何矫正相机》2013年3月《美国数学学会特征专栏》
上述方法及其缺点在第二版的《计算机视觉中的多视角几何》一书中的第4章“估计-2D投影变换”中有描述,Richard Hartley和Andrew Zissermann在其中还描述了不同且更好的算法; 您可以检查此链接http://www.cse.iitd.ac.in/~suban/vision/geometry/node24.html,该链接似乎遵循同一本书。
您可以在书籍Simon J.D. Prince的计算机视觉:模型,学习和推断的第15.1.4节“投影变换模型”中找到关于单应性的另一个解释。他的算法手册中概述了算法15.4:投影变换(单应性)的最大似然学习:通过非线性最小化来解决问题。

实际尝试后,我得到了一组无法解决的方程。这个答案似乎支持这一点——一个梯形不能通过线性变换从矩形中制作出来。 - Marijn
@Marijn 你好,你的输入数据是什么? - Alessandro Jacopson
在简单情况下,我想将位于(0, 0)和(1, 1)之间的矩形转换为梯形(0, 0)(0, 1)(1, A)(1, B),因此A和B是输入参数。如果我解决了这个问题,我会得到B = A + 1,即结果矩阵只会产生平行四边形。起初,我还尝试将左侧(X=0)点的Y作为参数,但这导致了一个无法解决的系统——虽然可能是我在化简方程时犯了错误(我对这些东西没有太多实践经验)。 - Marijn
1
感谢澄清。我试图创建一个3×3矩阵,用于CSS变换规则。据我所见,这种技术不适用于那里。 - Marijn
@Marijn 你也可以看看David Austin在http://www.ams.org/samplings/feature-column/fc-2013-03上的“使用投影几何矫正相机”一文。 - Alessandro Jacopson
显示剩余2条评论

3

0

最小依赖的Java实现

对于那些知识和时间有限,寻求快速且可靠解决方案的人们,Wii-interact项目中提供了一个工作良好且相当可靠的Java实现。

转换过程在单应性源文件中。它归结为构建和解决矩阵:

/**
* Please note that Dr. John Zelle assisted us in developing the code to
* handle the matrices involved in solving for the homography mapping.
* 
**/
Matrix A = new Matrix(new double[][]{
                {x1, y1, 1, 0,  0,  0, -xp1*x1, -xp1*y1},
                {0,  0,  0, x1, y1, 1, -yp1*x1, -yp1*y1},
                {x2, y2, 1, 0,  0,  0, -xp2*x2, -xp2*y2},
                {0,  0,  0, x2, y2, 1, -yp2*x2, -yp2*y2},
                {x3, y3, 1, 0,  0,  0, -xp3*x3, -xp3*y3},
                {0,  0,  0, x3, y3, 1, -yp3*x3, -yp3*y3},
                {x4, y4, 1, 0,  0,  0, -xp4*x4, -xp4*y4},
                {0,  0,  0, x4, y4, 1, -yp4*x4, -yp4*y4}
        });

        Matrix XP = new Matrix(new double[][]
                          {{xp1}, {yp1}, {xp2}, {yp2}, {xp3}, {yp3}, {xp4}, {yp4}});
        Matrix P = A.solve(XP);
        transformation = new Matrix(new double[][]{
                {P.get(0, 0), P.get(1, 0), P.get(2,0)},
                {P.get(3, 0), P.get(4, 0), P.get(5,0)},
                {P.get(6, 0), P.get(7, 0), 1}
        });

用法:以下方法执行最终转换:

public Point2D.Double transform(Point2D.Double point) {
    Matrix p = new Matrix(new double[][]{{point.getX()}, {point.getY()}, {1}});
    Matrix result = transformation.times(p);
    double z = result.get(2, 0);
    return new Point2D.Double(result.get(0, 0) / z, result.get(1, 0) / z);
}

Matrix 类的依赖来自于 JAMA:Java 矩阵包

许可证

  1. Wii-interact GNU GPL v3
  2. JAMA 公共领域

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接