Pergunta

Dada uma imagem 2D de um retângulo distorcida pela perspectiva:

enter descrição da imagem aqui

Eu sei que a forma era originalmente um retângulo, mas eu não sei o seu tamanho original.

Se eu souber as coordenadas de pixels dos cantos nesta imagem, como posso calcular as proporções originais, ou seja, o quociente (largura / altura) do retângulo?

(fundo: o objetivo é automaticamente undistort fotos de documentos retangulares, detecção de borda provavelmente será feito com transformada de Hough)

UPDATE:

Tem havido alguma discussão sobre se é possível a todos para determinar a largura: relação altura com as informações dadas. Meu pensamento ingênuo foi que deve ser possível, desde que eu posso pensar em nenhuma maneira de projeto, por exemplo, de 1: 4 retângulo para o quadrilátero descrito acima. Os aparece relação claramente perto de 1: 1, por isso deve haver uma maneira de determinar matematicamente. Tenho no entanto nenhuma prova para este além da minha suposição intuitiva.

Eu ainda não totalmente compreendido os argumentos apresentados a seguir, mas acho que deve haver algum pressuposto implícito de que estamos perdendo aqui e que é interpretada de forma diferente.

No entanto, após horas de busca, eu finalmente encontrei alguns documentos relevantes para o problema. Eu estou lutando para entender a matemática usada lá, até agora sem sucesso. Particularmente o primeiro papel parece discutir exatamente o que eu queria fazer, infelizmente sem exemplos de código e matemática muito densa.

  • Zhengyou Zhang, Li-Wei Ele, "de digitalização e imagem aprimoramento Whiteboard" http://research.microsoft.com/en -us / um / pessoas / Zhang / papers / tr03-39.pdf p.11

    "Por causa da distorção de perspectiva, a imagem de um retângulo parece ser um quadrado. No entanto, uma vez que sabemos que é um retângulo no espaço, somos capazes de estimar tanto em comprimento focal da câmera e relação de aspecto do retângulo. "

  • ROBERT M. Haralick "Determinar parâmetros da câmara a partir da projecção em perspectiva de um rectângulo" http://portal.acm.org/citation.cfm?id=87146

    "vamos mostrar como usar a perspectiva de projeção 2D de um retângulo de tamanho e posição desconhecida no espaço 3D para determinar os parâmetros ângulo da câmera olhar em relação aos planos do retângulo."

Foi útil?

Solução

Aqui está a minha tentativa de responder a minha pergunta depois de ler o papel

Eu manipulado as equações por algum tempo em SAGE, e veio com este pseudo-código em C-style:


// 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;

Update: aqui é como essas equações onde determinados:

A seguir está o código em SAGE . Ele pode ser acessado on-line em http://www.sagenb.org/home/pub/704/ . (Sage é realmente útil na resolução de equações, e utilizável em qualquer navegador, check it out)

# 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())
              ) 

As equações simplificadas no c-código, onde determinados por

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

Outras dicas

Atualizar

Depois de ler a sua atualização, e olhando para a primeira referência (digitalização Whiteboard e melhoria de imagem), eu ver onde o ponto que falta é.

Os dados de entrada do problema é um quádruplo (A, B, C, D), E o O centro da imagem projectada. No artigo, que corresponde à suposição u0 = v0 = 0. Adicionando este ponto, o problema torna-se restrita suficiente para obter a proporção do retângulo aspecto.

O problema é depois corrigido como se segue: Num quádruplo (A, B, C, D) no plano z = 0, encontrar a posição dos olhos de E (0,0, h), h> 0 e um plano 3D P de tal modo que a projecção do (a, B, C, D) sobre P é um rectângulo.

Note que P é determinada por E: para obter um paralelogramo, P deve conter paralelos com (UE) e (EV), onde U = (AB) x (CD) e V = (AD) x (BC).

Experimentalmente, parece que este problema tem em uma única solução geral, o que corresponde a um valor único do índice de w / h do rectângulo.

text alt text alt

Post Anterior

Não, você não pode determinar a relação retângulo da projeção.

No caso geral, um quádruplo (A, B, C, D) de quatro pontos não colineares do plano z = 0 é a projecção de um número infinito de rectângulos, com um número infinito de proporções largura / altura.

Considere os dois pontos de fuga U, intersecção de (AB) e (CD) e V, intersecção de (AD) e (BC), e o ponto I, interseção das duas diagonais (AC) e (BD). Para projeto como ABCD, um paralelogramo do centro Devo mentir sobre um plano que contém a linha paralela (UV) através do ponto I. Em uma dessas avião, você pode encontrar muitos retângulos projetando a ABCD, todos com uma relação diferente w / h.

