代码之家  ›  专栏  ›  技术社区  ›  Will

将四边形图像提取为矩形

  •  14
  • Will  · 技术社区  · 14 年前

    赏金更新

    下面是 denis的 link,这是如何使用 threeblindmiceandamonkey code:。

    目标rect是我们的“in”四元 int dw=300,dh=250; 双进[4][4]=0,0,dw,0,dw,dh,0,dh //源图像中的四元是“out” 双出[4][5]=171,72,331,93,333188,177210 双人型[3][6]; const int ret=mapquadtoquad(in、out、homo); //homo可用于计算任意目的点的x,y //在源中,例如 对于(int i=0;i<4;i++){ 双p1[3]=出[i][0],出[i][7],1 双P2〔3〕; 变换矩阵(p1,p2,homo); p2[0]/=p2[2];/x p2[1]/=p2[2];/Y printf(“\t%2.2f\t%2.2f\n”,p2[0],p2[1]); } < /代码>

    这为将目的地中的点转换为源提供了一种转换——当然,您可以用另一种方式进行转换,但对于混合来说,这样做是很整洁的:

    for(int y=0;y<dh;y++){
    对于(int x=0;x<dw;x++){
    //计算源中的四个角
    //目标像素,并混合
    < /代码> 
    
    

    对于混合,我正在使用super sampling和random points;它工作得很好,即使在源和目标区域存在很大的差异时也是如此。


    background question

    在顶部的图片中,货车侧面的标志不是面向摄像机的。我想尽我所能地用我拥有的像素来计算它在脸上的样子。

    我知道图像中四边形的角坐标,以及目标矩形的大小。

    我想象这是一个通过x和y轴的循环,在两个维度上同时做一条Bresenham的线,在源图像和目标图像中有某种像素混合-某种亚像素混合?

    有哪些方法,以及如何混合像素?

    有没有一个标准的方法?

    赏金更新

    跟随Denis's链接,这是如何使用threeblindmiceandamonkey代码:

    // the destination rect is our 'in' quad
    int dw = 300, dh = 250;
    double in[4][4] = {{0,0},{dw,0},{dw,dh},{0,dh}};
        // the quad in the source image is our 'out'
    double out[4][5] = {{171,72},{331,93},{333,188},{177,210}};
    double homo[3][6];
    const int ret = mapQuadToQuad(in,out,homo);
        // homo can be used for calculating the x,y of any destination point
    // in the source, e.g.
    for(int i=0; i<4; i++) {
        double p1[3] = {out[i][0],out[i][7],1};
        double p2[3];
        transformMatrix(p1,p2,homo);
        p2[0] /= p2[2]; // x
        p2[1] /= p2[2]; // y
        printf("\t%2.2f\t%2.2f\n",p2[0],p2[1]);
    }
    

    这为将目的地中的点转换为源提供了一种转换——当然,您可以用另一种方式进行转换,但对于混合来说,这样做是很整洁的:

    for(int y=0; y<dh; y++) {
        for(int x=0; x<dw; x++) {
            // calc the four corners in source for this
            // destination pixel, and mix
    

    为了混合,我用super-sampling使用随机点;即使在源区域和目标区域存在很大的差异,它也能很好地工作。


    背景问题

    在顶部的图片中,货车侧面的标志不是面向摄像机的。我想尽我所能地用我拥有的像素来计算它的表面效果。

    我知道图像中四边形的角坐标,以及目标矩形的大小。

    我想象这是一个通过x和y轴的循环,在两个维度上同时做一条Bresenham的线,在源图像和目标图像重叠的情况下,有某种像素混合-某种亚像素混合?

    有哪些方法,以及如何混合像素?

    有没有一个标准的方法?

    3 回复  |  直到 14 年前
        1
  •  5
  •   denis    14 年前

    查找 “Quad to Quad”transform ,例如 threeblindmiceandamonkey
    二维齐次坐标上的3x3变换可以变换任意4个点(四元) 任何其他四合院; 相反,任何FromQuad和ToQuad,例如卡车的角落和目标矩形, 进行3 x 3变换。

    qt有 quadtoquad 可以用它来转换像素地图,但我猜你没有qt?< BR> 新增10Jun: 从 labs.trolletech.com/page/graphics/examples 有一个很好的演示,当你移动角落的时候,哪个四到四个像素地图:

    6月11日补充道:@will,这是python中的translate.h(你知道吗? “”..“”是多行注释。)
    perstrans() is the key;hope that makes sense,if not ask.

    顺便说一下,您可以一个一个地映射像素,mapquadtoquad(target rect,orig quad), 但是如果没有像素插值,它看起来会很糟糕;opencv可以做到这一切。

    <预先> <代码>!/usr/bin/env蟒蛇 “方形-方形地图 从http://threeblindmiceandamonkey.com/?P=16矩阵H “” 来自未来进口部 将numpy导入为np _日期:2010-06-11 Jun Denis 定义DET2(A、B、C、D): 返回A*D-B*C def mapsquaretoquad(四元):[4][2] sq=np.零((3,3)) px=四元[0,0]-四元[1,0]+四元[2,0]-四元[3,0] py=四元[0,1]-四元[1,1]+四元[2,1]-四元[3,1] 如果abs(px)<1e-10和abs(py)<1e-10: sq[0,0]=四元[1,0]-四元[0,0] sq[1,0]=四元[2,0]-四元[1,0] sq[2,0]=四元[0,0] sq[0,1]=四元[1,1]-四元[0,1] sq[1,1]=四元[2,1]-四元[1,1] sq[2,1]=四元[0,1] Sq[0,2]=0。 Sq[1,2]=0。 Sq[2,2]=1。 返回平方 其他: dx1=四元[1,0]-四元[2,0] dx2=四元[3,0]-四元[2,0] Dy1=四元[1,1]-四元[2,1] DY2=四元[3,1]-四元[2,1] Det=Det2(dx1,dx2,dy1,dy2) 如果DET=0: 无返回 sq[0,2]=det2(px,dx2,py,dy2)/det sq[1,2]=det2(dx1,px,dy1,py)/det Sq[2,2]=1。 sq[0,0]=四元[1,0]-四元[0,0]+sq[0,2]*四元[1,0] sq[1,0]=四元[3,0]-四元[0,0]+sq[1,2]*四元[3,0] sq[2,0]=四元[0,0] sq[0,1]=四元[1,1]-四元[0,1]+sq[0,2]*四元[1,1] sq[1,1]=四元[3,1]-四元[0,1]+sq[1,2]*四元[3,1] sq[2,1]=四元[0,1] 返回平方 #……………………………………………………………………… 定义映射四边形(四边形): 返回np.linalg.inv(mapsquaretoquad(quad))。 def mapquadtoquad(A、B): 返回np.dot(mapquartosquare(a),mapsquaretoquad(b)) def perstrans(x,t)表示: 透视变换x nx2,t 3x3: [X0 Y0 1]t=[A0 B0 W0]->[A0/W0 B0/W0] [x1 y1]t=[a1 b1 w1]->[a1/w1 b1/w1] … “” x1=np.vstack((x.t,np.ones(len(x))) Y=np.dot(t.t,x1) 返回(y[:-1]/y[-1]).t #……………………………………………………………………… 如果“名称”, np.设置“打印选项”(2,阈值=100,抑制=真)。2f sq=np.数组([[0,0]、[1,0]、[1,1]、[0,1]) Quad=np.数组([[171,72],[331,93],[333,188],[177,210]) 打印“四格:”,四格 打印“方形到方形:”,Perstrans(sq,mapsqaretoquad(quad))。 打印“Quad to Square:”,Perstrans(Quad,MapQuadtoSquare(Quad))。 dw,dh=300,250 rect=np.数组([[0,0],[dw,0],[dw,dh],[0,dh]]) QuadQuad=MapQuadToQuad(Quad,Rect) 打印“四边形到四边形转换:”,四边形 打印“Quad to Rect:”,PerTrans(Quad,QuadQuad) “” 四轮:【171 72】 〔331 93〕 〔333 188〕 〔177 210〕 四方形:【171.72。 〔331〕。93。 〔333〕。188。 〔177〕。210。] 四方形:[-0.0。 〔1〕。0。 〔1〕。1。 〔0〕。1。] 四到四转换:【1.29-0.23-0】。] [-0.06 1.79-0.] [-217.24-88.54 1.34]] 四元到矩形:[[0.0。 〔300〕。0。 〔300〕。250。 〔0〕。250。] “” < /代码> g. threeblindmiceandamonkey .
    二维齐次坐标上的3x3变换可以变换任意4个点(四元) 任何其他四合院; 相反,任何FromQuad和ToQuad,例如卡车的角落和目标矩形, 进行3 x 3变换。

    QT有 quadToQuad 可以用它转换像素地图,但我猜你没有qt?
    新增10Jun: 从 labs.trolltech.com/page/Graphics/Examples 有一个很好的演示,当你移动角落的时候,哪个四到四个像素地图:

    alt text

    6月11日补充道:@will,这是python中的translate.h(你知道吗? “”..“”是多行注释。)
    perstrans() 是关键;如果不问的话,希望这是有意义的。

    顺便说一下,你 能够 逐个映射像素,mapquadtoquad(target rect,orig quad), 但是如果没有像素插值,它看起来会很糟糕;OpenCV可以做到这一切。

    #!/usr/bin/env python
    """ square <-> quad maps
        from http://threeblindmiceandamonkey.com/?p=16 matrix.h
    """
    
    from __future__ import division
    import numpy as np
    
    __date__ = "2010-06-11 jun denis"
    
    def det2(a, b, c, d):
        return a*d - b*c
    
    def mapSquareToQuad( quad ):  # [4][2]
        SQ = np.zeros((3,3))
        px = quad[0,0] - quad[1,0] + quad[2,0] - quad[3,0]
        py = quad[0,1] - quad[1,1] + quad[2,1] - quad[3,1]
        if abs(px) < 1e-10 and abs(py) < 1e-10:
            SQ[0,0] = quad[1,0] - quad[0,0]
            SQ[1,0] = quad[2,0] - quad[1,0]
            SQ[2,0] = quad[0,0]
            SQ[0,1] = quad[1,1] - quad[0,1]
            SQ[1,1] = quad[2,1] - quad[1,1]
            SQ[2,1] = quad[0,1]
            SQ[0,2] = 0.
            SQ[1,2] = 0.
            SQ[2,2] = 1.
            return SQ
        else:
            dx1 = quad[1,0] - quad[2,0]
            dx2 = quad[3,0] - quad[2,0]
            dy1 = quad[1,1] - quad[2,1]
            dy2 = quad[3,1] - quad[2,1]
            det = det2(dx1,dx2, dy1,dy2)
            if det == 0.:
                return None
            SQ[0,2] = det2(px,dx2, py,dy2) / det
            SQ[1,2] = det2(dx1,px, dy1,py) / det
            SQ[2,2] = 1.
            SQ[0,0] = quad[1,0] - quad[0,0] + SQ[0,2]*quad[1,0]
            SQ[1,0] = quad[3,0] - quad[0,0] + SQ[1,2]*quad[3,0]
            SQ[2,0] = quad[0,0]
            SQ[0,1] = quad[1,1] - quad[0,1] + SQ[0,2]*quad[1,1]
            SQ[1,1] = quad[3,1] - quad[0,1] + SQ[1,2]*quad[3,1]
            SQ[2,1] = quad[0,1]
            return SQ
    
    #...............................................................................
    def mapQuadToSquare( quad ):
        return np.linalg.inv( mapSquareToQuad( quad ))
    
    def mapQuadToQuad( a, b ):
        return np.dot( mapQuadToSquare(a), mapSquareToQuad(b) )
    
    def perstrans( X, t ):
        """ perspective transform X Nx2, t 3x3:
            [x0 y0 1] t = [a0 b0 w0] -> [a0/w0 b0/w0]
            [x1 y1 1] t = [a1 b1 w1] -> [a1/w1 b1/w1]
            ...
        """
        x1 = np.vstack(( X.T, np.ones(len(X)) ))
        y = np.dot( t.T, x1 )
        return (y[:-1] / y[-1]) .T
    
    #...............................................................................
    if __name__ == "__main__":
        np.set_printoptions( 2, threshold=100, suppress=True )  # .2f
    
        sq = np.array([[0,0], [1,0], [1,1], [0,1]])
        quad = np.array([[171, 72], [331, 93], [333, 188], [177, 210]])
        print "quad:", quad
        print "square to quad:", perstrans( sq, mapSquareToQuad(quad) )
        print "quad to square:", perstrans( quad, mapQuadToSquare(quad) )
    
        dw, dh = 300, 250
        rect = np.array([[0, 0], [dw, 0], [dw, dh], [0, dh]])
        quadquad = mapQuadToQuad( quad, rect )
        print "quad to quad transform:", quadquad
        print "quad to rect:", perstrans( quad, quadquad )
    """
    quad: [[171  72]
     [331  93]
     [333 188]
     [177 210]]
    square to quad: [[ 171.   72.]
     [ 331.   93.]
     [ 333.  188.]
     [ 177.  210.]]
    quad to square: [[-0.  0.]
     [ 1.  0.]
     [ 1.  1.]
     [ 0.  1.]]
    quad to quad transform: [[   1.29   -0.23   -0.  ]
     [  -0.06    1.79   -0.  ]
     [-217.24  -88.54    1.34]]
    quad to rect: [[   0.    0.]
     [ 300.    0.]
     [ 300.  250.]
     [   0.  250.]]
    """
    
        2
  •  14
  •   tzaman    14 年前

    你想要的是平面矫正,恐怕也不是那么简单。您需要做的是恢复将厢式货车侧的倾斜视图映射到前向视图上的 homography photoshop/etc.有工具为你提供一些控制点;如果你想自己实现它,你就必须开始钻研计算机视觉。

    edit -好的,现在开始:一个python脚本来进行扭曲,使用opencv opencv library,它有方便的函数来计算同形并扭曲图像:

    导入cv 定义扭曲图像(图像、角点、目标): mat=cv.createmat(3,3,cv.cv f) 获取透视变换(角、目标、垫子) out=cv.createmat(高度、宽度、cv.cv uc3) cv.翘曲透视图(图像,外,材质,cv.cv_内立方) 退回 如果“名称”= 宽,高=400,250 角=[(171,72),(331,93),(333188),(177210)] 目标=[(0,0),(宽度,0),(宽度,高度),(0,高度)] image=cv.loadImagem('fries.jpg') out=扭曲图像(图像、角点、目标) cv.saveimage(“fries_-warped.jpg”,out) < /代码>

    输出:

    opencv还具有C和C++绑定,或者您可以使用.AHEFF=“HTTP://www. EMGU.COM/WIKI/NETX.PHP/MIN页”Re=“NoeFror”> EngCuv 用于.Net包装器;API在所有语言中都是相当一致的,因此您可以用任何一种语言适合您的想象来复制它。

    恐怕不是那么简单。你需要做的是恢复 homography 这将货车侧面的倾斜视图映射到正面视图上。photoshop/etc.有工具为你提供一些控制点;如果你想自己实现它,你就必须开始钻研计算机视觉。

    编辑 -好了,现在开始:使用python脚本进行扭曲,使用 OpenCV 具有方便计算同形和扭曲图像功能的库:

    import cv
    
    def warpImage(image, corners, target):
        mat = cv.CreateMat(3, 3, cv.CV_32F)
        cv.GetPerspectiveTransform(corners, target, mat)
        out = cv.CreateMat(height, width, cv.CV_8UC3)
        cv.WarpPerspective(image, out, mat, cv.CV_INTER_CUBIC)
        return out
    
    if __name__ == '__main__':
        width, height = 400, 250
        corners = [(171,72),(331,93),(333,188),(177,210)]
        target = [(0,0),(width,0),(width,height),(0,height)]
        image = cv.LoadImageM('fries.jpg')
        out = warpImage(image, corners, target)
        cv.SaveImage('fries_warped.jpg', out)
    

    输出:
    Warped image

    OpenCV也有C和C++绑定,或者你可以使用 EmguCV 对于.NET包装器,API在所有语言中都是相当一致的,因此您可以用任何适合自己的语言来复制它。

        3
  •  0
  •   Andy West    14 年前

    我想你需要的是 affine transformation 这可以用矩阵数学来完成。