51 votes

les proportions d'un rectangle déformé par la perspective

Étant donné une image 2d d'un rectangle déformé par la perspective :

enter image description here

Je sais que la forme était à l'origine un rectangle, mais je ne connais pas sa taille originale.

Si je connais les coordonnées des pixels des coins de cette image, comment puis-je calculer les proportions originales, c'est-à-dire le quotient (largeur/hauteur) du rectangle ?

(background : le but est de déformer automatiquement des photos de documents rectangulaires, la détection des bords sera probablement faite avec la transformée de Hough)

UPDATE :

La question de savoir s'il est possible de déterminer le rapport largeur/hauteur à partir des informations fournies a fait l'objet de discussions. Ma pensée naïve était que cela devait être possible, puisque je ne vois aucun moyen de projeter par exemple un rectangle 1:4 sur le quadrilatère décrit ci-dessus. Le rapport semble clairement proche de 1:1, il devrait donc y avoir un moyen de le déterminer mathématiquement. Je n'ai cependant aucune preuve de cela au-delà de ma supposition intuitive.

Je n'ai pas encore pleinement compris les arguments présentés ci-dessous, mais je pense qu'il doit y avoir une hypothèse implicite qui nous échappe ici et qui est interprétée différemment.

Cependant, après des heures de recherche, j'ai finalement trouvé des documents pertinents pour le problème. Je m'efforce de comprendre les mathématiques qui y sont utilisées, sans succès jusqu'à présent. En particulier, le premier article semble discuter exactement de ce que je voulais faire, malheureusement sans exemples de code et avec des mathématiques très denses.

  • Zhengyou Zhang , Li-Wei He, "Numérisation et amélioration de l'image des tableaux blancs". http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf p.11

    "À cause de la distorsion de perspective, l'image d'un rectangle semble être un quadrilatère. Cependant, puisque nous savons qu'il s'agit d'un rectangle dans l'espace, nous sommes en mesure d'estimer à la fois la distance focale de l'appareil photo et le rapport d'aspect du rectangle."

  • ROBERT M. HARALICK "Déterminer les paramètres d'une caméra à partir de la projection en perspective d'un rectangle". http://portal.acm.org/citation.cfm?id=87146

    "Nous montrons comment utiliser la projection en perspective 2D d'un rectangle de taille et de position inconnues dans l'espace 3D pour déterminer les paramètres de l'angle de visée de la caméra par rapport aux plans du rectangle."

0 votes

P.s. juste pour être clair : la largeur et la hauteur elles-mêmes sont bien sûr indéterminables avec les informations données, je cherche le quotient de la largeur par la hauteur.

0 votes

J'ai mis à jour ma réponse, la conclusion est que le quotient largeur/hauteur est également indéterminable avec les informations données.

0 votes

J'ai aussi mis le mien à jour. Si vous connaissez le centre d'image, alors le problème a en fait une solution. Voir les diagrammes que j'ai ajoutés.

29voto

HugoRune Points 3921

Voici ma tentative de réponse à ma question après avoir lu l'article.

J'ai manipulé les équations pendant un certain temps dans SAGE, et je suis arrivé à ce pseudo-code en style 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;

Mise à jour : voici comment ces équations ont été déterminées :

Ce qui suit est un code dans SAGE . Il peut être consulté en ligne à l'adresse suivante http://www.sagenb.org/home/pub/704/ . (Sage est très utile pour résoudre des équations et peut être utilisé dans n'importe quel navigateur.)

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

Les équations simplifiées dans le code c sont déterminées par

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

1 votes