Veja estas duas imagens feitas com Cabri 3D. Nos dois casos é ABCD inalterado (em cinza, Z = 0 plano), e o plano azul contendo o rectângulo não é alterada, quer. A linha verde parcialmente escondido é a linha (UV) e a linha verde visível é paralela a ela e contém I.

text alt text alt

Tamanho não é realmente necessário, e nem são proporções. E saber de que lado está acima é uma espécie de irrelevante considerando que ele está usando fotos / digitalizações de documentos. Eu duvido que hes indo para digitalizar os lados das costas deles.

"Corner interseção" é o método de perspectiva correta. Isso pode ser de ajuda:

Como desenhar uma grade de perspectiva-Correct em 2D

Sobre a questão de por que os resultados dão h / w em vez w / h: Eu estou querendo saber se a expressão da Equação 20 acima está correto. Postado é:

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

Quando tento executar isso com OpenCV, eu recebo uma exceção. Mas tudo funciona corretamente quando eu usar a equação seguinte que para mim se parece mais com a Equação 20: Mas com base em Equação 20, parece que ele deve ser:

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

Você pode determinar a largura / altura por esta resposta Calculando retângulo coordenadas 3D com coordenar a sua sombra? . Suponha que seu retângulo rotação na intersecção calcular ponto diagonal-lo largura e altura. Mas quando você alterar a distância entre o plano suposição sombra ao real sombra avião proporcional do retângulo é o mesmo com calculada largura / altura!

é impossível saber a largura desse retângulo sem saber a distância do 'câmera'.

um pequeno retângulo visto de 5 cm de distância é a mesma de um grande retângulo como visto de metros de distância

Desenhar um triângulo isósceles direita com esses dois pontos de fuga e um terceiro ponto abaixo do horizonte (isto é, no mesmo lado do horizonte como o rectângulo é). Esse terceiro ponto será a nossa origem e as duas linhas para os pontos de fuga serão nossos eixos. Chamar a distância da origem a um ponto pi / 2 desaparecendo. Agora estender os lados do retângulo a partir dos pontos de fuga para os machados, e marca onde se cruzam os eixos. Escolha um eixo, medir as distâncias das duas marcas para a origem, transformar essas distâncias: x-> tan (x), ea diferença será o "verdadeiro" comprimento desse lado. Faça o mesmo para o outro eixo. Tome a relação entre esses dois comprimentos e você está feito.

Você precisa de mais informações, que figura transformada poderia vir de qualquer paralelogramo dado uma perspectiva arbitrária.

Então eu acho que você precisa fazer algum tipo de calibração em primeiro lugar.

Editar: para aqueles que disseram que eu estava errado, aqui vai a prova matemática de que existem infinitas combinações de retângulos / câmeras que o rendimento para a mesma projeção:

A fim de simplificar o problema (como precisamos apenas a relação dos lados), vamos supor que o nosso rectângulo é definido pelos seguintes pontos: R=[(0,0),(1,0),(1,r),(0,r)] (esta simplificação é o mesmo que transformar qualquer problema para uma equivalente em uma afim espaço).

O polígono transformado é definido como: T=[(tx0,ty0),(tx1,ty1),(tx2,ty2),(tx3,ty3)]

Existe uma transformação de matriz M = [[m00,m01,m02],[m10,m11,m12],[m20,m21,m22]] que satisfaz (Rxi,Ryi,1)*M=wi(txi,tyi,1)'

se expandirmos a equação acima para os pontos,

para R_0 temos: m02-tx0*w0 = m12-ty0*w0 = m22-w0 = 0

para R_1 temos: m00-tx1*w1 = m10-ty1*w1 = m20+m22-w1 = 0

para R_2 temos: m00+r*m01-tx2*w2 = m10+r*m11-ty2*w2 = m20+r*m21+m22-w2 = 0

e para R_3 temos: m00+r*m01-tx3*w3 = m10+r*m11-ty3*w3 = m20 + r*m21 + m22 -w3 = 0

Até agora temos 12 equações, 14 variáveis ??desconhecidas (9 a partir da matriz, a partir da 4 wi, e 1 para a relação r) e o resto valores são conhecidos (txi e tyi são dadas).

