Подтвердить что ты не робот

Пропорции перспективно-деформированного прямоугольника

Учитывая 2d изображение прямоугольника, искаженного перспективой:

enter image description here

Я знаю, что форма первоначально была прямоугольником, но я не знаю ее первоначального размера.

Если я знаю пиксельные координаты углов на этом изображении, как я могу рассчитать исходные пропорции, т.е. отношение (ширина/высота) прямоугольника?

(фон: цель состоит в том, чтобы автоматически искажать фотографии прямоугольных документов, обнаружение края, вероятно, будет выполнено с преобразованием hough)

UPDATE:

Было проведено некоторое обсуждение вопроса о том, возможно ли вообще определить отношение ширины: высоты к указанной информации. Моя наивная мысль заключалась в том, что это должно быть возможно, так как я не могу придумать никакого способа проецировать, например, прямоугольник 1: 4 на четырехугольник, изображенный выше. Коэффициент явно близок к 1:1, поэтому должен быть способ его математически определить. У меня нет никаких доказательств этого, кроме моей интуитивной догадки.

Я еще не полностью понял приведенные ниже аргументы, но я думаю, что здесь должно быть какое-то неявное предположение о том, что мы здесь отсутствуют, и это интерпретируется по-разному.

Однако после нескольких часов поиска я наконец нашел несколько статей, относящихся к проблеме. Я изо всех сил пытаюсь понять математику, используемую там, до сих пор без успеха. В частности, первая статья, похоже, обсуждает именно то, что я хотел сделать, к сожалению, без примеров кода и очень плотной математики.

  • Zhengyou Zhang, Li-Wei He, "Сканирование доски и улучшение изображения" http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf p.11

    "Из-за искажения перспективы изображение прямоугольника кажется четырехугольным. Однако, поскольку мы знаем, что это прямоугольник в пространстве, мы можем оценить как фокусное расстояние камеры, так и соотношение сторон прямоугольников."

  • ROBERT M. HARALICK "Определение параметров камеры с точки зрения проекции прямоугольника" http://portal.acm.org/citation.cfm?id=87146

    "мы покажем, как использовать 2D-перспективную проекцию прямоугольника неизвестного размера и положения в 3D-пространстве для определения параметров угла обзора камеры относительно планов прямоугольника."

4b9b3361

Ответ 1

Вот моя попытка ответить на мой вопрос после прочтения статьи

Я манипулировал уравнениями в течение некоторого времени в 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 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

Обновление

После прочтения вашего обновления и просмотра первой справки (Сканирование доски и улучшение изображения) я вижу, где находится недостающая точка.

Входные данные задачи представляют собой четверку (A, B, C, D), AND центра O проецируемого изображения. В статье это соответствует предположению u0 = v0 = 0. Добавляя эту точку, проблема становится достаточно ограниченной, чтобы получить соотношение сторон прямоугольника.

Задача затем пересчитывается следующим образом: учитывая четверку (A, B, C, D) в плоскости Z = 0, найдите положение глаза E (0,0, h), h > 0 и трехмерную плоскость P, что проекция (A, B, C, D) на P является прямоугольником.

Заметим, что P определяется E: для получения параллелограмма P должна содержать параллели с (EU) и (EV), где U = (AB) x (CD) и V = (AD) x (BC).

Экспериментально кажется, что эта проблема имеет в общем единственное решение, соответствующее единственному значению отношения w/h прямоугольника.

alt textalt text

Предыдущий пост

Нет, вы не можете определить отношение прямоугольника от проекции.

В общем случае четверка (A, B, C, D) четырех неколлинеарных точек плоскости Z = 0 представляет собой проекцию бесконечного числа прямоугольников с бесконечным числом отношений ширины/высоты.

Рассмотрим две точки обращения U, пересечение (AB) и (CD) и V, пересечение (AD) и (BC), и точку I, пересечение двух диагоналей (AC) и (BD). Чтобы проектировать ABCD, параллелограмм центра я должен лежать на плоскости, содержащей линию, параллельную (УФ) через точку I. На одной из таких плоскостей вы можете найти много прямоугольников, выступающих в ABCD, все с другим отношением w/h.