Merci, Hugo. You should not use == operator when working with doubles. Better if you write code like this: <code> double kk = (k3 - 1)*(k2 - 1); if (abs(kk) < 0.0001) { // there is no perspective distortion... use formula 2 } else { // there is perspective distortion... use formula 1 } </code>

0 votes

En ce qui concerne le problème de la hauteur/largeur / largeur/hauteur : je ne vois pas comment vous pourriez le savoir. Avec une image, le rapport entre les objets pourrait être les deux, n'est-ce pas ? Ce qui est largeur et ce qui est hauteur n'est généralement qu'une convention.

3 votes

Et pour les autres qui essaient de mettre en œuvre cette méthode : faites attention à l'ordre des sommets, ils sont les suivants no dans le sens inverse des aiguilles d'une montre, mais une sorte de zig-zag. Regardez dans le journal.

7voto

Eric Bainville Points 5300

Mise à jour

Après avoir lu votre mise à jour, et regardé la première référence (Numérisation du tableau blanc et amélioration de l'image), je vois où est le point manquant.

Les données d'entrée du problème sont un quadruple (A,B,C,D), ET le centre O de l'image projetée. Dans l'article, cela correspond à l'hypothèse u0=v0=0. En ajoutant ce point, le problème devient suffisamment contraint pour obtenir le rapport d'aspect du rectangle.

Le problème est alors reformulé comme suit : Étant donné un quadruple (A,B,C,D) dans le plan Z=0, trouver la position des yeux E(0,0,h), h>0 et un plan 3D P tel que la projection de (A,B,C,D) sur P soit un rectangle.

Notez que P est déterminé par E : pour obtenir un parallélogramme, P doit contenir les parallèles à (EU) et (EV), où U=(AB)x(CD) et V=(AD)x(BC).

Expérimentalement, il semble que ce problème ait en général une solution unique, correspondant à une valeur unique du rapport w/h du rectangle.

alt textalt text

Article précédent

Non, vous ne pouvez pas déterminer le rapport du rectangle à partir de la projection.

Dans le cas général, un quadruple (A,B,C,D) de quatre points non colinéaires du plan Z=0 est la projection d'une infinité de rectangles, avec une infinité de rapports largeur/hauteur.

Considérons les deux points de fuite U, intersection de (AB) et (CD) et V, intersection de (AD) et (BC), et le point I, intersection des deux diagonales (AC) et (BD). Pour se projeter sous la forme ABCD, un parallélogramme de centre I doit se trouver sur un plan contenant la droite parallèle à (UV) passant par le point I. Sur un tel plan, vous pouvez trouver de nombreux rectangles se projetant en ABCD, tous avec un rapport w/h différent.

Voir ces deux images réalisées avec Cabri 3D. Dans les deux cas, ABCD est inchangé (sur le plan gris Z=0), et le plan bleu contenant le rectangle n'est pas modifié non plus. La ligne verte partiellement cachée est la ligne (UV) et la ligne verte visible est parallèle à celle-ci et contient I.

alt textalt text

0 votes

Excusez-moi, mais ça ne semble pas correct. Vous semblez avoir déplacé la caméra entre ces deux cas, ce qui va changer l'apparence de ABCD. Projeter sur un plan comme ça n'est au mieux qu'approximativement correct, et vous avez enfreint les règles.

0 votes

Oui, l'œil est à l'intersection des lignes rouges. Vous avez raison de dire que la position de la caméra change entre les deux vues. Ce qui ne change pas, c'est l'entrée du problème : la projection ABCD.

0 votes

Excusez-moi, mais vous avez tort. Vous vous projetez sur le mauvais plan. Si je construis un rectangle 2:1, que je lui donne une position et une orientation, et que je place la caméra, pensez-vous pouvoir trouver un rectangle 3:1 qui ressemble à la caméra ?

1voto

Neil N Points 14566

La taille n'est pas vraiment nécessaire, pas plus que les proportions. Et savoir quel côté est en haut n'est pas très pertinent vu qu'il utilise des photos/scans de documents. Je doute qu'il scanne le verso des documents.

"L'intersection des angles" est la méthode permettant de corriger la perspective. Cela pourrait vous aider :

Comment dessiner une grille de Perspective-Correct en 2D

0 votes

Merci, mais je ne suis pas sûr d'avoir bien compris : En utilisant les informations données dans la réponse liée, je peux transformer le quadrilatère de l'image en un rectangle arbitraire, en le subdivisant à l'intersection des diagonales. Ce que j'aimerais faire, c'est transformer le quadrilatère en un rectangle aux proportions correctes. Ainsi, l'image d'un carré ne devrait être convertie qu'en un carré. Je ne sais pas comment obtenir le rapport des côtés. La recherche sur Google de l'expression "intersection des angles" n'a rien donné.

0 votes

Si vous continuez d'intersecter jusqu'à ce que les rectangles soient plus petits que des pixels, à partir de là, vous pouvez mesurer la hauteur et la largeur... vous saurez alors quelle taille créer pour votre rectangle de destination... et vous n'aurez plus qu'à faire le mappage en arrière à partir de là.

0 votes

Je ne suis pas sûr de savoir comment cela fonctionnerait. Lorsque je coupe le quadrangle original n fois, j'obtiens 2^n * 2^n quadrangles plus petits. Même s'ils sont plus petits que des pixels, ils ont toujours les mêmes proportions que le quadrilatère original, et le quadrilatère original sera exactement 2^n petits_quadrangles de haut et 2^n petits quadrangles de large. Si je fais correspondre chaque petit quadrangle à un pixel, j'obtiendrai un carré.

1voto

HooKooDooKu Points 11

En ce qui concerne la question de savoir pourquoi les résultats donnent h/w plutôt que w/h : Je me demande si l'expression de l'équation 20 ci-dessus est correcte. Elle l'est :

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

Quand j'essaie de l'exécuter avec OpenCV, j'obtiens une exception. Mais tout fonctionne correctement lorsque j'utilise l'équation suivante qui, pour moi, ressemble plus à l'équation 20 : Mais en se basant sur l'équation 20, on dirait que ça devrait être :

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

0 votes

C'est bizarre, ces opérations ne devraient même pas être définies. Je ne connais pas bien SAGE, mais il semble que n2 et n3 soient transposés par rapport à l'article. En tout cas, je ne peux pas mettre votre suggestion en pratique dans SAGE, car les opérations ne sont pas définies.

0voto

Toad Points 7868

Il est impossible de connaître la largeur de ce rectangle sans connaître la distance de la "caméra".

un petit rectangle vu à 5 centimètres de distance a la même apparence qu'un énorme rectangle vu à plusieurs mètres de distance

0 votes

Partiellement correct. Vous devez non seulement connaître la distance, mais aussi le champ de vision de l'appareil photo. Par exemple, un appareil photo 35 mm typique a un angle de vision de 54 degrés sans zoom.

0 votes

Il faudrait probablement aussi connaître la rotation, car on ne sait pas quel côté est en haut.

0 votes

Je n'ai pas besoin de la largeur, seulement des proportions, c'est-à-dire du quotient (largeur / hauteur). L'échelle dépend bien sûr de la distance à l'observateur, mais pour autant que je sache, les proportions ne le sont pas. Un carré de 1 par 1 sera représenté par des projections différentes de celles d'un rectangle de 1 par 2, n'est-ce pas ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X