Mesmo se o sistema não foram underspecified, algumas das incógnitas são multiplicados entre si (r e mi0 produtos) fazendo com que o sistema não linear (você poderia transformá-lo em um sistema linear atribuir um novo nome a cada produto, mas você vai acabar ainda com 13 incógnitas e 3 deles sendo expandida para infinitas soluções).

Se você pode encontrar qualquer falha no raciocínio ou a matemática, por favor me avise.

Dropbox tem um extenso artigo sobre o seu blog de tecnologia, onde eles descrevem como eles resolveram o problema para o seu aplicativo scanner.

https: //blogs.dropbox. com / tecnologia / 2016/08 / fast-documento retificação-e-realce /

Corrigir um documento

Assumimos que o documento de entrada é retangular no mundo físico, mas se ele não está exatamente de frente para a câmera, os cantos, resultando na imagem vai ser um general convexos quadrilátero. Então, para satisfazer o nosso primeiro objetivo, temos de desfazer a transformação geométrica aplicada pelo processo de captura. Esta transformação depende do ponto de vista da câmara em relação ao documento (estes são os chamados parâmetros extrínsecos), além de coisas como o comprimento focal da câmara (os parâmetros intrínsecos). Aqui está um diagrama do cenário de captura:

Para desfazer transformar a geométrica, devemos primeiro determinar os parâmetros disse. Se assumirmos uma câmera bem simétrica (sem astigmatismo, sem inclinação, et cetera), as incógnitas neste modelo são:

  • a localização 3D da câmera em relação ao documento (3 graus de liberdade),
  • A orientação 3D da câmera em relação ao documento (3 graus de liberdade),
  • as dimensões do documento (2 graus de liberdade), e
  • a distância focal da câmara (1 grau de liberdade).

