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

透视变形矩形的比例

  •  43
  • HugoRune  · 技术社区  · 15 年前

    给定一个被透视扭曲的矩形的二维图片:

    enter image description here

    我知道形状原来是一个矩形,但我不知道它的原始大小。

    如果我知道这张图片中角的像素坐标,我如何计算原始比例,即矩形的商(宽度/高度)?

    (背景:目标是自动对矩形文档的照片进行不失真处理,边缘检测可能需要进行Hough变换)

    更新:

    关于是否有可能根据给出的信息确定宽高比,已经有过一些讨论。我幼稚的想法是,这一定是可能的,因为我想不出任何方法来投射,例如,在上面描述的四边形上有一个1:4的矩形。这个比例显然接近1:1,所以应该有一种方法来从数学上确定它。然而,除了我的直觉之外,我没有证据证明这一点。

    我还没有完全理解下面提出的论点,但我认为一定有一些隐含的假设,即我们在这里是不存在的,这是不同的解释。

    然而,经过数小时的搜索,我终于找到了一些与这个问题相关的论文。 我正在努力理解那里使用的数学,到目前为止还没有成功。尤其是第一篇论文似乎正是要讨论我想做什么,不幸的是没有代码示例和非常密集的数学。

    10 回复  |  直到 7 年前
        1
  •  27
  •   HugoRune    15 年前

    这是我看完报纸后想回答的问题

    我在sage中操纵了一段时间的方程式,并用c样式生成了这个伪代码:

    
    // in case it matters: licensed under GPLv2 or later
    // legend:
    // sqr(x)  = x*x
    // sqrt(x) = square root of x
    
    // let m1x,m1y ... m4x,m4y be the (x,y) pixel coordinates
    // of the 4 corners of the detected quadrangle
    // i.e. (m1x, m1y) are the cordinates of the first corner, 
    // (m2x, m2y) of the second corner and so on.
    // let u0, v0 be the pixel coordinates of the principal point of the image
    // for a normal camera this will be the center of the image, 
    // i.e. u0=IMAGEWIDTH/2; v0 =IMAGEHEIGHT/2
    // This assumption does not hold if the image has been cropped asymmetrically
    
    // first, transform the image so the principal point is at (0,0)
    // this makes the following equations much easier
    m1x = m1x - u0;
    m1y = m1y - v0;
    m2x = m2x - u0;
    m2y = m2y - v0;
    m3x = m3x - u0;
    m3y = m3y - v0;
    m4x = m4x - u0;
    m4y = m4y - v0;
    
    
    // temporary variables k2, k3
    double k2 = ((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x) /
                ((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) ;
    
    double k3 = ((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x) / 
                ((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) ;
    
    // f_squared is the focal length of the camera, squared
    // if k2==1 OR k3==1 then this equation is not solvable
    // if the focal length is known, then this equation is not needed
    // in that case assign f_squared= sqr(focal_length)
    double f_squared = 
        -((k3*m3y - m1y)*(k2*m2y - m1y) + (k3*m3x - m1x)*(k2*m2x - m1x)) / 
                          ((k3 - 1)*(k2 - 1)) ;
    
    //The width/height ratio of the original rectangle
    double whRatio = sqrt( 
        (sqr(k2 - 1) + sqr(k2*m2y - m1y)/f_squared + sqr(k2*m2x - m1x)/f_squared) /
        (sqr(k3 - 1) + sqr(k3*m3y - m1y)/f_squared + sqr(k3*m3x - m1x)/f_squared) 
    ) ;
    
    // if k2==1 AND k3==1, then the focal length equation is not solvable 
    // but the focal length is not needed to calculate the ratio.
    // I am still trying to figure out under which circumstances k2 and k3 become 1
    // but it seems to be when the rectangle is not distorted by perspective, 
    // i.e. viewed straight on. Then the equation is obvious:
    if (k2==1 && k3==1) whRatio = sqrt( 
        (sqr(m2y-m1y) + sqr(m2x-m1x)) / 
        (sqr(m3y-m1y) + sqr(m3x-m1x))
    
    
    // After testing, I found that the above equations 
    // actually give the height/width ratio of the rectangle, 
    // not the width/height ratio. 
    // If someone can find the error that caused this, 
    // I would be most grateful.
    // until then:
    whRatio = 1/whRatio;
    

    更新:以下是这些公式的确定方式:

    以下是代码输入 SAGE . 它可以在线访问 http://www.sagenb.org/home/pub/704/ . (sage在解方程方面非常有用,可以在任何浏览器中使用,请查看)

    # CALCULATING THE ASPECT RATIO OF A RECTANGLE DISTORTED BY PERSPECTIVE
    
    #
    # BIBLIOGRAPHY:
    # [zhang-single]: "Single-View Geometry of A Rectangle 
    #  With Application to Whiteboard Image Rectification"
    #  by Zhenggyou Zhang
    #  http://research.microsoft.com/users/zhang/Papers/WhiteboardRectification.pdf
    
    # pixel coordinates of the 4 corners of the quadrangle (m1, m2, m3, m4)
    # see [zhang-single] figure 1
    m1x = var('m1x')
    m1y = var('m1y')
    m2x = var('m2x')
    m2y = var('m2y')
    m3x = var('m3x')
    m3y = var('m3y')
    m4x = var('m4x')
    m4y = var('m4y')
    
    # pixel coordinates of the principal point of the image
    # for a normal camera this will be the center of the image, 
    # i.e. u0=IMAGEWIDTH/2; v0 =IMAGEHEIGHT/2
    # This assumption does not hold if the image has been cropped asymmetrically
    u0 = var('u0')
    v0 = var('v0')
    
    # pixel aspect ratio; for a normal camera pixels are square, so s=1
    s = var('s')
    
    # homogenous coordinates of the quadrangle
    m1 = vector ([m1x,m1y,1])
    m2 = vector ([m2x,m2y,1])
    m3 = vector ([m3x,m3y,1])
    m4 = vector ([m4x,m4y,1])
    
    
    # the following equations are later used in calculating the the focal length 
    # and the rectangle's aspect ratio.
    # temporary variables: k2, k3, n2, n3
    
    # see [zhang-single] Equation 11, 12
    k2_ = m1.cross_product(m4).dot_product(m3) / m2.cross_product(m4).dot_product(m3)
    k3_ = m1.cross_product(m4).dot_product(m2) / m3.cross_product(m4).dot_product(m2)
    k2 = var('k2')
    k3 = var('k3')
    
    # see [zhang-single] Equation 14,16
    n2 = k2 * m2 - m1
    n3 = k3 * m3 - m1
    
    
    # the focal length of the camera.
    f = var('f')
    # see [zhang-single] Equation 21
    f_ = sqrt(
             -1 / (
              n2[2]*n3[2]*s^2
             ) * (
              (
               n2[0]*n3[0] - (n2[0]*n3[2]+n2[2]*n3[0])*u0 + n2[2]*n3[2]*u0^2
              )*s^2 + (
               n2[1]*n3[1] - (n2[1]*n3[2]+n2[2]*n3[1])*v0 + n2[2]*n3[2]*v0^2
              ) 
             ) 
            )
    
    
    # standard pinhole camera matrix
    # see [zhang-single] Equation 1
    A = matrix([[f,0,u0],[0,s*f,v0],[0,0,1]])
    
    
    #the width/height ratio of the original rectangle
    # see [zhang-single] Equation 20
    whRatio = sqrt (
                   (n2*A.transpose()^(-1) * A^(-1)*n2.transpose()) / 
                   (n3*A.transpose()^(-1) * A^(-1)*n3.transpose())
                  ) 
    

    C代码中的简化方程由

    print "simplified equations, assuming u0=0, v0=0, s=1"
    print "k2 := ", k2_
    print "k3 := ", k3_
    print "f  := ", f_(u0=0,v0=0,s=1)
    print "whRatio := ", whRatio(u0=0,v0=0,s=1)
    
        simplified equations, assuming u0=0, v0=0, s=1
        k2 :=  ((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y
        - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
        k3 :=  ((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)/((m3y
        - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x)
        f  :=  sqrt(-((k3*m3y - m1y)*(k2*m2y - m1y) + (k3*m3x - m1x)*(k2*m2x
        - m1x))/((k3 - 1)*(k2 - 1)))
        whRatio :=  sqrt(((k2 - 1)^2 + (k2*m2y - m1y)^2/f^2 + (k2*m2x -
        m1x)^2/f^2)/((k3 - 1)^2 + (k3*m3y - m1y)^2/f^2 + (k3*m3x -
        m1x)^2/f^2))
    
    print "Everything in one equation:"
    print "whRatio := ", whRatio(f=f_)(k2=k2_,k3=k3_)(u0=0,v0=0,s=1)
    
        Everything in one equation:
        whRatio :=  sqrt(((((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
        m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
        1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
        m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
        m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x
        - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - m1y)^2/((((m1y - m4y)*m2x -
        (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
        m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
        m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
        + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
        m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
        - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
        m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
        - m1x)) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
        m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
        1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
        m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
        m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)*m2x/((m2y - m4y)*m3x
        - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - m1x)^2/((((m1y - m4y)*m2x -
        (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
        m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
        m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
        + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
        m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
        - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
        m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
        - m1x)) - (((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
        m1y*m4x)/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) -
        1)^2)/((((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
        m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
        1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
        m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
        m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x
        - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)^2/((((m1y - m4y)*m2x -
        (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
        m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
        m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
        + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
        m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
        - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
        m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
        - m1x)) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
        m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
        1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
        m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
        m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x
        - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) - m1x)^2/((((m1y - m4y)*m2x -
        (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
        m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
        m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
        + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
        m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
        - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
        m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
        - m1x)) - (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
        m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
        1)^2))
    
    
    
    # some testing:
    # - choose a random rectangle, 
    # - project it onto a random plane,
    # - insert the corners in the above equations,
    # - check if the aspect ratio is correct.
    
    from sage.plot.plot3d.transform import rotate_arbitrary
    
    #redundandly random rotation matrix
    rand_rotMatrix = \
               rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5)) *\
               rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5)) *\
               rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5))
    
    #random translation vector
    rand_transVector = vector((uniform(-10,10),uniform(-10,10),uniform(-10,10))).transpose()
    
    #random rectangle parameters
    rand_width =uniform(0.1,10)
    rand_height=uniform(0.1,10)
    rand_left  =uniform(-10,10)
    rand_top   =uniform(-10,10)
    
    #random focal length and principal point
    rand_f  = uniform(0.1,100)
    rand_u0 = uniform(-100,100)
    rand_v0 = uniform(-100,100)
    
    # homogenous standard pinhole projection, see [zhang-single] Equation 1
    hom_projection = A * rand_rotMatrix.augment(rand_transVector)
    
    # construct a random rectangle in the plane z=0, then project it randomly 
    rand_m1hom = hom_projection*vector((rand_left           ,rand_top            ,0,1)).transpose()
    rand_m2hom = hom_projection*vector((rand_left           ,rand_top+rand_height,0,1)).transpose()
    rand_m3hom = hom_projection*vector((rand_left+rand_width,rand_top            ,0,1)).transpose()
    rand_m4hom = hom_projection*vector((rand_left+rand_width,rand_top+rand_height,0,1)).transpose()
    
    #change type from 1x3 matrix to vector
    rand_m1hom = rand_m1hom.column(0)
    rand_m2hom = rand_m2hom.column(0)
    rand_m3hom = rand_m3hom.column(0)
    rand_m4hom = rand_m4hom.column(0)
    
    #normalize
    rand_m1hom = rand_m1hom/rand_m1hom[2]
    rand_m2hom = rand_m2hom/rand_m2hom[2]
    rand_m3hom = rand_m3hom/rand_m3hom[2]
    rand_m4hom = rand_m4hom/rand_m4hom[2]
    
    #substitute random values for f, u0, v0
    rand_m1hom = rand_m1hom(f=rand_f,s=1,u0=rand_u0,v0=rand_v0)
    rand_m2hom = rand_m2hom(f=rand_f,s=1,u0=rand_u0,v0=rand_v0)
    rand_m3hom = rand_m3hom(f=rand_f,s=1,u0=rand_u0,v0=rand_v0)
    rand_m4hom = rand_m4hom(f=rand_f,s=1,u0=rand_u0,v0=rand_v0)
    
    # printing the randomly choosen values
    print "ground truth: f=", rand_f, "; ratio=", rand_width/rand_height
    
    # substitute all the variables in the equations:
    print "calculated: f= ",\
    f_(k2=k2_,k3=k3_)(s=1,u0=rand_u0,v0=rand_v0)(
      m1x=rand_m1hom[0],m1y=rand_m1hom[1],
      m2x=rand_m2hom[0],m2y=rand_m2hom[1],
      m3x=rand_m3hom[0],m3y=rand_m3hom[1],
      m4x=rand_m4hom[0],m4y=rand_m4hom[1],
    ),"; 1/ratio=", \
    1/whRatio(f=f_)(k2=k2_,k3=k3_)(s=1,u0=rand_u0,v0=rand_v0)(
      m1x=rand_m1hom[0],m1y=rand_m1hom[1],
      m2x=rand_m2hom[0],m2y=rand_m2hom[1],
      m3x=rand_m3hom[0],m3y=rand_m3hom[1],
      m4x=rand_m4hom[0],m4y=rand_m4hom[1],
    )
    
    print "k2 = ", k2_(
      m1x=rand_m1hom[0],m1y=rand_m1hom[1],
      m2x=rand_m2hom[0],m2y=rand_m2hom[1],
      m3x=rand_m3hom[0],m3y=rand_m3hom[1],
      m4x=rand_m4hom[0],m4y=rand_m4hom[1],
    ), "; k3 = ", k3_(
      m1x=rand_m1hom[0],m1y=rand_m1hom[1],
      m2x=rand_m2hom[0],m2y=rand_m2hom[1],
      m3x=rand_m3hom[0],m3y=rand_m3hom[1],
      m4x=rand_m4hom[0],m4y=rand_m4hom[1],
    )
    
    # ATTENTION: testing revealed, that the whRatio 
    # is actually the height/width ratio, 
    # not the width/height ratio
    # This contradicts [zhang-single]
    # if anyone can find the error that caused this, I'd be grateful
    
        ground truth: f= 72.1045134124554 ; ratio= 3.46538779959142
        calculated: f=  72.1045134125 ; 1/ratio= 3.46538779959
        k2 =  0.99114614987 ; k3 =  1.57376280159
    
        2
  •  7
  •   Spooky Muscothym    9 年前

    更新

    在阅读了您的更新,并查看了第一个参考(白板扫描和图像增强),我看到了丢失点在哪里。

    问题的输入数据是四倍(A、B、C、D)。 投影图像的中心O。在本文中,它对应于假设u0=v0=0。加上这一点,问题会受到足够的约束,从而得到矩形的纵横比。

    然后将问题重述如下:给定z=0平面上的四倍(a,b,c,d),找到眼睛位置e(0,0,h),h>0和三维平面p,使(a,b,c,d)在p上的投影是一个矩形。

    注意,p由e决定:要得到一个平行四边形,p必须包含(e u)和(e v)的平行线,其中u=(ab)x(cd)和v=(ad)x(bc)。

    从实验上看,这个问题一般有一个唯一的解,对应于矩形的W/H比的一个唯一值。

    alt text alt text

    上岗

    不,不能从投影中确定矩形比例。

    在一般情况下,z=0平面上四个非共线点的四倍(a,b,c,d)是无限多个矩形的投影,具有无限多的宽高比。

    考虑两个消失点u,(ab)和(cd)和v的交点,(ad)和(bc)的交点,以及点i,两条对角线(ac)和(bd)的交点。要投影为abcd,中心的平行四边形i必须位于一个平面上,该平面包含通过点i与(uv)平行的线。在一个这样的平面上,可以找到许多投影到abcd的矩形,它们都具有不同的w/h比率。

    请参阅这两张使用cabri 3d完成的图像。在这两种情况下,abcd未更改(在灰色z=0平面上),并且包含矩形的蓝色平面也未更改。部分隐藏的绿线是(UV)线,可见绿线与之平行,包含i。

    alt text alt text

        3
  •  1
  •   Community CDub    7 年前

    尺寸不是真正需要的,比例也不是。考虑到他使用的是文件的照片/扫描,知道哪一边是不相关的。我怀疑他会扫描它们的背面。

    “转角交叉”是纠正透视的方法。这可能有帮助:

    How to draw a Perspective-Correct Grid in 2D

        4
  •  1
  •   Code Lღver Ionut Rusen    12 年前

    关于为什么结果给出h/w而不是w/h的问题: 我想知道上面等式20的表达式是否正确。 张贴的是:

           whRatio = sqrt (
                (n2*A.transpose()^(-1) * A^(-1)*n2.transpose()) / 
                (n3*A.transpose()^(-1) * A^(-1)*n3.transpose())
               ) 
    

    当我尝试用opencv执行它时,会得到一个异常。但当我使用下面的等式时,一切都是正确的,对我来说,它更像等式20: 但是根据公式20,它看起来应该是:

            whRatio = sqrt (
                (n2.transpose()*A.transpose()^(-1) * A^(-1)*n2) /
                (n3.transpose()*A.transpose()^(-1) * A^(-1)*n3)
               )
    
        5
  •  1
  •   Community CDub    7 年前

    你可以通过这个答案来确定宽度/高度。 Calculating rectangle 3D coordinate with coordinate its shadow? .假设你的矩形在交叉点上旋转,计算它的宽度和高度。但是,当您将假设阴影平面之间的距离更改为实际阴影平面时,矩形的比例与计算的宽度/高度相同!

        6
  •  0
  •   Toad    15 年前

    不知道“摄像机”的距离就不可能知道这个矩形的宽度。

    从5厘米远的地方看,一个小矩形和从几米远的地方看一样。

        7
  •  0
  •   Beta    15 年前

    画一个右等腰三角形,其中有两个消失点和地平线下的第三个点(即,与矩形在地平线的同一侧)。第三个点是我们的原点,到消失点的两条线是我们的轴。从原点到消失点的距离称为pi/2。现在,将矩形的边从消失点扩展到轴,并标记它们与轴相交的位置。选取一个轴,测量从两个标记到原点的距离,将这些距离转换为:x->tan(x),差就是该边的“真实”长度。对另一个轴执行相同的操作。取这两个长度的比值,就可以了。

        8
  •  0
  •   fortran    15 年前

    您需要更多的信息,转换后的图形可以来自任意角度的任意平行四边形。

    所以我想你需要先做些校准。

    编辑: 对于那些说我错了的人,下面是数学证明,有无限多的矩形/照相机组合产生相同的投影:

    为了简化问题(因为我们只需要边的比例),假设我们的矩形由以下点定义: R=[(0,0),(1,0),(1,r),(0,r)] (这种简化与将仿射空间中的任何问题转换为等效问题一样)。

    变换后的多边形定义为: T=[(tx0,ty0),(tx1,ty1),(tx2,ty2),(tx3,ty3)]

    存在一个变换矩阵 M = [[m00,m01,m02],[m10,m11,m12],[m20,m21,m22]] 满足的 (Rxi,Ryi,1)*M=wi(txi,tyi,1)'

    如果我们把上面的方程推广到这些点上,

    对于 R_0 我们得到: m02-tx0*w0 = m12-ty0*w0 = m22-w0 = 0

    对于 R_1 我们得到: m00-tx1*w1 = m10-ty1*w1 = m20+m22-w1 = 0

    对于 R_2 我们得到: m00+r*m01-tx2*w2 = m10+r*m11-ty2*w2 = m20+r*m21+m22-w2 = 0

    为了 R_3 我们得到: m00+r*m01-tx3*w3 = m10+r*m11-ty3*w3 = m20 + r*m21 + m22 -w3 = 0

    到目前为止,我们有12个方程,14个未知变量(9个来自矩阵,4个来自 wi ,比率为1 r )其余都是已知值( txi tyi 给出)。

    即使系统没有被低估,一些未知数也会彼此相乘。( R mi0 产品)使系统非线性(可以将其转换为线性系统,为每个产品指定一个新名称,但最终仍会有13个未知项,其中3个被扩展为无限解)。

    如果你能在推理或数学上发现任何缺陷,请告诉我。

        9
  •  0
  •   adius TankorSmash    8 年前

    Dropbox在他们的技术博客上有一篇广泛的文章,描述了他们如何解决扫描仪应用程序的问题。

    https://blogs.dropbox.com/tech/2016/08/fast-document-rectification-and-enhancement/

    更正文档

    我们假设输入文档在物理世界中是矩形的,但如果它不完全面向相机,则图像中的角将是一般的凸四边形。为了满足我们的第一个目标,我们必须撤消捕获过程应用的几何变换。这个转换取决于摄像机相对于文档的视点(这些是所谓的外部参数),以及摄像机的焦距(内部参数)。这里是捕获场景的图表:

    为了撤销几何变换,必须首先确定上述参数。如果我们假设一个很好对称的相机(没有散光,没有偏斜,等等),这个模型中的未知数是:

    • 相机相对于文档的三维位置(3个自由度);
    • 相机相对于文档的三维方向(3个自由度);
    • 文件的尺寸(2个自由度),以及
    • 相机的焦距(1度自由度)。

    另一方面,四个检测到的文档角的x和y坐标给了我们八个有效的约束。虽然看起来有更多的未知(9)而不是约束(8),但这些未知并非完全是自由变量,人们可以想象从物理上缩放文档并将其放在离相机更远的位置,以获得相同的照片。这个关系放置了一个额外的约束,所以我们有一个完全约束的系统要解决。(我们解出的实际方程组涉及其他一些考虑因素;维基百科的相关文章给出了一个很好的总结: https://en.wikipedia.org/wiki/Camera_resectioning )

    一旦恢复了参数,我们就可以撤消捕获过程中应用的几何变换,以获得一个漂亮的矩形图像。然而,这可能是一个耗时的过程:对于每个输出像素,都要查找源图像中相应输入像素的值。当然,GPU是专门为这样的任务设计的:在虚拟空间中渲染纹理。存在一个视图转换,它恰好是我们刚刚解决的摄像机转换的反方向!_“,用它可以呈现完整的输入图像并获得校正的文件。(要看到这一点,一个简单的方法是注意,一旦您的手机屏幕上有了完整的输入图像,您就可以倾斜和翻译手机,使屏幕上文档区域的投影对您来说是直线的。)

    最后,回想一下,在比例方面存在一个模糊性:例如,我们可以t判断文档是字母大小的纸张(8.5_x 11_)还是海报板(17__x 22_)。输出图像的尺寸应该是多少?为了解决这种模糊性,我们计算输入图像中四边形内的像素数,并将输出分辨率设置为与该像素数匹配。我们的想法是不想对图像进行过多的上下采样。

        10
  •  0
  •   Toby Collins    7 年前

    在这个有趣的问题上似乎仍然有些困惑。我想给出一个简单易懂的解释,说明问题何时可以解决,何时不能解决。

    约束和自由度

    通常,当我们面临这样一个问题时,首先要做的是评估未知自由度(自由度)n的数量,以及约束未知自由度的独立方程m的数量。如果n超过m,就不可能解决问题(意味着约束比未知少)。在这种情况下,我们可以排除所有无法解决的问题。如果n不超过m,则 可以 可以用唯一的解决方案来解决问题,但这是不保证的(请参阅第二段到最后一段的示例)。

    让我们使用 1, 2, 3和 4表示平面四角在世界坐标系中的位置。让我们使用 R T 将这些转换为相机坐标的三维旋转和平移。让我们使用 K 表示3x3_摄像机固有矩阵。我们暂时不考虑透镜变形。的二维位置 相机图像的第个角由 Q I= f K ( RP I+ T ))其中f是投影函数f(x,y,z)=(x/z,y/z)。利用这个方程,我们知道图像中的每个角给了我们两个未知的方程(即两个约束):一个来自 Q i和y分量中的一个。所以我们总共有8个约束要处理。这些约束的正式名称是 重投影约束 .

    那么,我们未知的自由度是什么呢?当然 R T 未知,因为我们不知道摄像机在世界坐标中的姿态。因此,我们已经有6个未知的自由度:3用于 R (例如横摆、纵摇和横摇)和3 T 因此 剩余术语中的未知数( K , 1, 2, 三, 4)

    不同的问题

    我们可以构造不同的问题,这取决于( K , 1, 2, 三, 4)我们将视为未知。现在让我们写出 K 以通常的形式: K =(fx,0,cx;0,fy,cy;0,0,1),其中fx和fy是焦距项(fx/fy通常称为图像纵横比),并且(cx,cy)是主点(图像中的投影中心)。

    我们可以通过让fx和fy作为我们的两个未知数来获得一个问题,并假设(cx,cy, 1, 2, 三, 4)都是已知的。事实上,这个问题在OpenCV的相机校准方法中得到了应用和解决,使用的是棋盘平面目标的图像。通过假设主点位于图像中心(这对大多数相机来说是一个非常合理的假设),可以得到fx和fy的初始估计值。

    或者,我们可以通过假设fx=fy来创建一个不同的问题,这对于许多相机来说也是非常合理的,并且假设这个焦距(表示为f)是 只有 未知的 K . 因此,我们还有一个未知数需要处理(回想一下,我们最多可以有两个未知数)。所以让我们假设我们知道平面的形状:作为一个矩形(这是问题的最初假设)。因此,我们可以将角定义为: 1=(0,0,0), 2=(0,W,0), 3=(H,0,0) 4=(h,w,0),其中h和w表示矩形的高度和宽度。现在,因为我们只剩下1个未知的,让我们把它设为平面的展弦比:x=w/h。现在的问题是,我们能同时恢复x,f吗? R T 来自8个重投影限制?答案是肯定的!在张的论文中给出了这个问题的答案。

    尺度模糊

    如果我们假设 K 已知,2个未知数是h和w。它们能从重射方程中解出来吗?答案是否定的,这是因为平面的大小和平面到相机的深度之间存在模糊性。特别是如果我们缩放角落 I按S和比例 T 在重射方程中,用s,然后s消去。因此,平面的绝对尺度是不可恢复的。

    对于未知的自由度,可能存在其他不同组合的问题,例如 R , T ,其中一个主点分量和平面的宽度未知。然而,我们需要考虑哪些情况是实际使用的。不过,我还没有看到针对所有有用组合的系统解决方案集!

    更多点

    我们可能认为,如果我们在平面和图像之间增加额外的点对应,或者利用平面的边缘,我们可以恢复8个以上的未知自由度。遗憾的是,答案是否定的,这是因为它们没有添加任何额外的独立约束。原因是4个角描述了 完全地 从平面到图像的转换。这可以通过使用四个角来拟合一个同形矩阵来看到,这可以确定图像中平面上所有其他点的位置。

    推荐文章