Смотрите два изображения, сделанные с помощью Cabri 3D. В двух случаях ABCD не изменяется (на серой плоскости Z = 0), и синяя плоскость, содержащая прямоугольник, также не изменяется. Зеленая линия частично скрыта (линия УФ), а видимая зеленая линия параллельна ей и содержит I.

alt textalt text

Ответ 3

Размер действительно не нужен, и ни один из них не пропорционален. И зная, какая сторона вверх, не имеет значения, учитывая, что он использует фотографии/сканирование документов. Я сомневаюсь, что они будут сканировать задние стороны.

"Угловое пересечение" - это метод коррекции перспективы. Это может помочь:

Как нарисовать перспективно-правильную сетку в 2D

Ответ 4

В вопросе о том, почему результаты дают 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

Вы можете определить ширину/высоту с помощью этого ответа Вычисление трехмерной координаты прямоугольника с координатой его тени?. Предположим, что ваш прямоугольник вращается в диагональной точке пересечения, рассчитывая его ширину и высоту. Но когда вы меняете расстояние между плоскостью тени предположения и реальной плоскостью тени, пропорциональной прямоугольнику, то же самое с расчетной шириной/высотой!

Ответ 6

невозможно узнать ширину этого прямоугольника, не зная расстояние от "камеры".

маленький прямоугольник, видимый с расстояния 5 сантиметров, выглядит так же, как огромный прямоугольник, как видно из метров.

Ответ 7

Вам нужна дополнительная информация, что преобразованная фигура может исходить из любого параллелограмма с учетом произвольной перспективы.

Итак, я думаю, вам нужно сначала выполнить некоторую калибровку.

Изменить: для тех, кто сказал, что я ошибался, здесь идет математическое доказательство того, что существуют бесконечные комбинации прямоугольников/камер, которые дают одну и ту же проекцию:

Чтобы упростить задачу (поскольку нам нужно только соотношение сторон), предположим, что наш прямоугольник определяется следующими точками: 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 из них будут расширены до бесконечных решений).

Если вы можете найти какой-либо недостаток в рассуждениях или математике, пожалуйста, дайте мне знать.

Ответ 8

Нарисуйте правый равнобедренный треугольник с этими двумя исчезающими точками и третью точку ниже горизонта (то есть на той же стороне горизонта, что и прямоугольник). Этот третий пункт будет нашим происхождением, и две линии к исчезающим точкам будут нашими топорами. Вызовите расстояние от начала координат до точки исчезновения pi/2. Теперь протяните стороны прямоугольника от нулевых точек до осей и отметьте, где они пересекают оси. Выберите ось, измерьте расстояния от двух меток до начала координат, преобразуйте эти расстояния: x- > tan (x), и разница будет "истинной" длиной этой стороны. Сделайте то же самое для другой оси. Возьмите соотношение этих двух длин, и все готово.

Ответ 9

В 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)

Как только параметры будут восстановлены, мы можем отменить геометрическое преобразование, применяемое процессом захвата, чтобы получить хорошее прямоугольное изображение. Тем не менее, это потенциально длительный процесс: для каждого выходного пикселя будет отображаться значение соответствующего входного пикселя в исходном изображении. Конечно, графические процессоры специально разработаны для таких задач: рендеринг текстуры в виртуальном пространстве. Существует преобразование вида, которое, оказывается, является обратным преобразованию камеры, которое мы только что решили для! - с помощью которого можно отобразить полное входное изображение и получить выпрямленный документ. (Простой способ увидеть это - отметить, что после полного ввода изображения на экране вашего телефона вы можете наклонить и перевести телефон так, чтобы проекция области документа на экране выглядела прямолинейной для вас.)

Наконец, напомним, что существует неоднозначность по шкале: мы не можем сказать, был ли документ документом размером с письмо (8.5 "x 11" ) или плакатной доской (17 "x 22" ), например. Какими должны быть размеры выходного изображения? Чтобы устранить эту двусмысленность, мы подсчитываем количество пикселей в четырехстороннем изображении во входном изображении и устанавливаем разрешение вывода в соответствии с этим количеством пикселей. Идея состоит в том, что мы не хотим слишком сильно увеличивать или уменьшать изображение.