Por outro lado, o xey coordenadas dos quatro cantos de documentos detectados nos dá efetivamente oito restrições. Enquanto há aparentemente mais incógnitas (9) do que as restrições (8), os desconhecidos não são inteiramente livres variáveis-se poderia imaginar escalar o documento fisicamente e colocá-lo mais longe da câmera, para obter uma foto idêntica. Esta relação coloca uma restrição adicional, por isso temos um sistema totalmente constrangido a ser resolvido. (O atual sistema de equações que resolver envolve algumas outras considerações, o artigo relevante Wikipedia dá um bom resumo: https : //en.wikipedia.org/wiki/Camera_resectioning )

Uma vez que os parâmetros foram recuperados, podemos desfazer a transformação geométrica aplicada pelo processo de captura para obter uma imagem retangular agradável. No entanto, este é potencialmente um processo demorado: seria olhar para cima, para cada pixel de saída, o valor do pixel de entrada correspondente na imagem de origem. Claro, GPUs são projetados especificamente para tarefas como esta: Rendição uma textura em um espaço virtual. Existe uma visão transformar-que passa a ser o inverso da câmera transformar nós apenas resolvidos para -com! Que se pode tornar a imagem de entrada completa e obter o documento corrigido. (Uma maneira fácil de ver isso é notar que uma vez que você tem a imagem de entrada completa na tela do seu telefone, você pode inclinar e traduzir o telefone de tal forma que a projeção da região do documento no ecrã aparece retilíneo para você.)

Por fim, lembre-se que havia uma ambiguidade em relação à escala: não podemos dizer se o documento era um papel tamanho carta (8,5” x 11” ) ou um cartaz (17” x 22” ), para instância. Quais devem ser as dimensões da imagem de saída ser? Para resolver esta ambiguidade, contamos o número de pixels dentro do quadrilátero na imagem de entrada, e definir a resolução de saída como para coincidir com esta contagem de pixels. A idéia é que nós não queremos upsample ou downsample a imagem muito.

Parece ainda haver alguma confusão sobre este problema interessante. Eu quero dar uma explicação fácil de seguir para quando o problema pode e não pode ser resolvido.

Restrições e graus de liberdade

Normalmente, quando nos deparamos com um problema como este, a primeira coisa a fazer é avaliar o número de graus de liberdade desconhecidos (dofs) N, e o número de equações independentes M que temos para restringir as dofs desconhecidos. É impossível resolver o problema se se excede N M (ou seja, existem menos limitações de incógnitas). Nós podemos descartar todos os problemas que este é o caso como sendo insolúvel. Se N não exceda M então pode ser possível resolver o problema com uma solução única, mas isso não é garantido (ver o segundo ao último parágrafo para um exemplo).

Vamos usar p 1, p 2, p 3 e p 4 a identificar as posições da 4 cantos da superfície plana em coordenadas globais. Vamos uso R e t para ser a rotação 3D e tradução que transforma estes em coordenadas da câmera. Vamos uso K para denotar a matriz intrínseca câmera 3x3. Vamos ignorar distorção da lente para agora. A posição 2D do i th canto na imagem da câmera é dada por q i = f ( K ( R i + t )) em que f é a função de projecção f (x, y, z) = (x / z, y / z). Usando esta equação sabemos que cada canto na imagem dá-nos duas equações (ou seja, duas restrições) nas nossas incógnitas: um do componente x q i e um do componente y. Portanto, temos um total de 8 restrições para trabalhar. O nome oficial dessas restrições são as restrições reprojeção .

Então, quais são os nossos dofs desconhecidos? Certamente R e t são desconhecidas, porque não sabemos a pose da câmera nas coordenadas mundiais. Portanto, temos já 6 dofs desconhecidos: 3 para R (por exemplo guinada, pitch and roll) e 3 para t . Portanto, pode haver um máximo de dois incógnitas em termos restantes ( K , p 1, p 2, p 3, p 4).

Diferentes problemas

pode construir diferentes problemas, dependendo de qual dois termos ( K , p 1, p 2, p 3, p 4), consideraremos como desconhecido. Ao escrever este ponto de deixar sair K na forma habitual: K = (fx, 0, cx; 0, fy, cy; 0,0,1) onde fx e fy são os termos de distância focal (fx / fy é normalmente chamada a relação de aspecto da imagem) e (CX, CY) é o ponto principal (o centro da projecção na imagem).

Nós poderíamos obter um problema por ter fx e fy como as nossas duas incógnitas, e assumir (cx, cy, p 1, p 2, p 3, p 4) são todos conhecidos. Na verdade, esta muito problema é usado e resolvido dentro método de calibração a câmera do OpenCV, usando imagens de um alvo quadriculado planar. Isto é usado para obter uma estimativa inicial para fx e fy, assumindo que o ponto principal é no centro da imagem (que é uma hipótese muito razoável para a maioria das câmeras).

Como alternativa, podemos criar um problema diferente, assumindo fx = fy, que novamente é bastante razoável para muitas câmeras, e assumir esse comprimento focal (denotado como f) é o única desconhecido em K . Portanto, ainda temos um incógnitas esquerda para jogar com (lembre-se que pode ter um máximo de duas incógnitas). Então, vamos usar isso supondo que conhecida a forma do avião: como um retângulo (que era a suposição original na pergunta). Portanto, podemos definir os cantos, como se segue: p 1 = (0,0,0), p 2 = (0, W, 0), P 3 = (H, 0,0) e p 4 = (H, W, 0), em que h e W significa a altura e a largura do rectângulo. Agora, porque só temos 1 Desconhecido esquerda, vamos definir isso como proporção do avião: x = w / h. Agora a questão é que podemos recuperar simultaneamente x, f, R e t a partir das 8 restrições reprojeção? A resposta despeja é sim! E a solução é dada no artigo de Zhang citado na pergunta.

A escala ambigüidade

Uma maravilha poder se outro problema pode ser resolvido: se assumirmos K h é conhecido e os 2 incógnitas são e w. eles podem ser resolvidos a partir das equações reprojeção? A resposta é não, e é porque há uma ambiguidade entre o tamanho do avião e profundidade do avião para a câmera. Especificamente, se dimensionar os cantos p i por s e escala t por s, então s cancela nas equações reprojeção. Portanto, a escala absoluta do avião não é recuperável.

Pode haver outros problemas com diferentes combinações para os dofs desconhecidos, por exemplo, possuindo R , t , um dos principais componentes de ponto e do plano "s largura como incógnitas. mas é preciso pensar em quais casos são de uso prático. No entanto, eu ainda não vi um conjunto sistemático de soluções para todas as combinações úteis!

Mais pontos

Podemos pensar que, se fôssemos para adicionar correspondências ponto extra entre o plano ea imagem, ou explorar as arestas do plano, poderíamos recuperar mais de 8 dofs desconhecidos. Infelizmente, a resposta é não. Isso é porque eles não adicionar quaisquer restrições extras independentes. A razão é porque os 4 cantos descrever completamente a transformação do avião para a imagem. Isto pode ser visto por ajuste de uma matriz homografia usando os quatro cantos, que pode, então, determinar as posições de todos os outros pontos no plano da imagem.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top