proportions d'un rectangle déformé en perspective
Donné une image 2d d'un rectangle déformé par la perspective:
je sais que la forme était à l'origine un rectangle, mais je ne connais pas sa taille originale.
si je connais les coordonnées pixel 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 automatiquement undistort photos de la forme rectangulaire des documents, la détection de contour sera probablement fait avec la transformation de hough)
mise à jour:
on s'est demandé s'il était possible de déterminer le rapport largeur / hauteur à l'aide des informations fournies. Ma pensée naïve était qu'il devait être possible, puisque je ne peux penser à aucun moyen de projeter par exemple un rectangle 1:4 sur le quadrilatère représenté ci-dessus. Le rapport apparaît clairement proche de 1:1, donc il devrait y avoir un moyen pour déterminer mathématiquement. Je n'ai cependant aucune preuve pour cela au-delà de mon intuition.
Je n'ai pas encore bien compris les arguments présentés ci-dessous, mais je pense qu'il doit y avoir une hypothèse implicite que nous manquons ici et qui est interprétée différemment.
cependant, après des heures de recherche, j'ai finalement trouvé quelques documents pertinents au problème. J'ai du mal à comprendre les maths utilisées là-dedans, donc à présent sans succès. En particulier, le premier papier semble discuter exactement ce que je voulais faire, malheureusement sans exemples de code et de mathématiques très dense.
-
Zhengyou Zhang , Li-Wei-Il, "Tableau de numérisation et de valorisation de l'image" http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf p. 11
"en Raison de la distorsion de perspective, l'image d'un rectangle semble être un quadrangle. Cependant, comme nous savons qu'il s'agit d'un rectangle dans l'espace, nous sommes en mesure d'estimer à la fois la distance focale de la caméra et le rapport d'aspect du rectangle."
-
ROBERT M. HARALICK "Determining camera parameters from the perspective projection of a rectangle" http://portal.acm.org/citation.cfm?id=87146
" nous montrons comment utiliser la perspective 2D projection d'un rectangle de taille et de position inconnues dans L'espace 3D pour déterminer les paramètres d'angle de visée de la caméra par rapport aux plans du rectangle."
10 réponses
voici ma tentative de répondre à ma question après avoir lu le journal
- Zhengyou Zhang, Li-Wei He, "Tableau de numérisation et de valorisation de l'image" http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf
j'ai manipulé les équations pendant un certain temps dans SAGE, et j'ai trouvé ce pseudo-code dans le 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 où déterminées:
est le code dans SAGE . Il peut être consulté en ligne à http://www.sagenb.org/home/pub/704 / . (Sage est vraiment utile pour résoudre des équations, et utilisable dans n'importe quel navigateur, vérifier)
# 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 du code c lorsqu'elles 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
mise à Jour
après avoir lu votre mise à jour, et en regardant la première référence (balayage de tableau blanc et amélioration d'image), je vois où le point manquant est.
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, il correspond à l'hypothèse u0=v0=0. En ajoutant ce point, le problème devient assez contraint pour obtenir le proportions du rectangle.
le problème est alors reformulé comme suit: avec un quadruple (A,B,C,D) dans le plan Z=0, trouver la position de l'oeil E(0,0,h), h>0 et un plan 3D P tel que la projection de (A,B,C,D) sur P est un rectangle.
noter que P est déterminé par E: pour obtenir un parallélogramme, P doit contenir des parallèles à (EU) et (EV), où U=(AB)x(CD) et V=(AD)x(BC).
expérimentalement, il semble que ce problème général une solution unique, correspondant à une valeur unique du rapport w/h du rectangle.
Post Précédent
Non, vous ne pouvez pas déterminer le ratio rectangle à partir de la projection.
dans le cas général, un quadruple (A, B,C, D) de quatre points non collinéaires du plan Z=0 est la projection d'un nombre infini rectangles, avec des rapports largeur/hauteur infiniment nombreux.
Considérer 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 projeter comme ABCD, un parallélogramme du Centre I doit se trouver sur un plan contenant la ligne parallèle à (UV) par le point I. sur un tel plan, vous pouvez trouver de nombreux rectangles projetant à ABCD, tous avec un rapport w/h différent.
voir ces deux images fait 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 changé non plus. La ligne verte partiellement cachée est la ligne (UV) et la ligne verte visible est parallèle à elle et contient I.
la taille n'est pas vraiment nécessaire, et les proportions non plus. Et savoir quel côté est en haut est un peu hors de propos considérant qu'il utilise des photos/scans de documents. Je doute qu'il scanne les côtés arrières.
"au Coin de l'intersection" est la méthode pour corriger la perspective. Cela pourrait être utile:
sur 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. Posté:
whRatio = sqrt (
(n2*A.transpose()^(-1) * A^(-1)*n2.transpose()) /
(n3*A.transpose()^(-1) * A^(-1)*n3.transpose())
)
quand J'essaie D'exécuter cela avec OpenCV, j'obtiens une exception. Mais tout fonctionne correctement lorsque j'utilise l'équation suivante qui pour moi ressemble plus à de l'Équation 20: Mais sur la base de L'équation 20, Il semble qu'il devrait être:
whRatio = sqrt (
(n2.transpose()*A.transpose()^(-1) * A^(-1)*n2) /
(n3.transpose()*A.transpose()^(-1) * A^(-1)*n3)
)
vous pouvez déterminer la largeur / hauteur par cette réponse calcul rectangle 3D coordonnées avec coordonner son ombre? . Supposons que votre rectangle tourne sur le point d'intersection diagonale calculer la largeur et la hauteur. Mais quand vous changez la distance entre le plan d'ombre de l'hypothèse au plan d'ombre réel proportionnel de rectangle est le même avec la largeur / hauteur calculée!
il est impossible de connaître la largeur de ce rectangle, sans connaître la distance de la "caméra".
un petit rectangle vu de 5 centimètres de distance ressemble à un grand rectangle vu de mètres de distance
dessinez un triangle isocèle droit avec ces deux points de fuite et un troisième point au-dessous de l'horizon (c'est-à-dire, du même côté de l'horizon que le rectangle est). Ce troisième point sera notre origine et les deux lignes vers les points de fuite seront nos axes. Appelez la distance entre l'origine et un point de fuite pi/2. Maintenant, étendez les côtés du rectangle des points de fuite aux axes, et marquez où ils croisent les axes. Choisir un axe, mesurer les distances deux marques à l'origine, transformer ces distances: x->tan(x), et la différence sera le "vrai" longueur de ce côté. Faire de même pour les autres axes. Prendre le rapport de ces deux longueurs et vous avez terminé.
vous avez besoin de plus d'informations, que la figure transformée pourrait venir de n'importe quel parallélogramme donné une perspective arbitraire.
donc je suppose que vous devez faire une sorte de calibrage d'abord.
Edit: pour ceux qui ont dit que j'avais tort, voici la preuve mathématique qu'il y a des combinaisons infinies de rectangles / caméras qui donnent à la même projection:
pour simplifier le problème (puisque nous n'avons besoin que du rapport des côtés) supposons que notre rectangle est défini par les points suivants: R=[(0,0),(1,0),(1,r),(0,r)]
(cette simplification est la même que transformer n'importe quel problème en un équivalent dans un espace affine).
le polygone transformé est défini comme suit: T=[(tx0,ty0),(tx1,ty1),(tx2,ty2),(tx3,ty3)]
il existe une matrice de transformation M = [[m00,m01,m02],[m10,m11,m12],[m20,m21,m22]]
qui satisfait (Rxi,Ryi,1)*M=wi(txi,tyi,1)'
si nous développons l'équation ci-dessus pour points,
pour R_0
nous obtenons: m02-tx0*w0 = m12-ty0*w0 = m22-w0 = 0
pour R_1
nous obtenons: m00-tx1*w1 = m10-ty1*w1 = m20+m22-w1 = 0
pour R_2
nous obtenons: m00+r*m01-tx2*w2 = m10+r*m11-ty2*w2 = m20+r*m21+m22-w2 = 0
et pour R_3
nous obtenons: m00+r*m01-tx3*w3 = m10+r*m11-ty3*w3 = m20 + r*m21 + m22 -w3 = 0
Jusqu'à présent nous avons 12 équations, 14 variables inconnues (9 de la matrice, 4 de la wi
, et 1 pour le rapport r
) et le reste sont des valeurs connues ( txi
et tyi
sont donnés).
même si le système n'était pas sous-spécifié, certaines des inconnues sont multipliées entre elles ( r
et mi0
produits) rendant le système non linéaire (vous pourriez le transformer en un système linéaire attribuant un nouveau nom à chaque produit, mais vous finirez toujours avec 13 inconnues, et 3 d'entre elles étant étendues à des solutions infinies).
si vous pouvez trouver n'importe quel défaut dans le raisonnement ou les maths, s'il vous plaît laissez - moi savoir.
Dropbox a un article complet sur leur Blog tech où ils décrivent comment ils ont résolu le problème pour leur application de scanner.
https://blogs.dropbox.com/tech/2016/08/fast-document-rectification-and-enhancement /
rectification d'un Document
nous supposons que le document d'entrée est rectangulaire dans le monde physique, mais s'il n'est pas exactement face à la caméra, le les coins résultants de l'image seront un quadrilatère convexe général. Donc pour satisfaire notre premier objectif, nous devons défaire la transformation géométrique appliquée par le processus de capture. Cette transformation dépend du point de vue de la caméra par rapport au document (ce sont les paramètres dits extrinsèques), en plus de choses comme la distance focale de la caméra (les paramètres intrinsèques). Voici un schéma du scénario de capture:
pour défaire le Géométrique transformer, nous devons d'abord déterminer le dit des paramètres. Si nous supposons une caméra bien symétrique( pas d'astigmatisme, pas de biais, et cetera), les inconnues dans ce modèle sont:
- la 3D à l'emplacement de la caméra par rapport au document (3 degrés de liberté),
- l'orientation 3D de la caméra par rapport au document (3 degrés de liberté),
- les dimensions du document (2 degrés de liberté), et
- la distance focale de la caméra (1 degré de liberté).
de l'autre côté, les coordonnées x et y des quatre coins de document détectés nous donnent effectivement huit contraintes. Bien qu'il y ait apparemment plus d'inconnues (9) que de contraintes (8), les inconnues ne sont pas entièrement des variables libres-on pourrait imaginer mettre le document physiquement à l'échelle et le placer plus loin de la caméra, pour obtenir une photo identique. Cette relation place une contrainte supplémentaire, de sorte que nous avons un système complètement contraint à résoudre. (Le système actuel d'équations que nous résolvons implique quelques autres considérations; L'article Wikipedia pertinent donne un bon résumé: https://en.wikipedia.org/wiki/Camera_resectioning )
une fois que les paramètres ont été récupérés, nous pouvons annuler la transformation géométrique appliquée par le processus de capture pour obtenir une belle image rectangulaire. Toutefois, cela est potentiellement un processus qui prend du temps: on cherche, pour chaque pixel de sortie, la valeur du pixel d'entrée correspondant dans l'image source. Bien sûr, les GPU sont spécialement conçus pour des tâches comme celle-ci: rendre une texture dans un espace virtuel. Il existe une vue transform-qui se trouve être l'inverse de la caméra transform que nous venons de résoudre pour!-avec lequel on peut rendre l'image pleine entrée et obtenir le document rectifié. (Une façon facile de voir ceci est de noter qu'une fois que vous avez l'image d'entrée complète sur l'écran de votre téléphone, vous pouvez incliner et de traduire le téléphone telles que la projection du document région sur l'écran apparaît rectiligne.)
enfin, rappelons qu'il y avait une ambiguïté quant à l'échelle: on ne peut pas dire si le document était un papier de format lettre (8.5" x 11") ou un poster (17" x 22"), par exemple. Quelles devraient être les dimensions de l'image de sortie? Pour résoudre cette ambiguïté, nous comptons le nombre de pixels quadrilatère dans l'image d'entrée, et de définir la résolution de sortie pour correspondre à ce nombre de pixels. L'idée est que nous ne voulons pas donner trop d'importance à l'image.
il semble qu'il y ait encore une certaine confusion sur ce problème intéressant. Je tiens à donner une explication facile à suivre pour quand le problème peut et ne peut pas être résolu.
contraintes et degrés de liberté
Généralement lorsque nous sommes confrontés à un problème comme celui-la première chose à faire est d'évaluer le nombre d'inconnues Degrés de Liberté (DoFs) N, et le nombre d'équations indépendantes M que nous avons pour contraindre l'inconnu DoFs. Il est impossible de résoudre le problème si N Si dépasse M (ce qui signifie qu'il y a moins de contraintes que d'inconnues). Nous pouvons exclure tous les problèmes dans ce cas comme étant insolubles. Si N ne dépasse pas M puis peut être possible de résoudre le problème avec une solution unique, mais ce n'est pas garanti (voir l'avant-dernier paragraphe, par exemple).
utilisons p 1, p 2, p 3 et p 4 pour indiquer les positions des 4 coins de la surface planaire en coordonnées mondiales. Utilisons R et t pour être la rotation 3D et la translation qui les transforme en coordonnées de caméra. Utilisons K pour désigner la matrice intrinsèque de la caméra 3x3. Nous ignorerons la distorsion des lentilles pour l'instant. La position 2D du coin i e dans l'image de la caméra est donnée par q i=f( K ( Rp i+ t ) où f est la fonction de projection f(x,y,z)=(x/z,y/z). En utilisant cette équation, nous savons que chaque coin de l'image nous donne deux équations (c.-à-d. deux contraintes) sur nos inconnues: une de la composante x de q i et une de la composante Y. Nous avons donc un total de 8 contraintes à travailler. Le nom officiel de ces les contraintes sont les "contraintes de reprojection .
alors quels sont nos DOF inconnus? Certainement R et t sont inconnus, parce que nous ne connaissons pas la pose de la caméra en coordonnées mondiales. Nous avons donc déjà 6 DOF inconnus: 3 pour R (par ex. lacet, tangage et roulis) et 3 pour t . Par conséquent, il peut y avoir un maximum de deux inconnues dans les autres termes ( K , p 1, p 2, p 3, p 4).
Différents problèmes
nous pouvons construire des problèmes différents en fonction de laquelle deux termes dans ( K , p 1, p 2, p 3, p 4) nous devons considérer comme étant inconnu. À ce point, écrivons K sous la forme habituelle: K =(fx, 0, cx; 0, fy,cy; 0,0,1) où fx et fy sont les termes de Distance focale (Fx/fy est normalement appelé le rapport d'aspect de l'image) et (cx, cy) est le point principal (le centre de projection dans l'image).
nous pourrions obtenir un problème en ayant fx et fy comme nos deux inconnues, et supposer (cx, cy, p 1, p 2, p 3, p 4) sont tous connus. En effet, ce même problème est utilisé et résolu dans le cadre de la méthode de calibration de la caméra OpenCV, en utilisant des images d'une cible planaire en damier. Ceci est utilisé pour obtenir une estimation initiale pour fx et fy, en supposant que le point principal est au centre de l'image (ce qui est une hypothèse très raisonnable pour la plupart des caméras).
nous pouvons aussi créer un problème différent en supposant fx=fy, ce qui est assez raisonnable pour de nombreuses caméras, et supposer que cette Distance focale (indiquée par f) est le seulement inconnu dans K . Par conséquent, nous avons encore un inconnu à jouer avec (rappelez-vous que nous pouvons avoir un maximum de deux inconnues). Donc, nous allons utiliser ceci en supposant que nous avons connu la forme du plan: comme un rectangle (qui était l'hypothèse originale dans la question). Par conséquent, nous pouvons définir les coins comme suit: p 1=(0,0,0), p 2=(0,w,0), p 3=(h,0,0) et p 4=(h,w,0), où h et w représente la hauteur et la largeur du rectangle. Maintenant, puisque nous n'avons plus qu'un inconnu, définissons ceci comme le rapport d'aspect du plan: x=w/H. Maintenant, la question Est de savoir si nous pouvons récupérer simultanément x, f, R et t des 8 contraintes de reprojection? La réponse, il s'avère que c'est oui! Et la solution est donnée dans le journal de Zhang cité dans la question.
L'échelle de l'ambiguïté
on peut se demander si un autre problème peut être résolu: si nous supposons K est connu et les 2 inconnues sont h et W. Peuvent-ils être résolus à partir des équations de reprojection? La réponse est non, et qu'il existe une ambiguïté entre la taille de l'avion et l'avion de la profondeur à la photo. En particulier si nous escaladons les coins p i par s et échelle t par s, alors s annule dans la reprojection des équations. Par conséquent, l'échelle absolue du plan n'est pas récupérable.
il peut y avoir d'autres problèmes avec différentes combinaisons pour les DOF inconnus, par exemple avoir R , t , l'un des principaux composants de point et le plan " s Largeur comme inconnues. Toutefois, il faut se demander quels sont les cas d'utilisation pratique. Néanmoins, je n'ai pas encore vu un ensemble systématique de solutions pour toutes les combinaisons utiles!
autres points
nous pourrions penser que si nous devions ajouter des correspondances de points supplémentaires entre le plan et l'image, ou exploiter les bords du plan, nous pourrions récupérer plus de 8 DOF inconnus. Malheureusement la réponse est non. C'est parce qu'ils n'ajoutent pas de contraintes supplémentaires indépendantes. La raison en est que les 4 coins décrivent complètement la transformation du plan à l'image. Cela peut être vu en ajustant une matrice d'homographie en utilisant les quatre coins, qui peut alors déterminer les positions de tous les autres points sur le plan dans l'image.