将四边形变成矩形?

11

我有一个由任意四边形组成的场景。我需要能够将该四边形转换为矩形。每个四边形都在2D坐标系中,因此它们有4个顶点(x_i, y_i)

变换需要有一个反演,因为想法是在操作矩形后回到原始四边形。

执行此操作的最简单方法是什么?我听说这被称为透视变换,但我发现了一些小线索,让我认为这可能很容易实现。


这里有另一种实现方法:https://dev59.com/mWox5IYBdhLWcg3wDgEz 如果有帮助,请告诉我。 - MonsieurDart
@MonsieurDart 那个问题/答案是针对IOS特定的。 - Timothy Groote
确实!我的评论只适用于iOS。 - MonsieurDart
3个回答

15

你知道所需矩形的尺寸吗?如果是这样,您可以使用透视变换将任何凸四边形映射到矩形上,并进行可逆转换。您只需要获取4个相应点(在四边形和矩形之间),例如(X1,Y1),(X2,Y2),(X3,Y3),(X4,Y4)用于四边形,对应地(x1,y1),(x2,y2),(x3,y3),(x4,y4)用于矩形。然后将它们插入Borealid's链接中的最终方程式中即可:

alt text

上述方程的解(其中n=4)将给出可逆透视变换矩阵的元素(a、b、c、d、e、...、h)。

alt text

这将使您能够将矩形上的点转换为四边形上的点。要进行反向变换,只需反转变换矩阵即可。
另请注意,一旦获得了转换后坐标的向量[XW YW W],您需要对其进行归一化,使W = 1。即,您的最终答案是[XW/W YW/W W/W],它等于[X Y 1],即所需答案。

1
非常好的答案,谢谢。这是完全正确的。我不知道是否应该将其作为一个新问题提出,但是,就在这里:当我获得透视变换矩阵时,有没有一种方法将此矩阵应用于OpenGL上下文?我尝试过使用glPushMatrix()然后glMultMatrixf(perspectiveTransformationInverse)然后尝试绘制我的四边形,然后glPopMatrix()。然而,这种方法不起作用,您会推荐我做什么? - Goles
由于我从未使用过OpenGL,所以我无法真正推荐任何东西。但是,要转换所有点,您只需将其乘以变换矩阵并进行归一化即可。 - Jacob
我理解,但如果我想在转换后的矩形内绘制一些点,那么是否可以在这些点上应用相同的逆转换将它们带回到原始的非矩形四边形中?还是变换不会应用于这些点?谢谢。 - Goles
你能够用一个3D四边形来完成这个吗? - dwitvliet
1
这是一个用Java/Processing实现的东西,在这里可以找到它的代码。 - bumbu
2
感谢提供这些链接!这对于平滑纹理四边形非常有用。那些图片的页面现在已经无法访问,但是在wayback机器上有一个版本:http://web.archive.org/web/20100327214143/http://alumni.media.mit.edu/~cwren/interpolator - Will

1

并非所有的四边形都是矩形。正因为如此,从四边形到矩形没有可逆变换;存在更多的四边形而不是矩形,因此您无法从四边形到矩形产生可逆映射。

然而,您可以为一个特定的四边形生成可逆变换。正如您所推测的那样,这涉及到旋转视角,使得四边形在您的新坐标空间中“看起来”像一个矩形。请参见https://web.archive.org/web/20100801071311/http://alumni.media.mit.edu/~cwren/interpolator/,其中包含了这个问题的Matlab源代码。


0
这个解决方案使用JAI(Java高级图像)API,所有的魔法都在QuadToQuad方法中。以下是代码示例。
try
     {
      BufferedImage img = UtilImageIO.loadImage(picName);
      ParameterBlock params = new ParameterBlock();
      params.addSource(img); //source is the input image
        int w = img.getWidth(); //Set to the original width of the image
        int h = img.getHeight(); //Set to the original height of image
        Point tl = new Point(x,y); //The new top left corner
        Point tr = new Point((x1,y1); //The new top right corner
        Point bl = new Point(x2,y2); //The new bottom left corner
        Point br = new Point(x3,y3); //The new bottom right corner
        PerspectiveTransform p = PerspectiveTransform.getQuadToQuad(0,0, 0, h, w, h, w, 0, tl.x, tl.y, bl.x, bl.y, br.x, br.y, tr.x, tr.y).createInverse();
        WarpPerspective wa = new WarpPerspective(p);
        params.add(wa);
        params.add(Interpolation.getInstance(Interpolation.INTERP_BICUBIC)); //Change the interpolation if you need more speed
        RenderedOp dest = JAI.create("warp", params); //dest is now the output
        File outputfile = new File(picName);
        ImageIO.write(dest, "jpg", outputfile); 

    }
    catch(Exception e){}

希望这能帮到你。 :)

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