web-dev-qa-db-ja.com

透視変形した長方形の比率

遠近法によって歪んだ長方形の2D画像があるとします。

enter image description here

もともと長方形だったのは知っていますが、元の大きさはわかりません。

この写真の角のピクセル座標がわかっている場合、元の比率、つまり長方形の商(幅/高さ)を計算するにはどうすればよいですか?

(背景:目標は、長方形のドキュメントの写真の歪みを自動的に解消することです。エッジ検出は、おそらくハフ変換で行われます)

更新:

与えられた情報で幅:高さの比率を決定することがまったく可能かどうかについて、いくつかの議論がありました。私の素朴な考えは、たとえば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透視投影を使用して、長方形の平面に対するカメラのルックアングルパラメータを決定する方法を示します。」

45
HugoRune

これが論文を読んだ後の私の質問に答える私の試みです

私は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/ 。 (セージは方程式を解くのに本当に便利で、どんなブラウザでも使用できます。チェックしてください)

# CALCULATING THE ASPECT RATIO OF A RECTANGLE DISTORTED BY PERSPECTIVE

#
# BIBLIOGRAPHY:
# [zhang-single]: "Single-View Geometry of A Rectangle 
#  With Application to Whiteboard Image Rectification"
#  by Zhenggyou Zhang
#  http://research.Microsoft.com/users/zhang/Papers/WhiteboardRectification.pdf

# pixel coordinates of the 4 corners of the quadrangle (m1, m2, m3, m4)
# see [zhang-single] figure 1
m1x = var('m1x')
m1y = var('m1y')
m2x = var('m2x')
m2y = var('m2y')
m3x = var('m3x')
m3y = var('m3y')
m4x = var('m4x')
m4y = var('m4y')

# pixel coordinates of the principal point of the image
# for a normal camera this will be the center of the image, 
# i.e. u0=IMAGEWIDTH/2; v0 =IMAGEHEIGHT/2
# This assumption does not hold if the image has been cropped asymmetrically
u0 = var('u0')
v0 = var('v0')

# pixel aspect ratio; for a normal camera pixels are square, so s=1
s = var('s')

# homogenous coordinates of the quadrangle
m1 = vector ([m1x,m1y,1])
m2 = vector ([m2x,m2y,1])
m3 = vector ([m3x,m3y,1])
m4 = vector ([m4x,m4y,1])


# the following equations are later used in calculating the the focal length 
# and the rectangle's aspect ratio.
# temporary variables: k2, k3, n2, n3

# see [zhang-single] Equation 11, 12
k2_ = m1.cross_product(m4).dot_product(m3) / m2.cross_product(m4).dot_product(m3)
k3_ = m1.cross_product(m4).dot_product(m2) / m3.cross_product(m4).dot_product(m2)
k2 = var('k2')
k3 = var('k3')

# see [zhang-single] Equation 14,16
n2 = k2 * m2 - m1
n3 = k3 * m3 - m1


# the focal length of the camera.
f = var('f')
# see [zhang-single] Equation 21
f_ = sqrt(
         -1 / (
          n2[2]*n3[2]*s^2
         ) * (
          (
           n2[0]*n3[0] - (n2[0]*n3[2]+n2[2]*n3[0])*u0 + n2[2]*n3[2]*u0^2
          )*s^2 + (
           n2[1]*n3[1] - (n2[1]*n3[2]+n2[2]*n3[1])*v0 + n2[2]*n3[2]*v0^2
          ) 
         ) 
        )


# standard pinhole camera matrix
# see [zhang-single] Equation 1
A = matrix([[f,0,u0],[0,s*f,v0],[0,0,1]])


#the width/height ratio of the original rectangle
# see [zhang-single] Equation 20
whRatio = sqrt (
               (n2*A.transpose()^(-1) * A^(-1)*n2.transpose()) / 
               (n3*A.transpose()^(-1) * A^(-1)*n3.transpose())
              ) 

によって決定されるcコードの簡略化された方程式

print "simplified equations, assuming u0=0, v0=0, s=1"
print "k2 := ", k2_
print "k3 := ", k3_
print "f  := ", f_(u0=0,v0=0,s=1)
print "whRatio := ", whRatio(u0=0,v0=0,s=1)

    simplified equations, assuming u0=0, v0=0, s=1
    k2 :=  ((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y
    - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
    k3 :=  ((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)/((m3y
    - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x)
    f  :=  sqrt(-((k3*m3y - m1y)*(k2*m2y - m1y) + (k3*m3x - m1x)*(k2*m2x
    - m1x))/((k3 - 1)*(k2 - 1)))
    whRatio :=  sqrt(((k2 - 1)^2 + (k2*m2y - m1y)^2/f^2 + (k2*m2x -
    m1x)^2/f^2)/((k3 - 1)^2 + (k3*m3y - m1y)^2/f^2 + (k3*m3x -
    m1x)^2/f^2))

print "Everything in one equation:"
print "whRatio := ", whRatio(f=f_)(k2=k2_,k3=k3_)(u0=0,v0=0,s=1)

    Everything in one equation:
    whRatio :=  sqrt(((((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
    m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
    1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
    m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
    m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x
    - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - m1y)^2/((((m1y - m4y)*m2x -
    (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
    m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
    m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
    + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
    m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
    - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
    m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
    - m1x)) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
    m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
    1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
    m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
    m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)*m2x/((m2y - m4y)*m3x
    - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - m1x)^2/((((m1y - m4y)*m2x -
    (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
    m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
    m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
    + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
    m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
    - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
    m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
    - m1x)) - (((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
    m1y*m4x)/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) -
    1)^2)/((((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
    m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
    1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
    m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
    m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x
    - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)^2/((((m1y - m4y)*m2x -
    (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
    m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
    m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
    + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
    m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
    - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
    m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
    - m1x)) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
    m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
    1)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y - m1y*m4x)/((m2y -
    m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x) - 1)*(((m1y -
    m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x
    - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) - m1x)^2/((((m1y - m4y)*m2x -
    (m1x - m4x)*m2y + m1x*m4y - m1y*m4x)*m3y/((m3y - m4y)*m2x - (m3x -
    m4x)*m2y + m3x*m4y - m3y*m4x) - m1y)*(((m1y - m4y)*m3x - (m1x -
    m4x)*m3y + m1x*m4y - m1y*m4x)*m2y/((m2y - m4y)*m3x - (m2x - m4x)*m3y
    + m2x*m4y - m2y*m4x) - m1y) + (((m1y - m4y)*m2x - (m1x - m4x)*m2y +
    m1x*m4y - m1y*m4x)*m3x/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y
    - m3y*m4x) - m1x)*(((m1y - m4y)*m3x - (m1x - m4x)*m3y + m1x*m4y -
    m1y*m4x)*m2x/((m2y - m4y)*m3x - (m2x - m4x)*m3y + m2x*m4y - m2y*m4x)
    - m1x)) - (((m1y - m4y)*m2x - (m1x - m4x)*m2y + m1x*m4y -
    m1y*m4x)/((m3y - m4y)*m2x - (m3x - m4x)*m2y + m3x*m4y - m3y*m4x) -
    1)^2))


# some testing:
# - choose a random rectangle, 
# - project it onto a random plane,
# - insert the corners in the above equations,
# - check if the aspect ratio is correct.

from sage.plot.plot3d.transform import rotate_arbitrary

#redundandly random rotation matrix
Rand_rotMatrix = \
           rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5)) *\
           rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5)) *\
           rotate_arbitrary((uniform(-5,5),uniform(-5,5),uniform(-5,5)),uniform(-5,5))

#random translation vector
Rand_transVector = vector((uniform(-10,10),uniform(-10,10),uniform(-10,10))).transpose()

#random rectangle parameters
Rand_width =uniform(0.1,10)
Rand_height=uniform(0.1,10)
Rand_left  =uniform(-10,10)
Rand_top   =uniform(-10,10)

#random focal length and principal point
Rand_f  = uniform(0.1,100)
Rand_u0 = uniform(-100,100)
Rand_v0 = uniform(-100,100)

# homogenous standard pinhole projection, see [zhang-single] Equation 1
hom_projection = A * Rand_rotMatrix.augment(Rand_transVector)

# construct a random rectangle in the plane z=0, then project it randomly 
Rand_m1hom = hom_projection*vector((Rand_left           ,Rand_top            ,0,1)).transpose()
Rand_m2hom = hom_projection*vector((Rand_left           ,Rand_top+Rand_height,0,1)).transpose()
Rand_m3hom = hom_projection*vector((Rand_left+Rand_width,Rand_top            ,0,1)).transpose()
Rand_m4hom = hom_projection*vector((Rand_left+Rand_width,Rand_top+Rand_height,0,1)).transpose()

#change type from 1x3 matrix to vector
Rand_m1hom = Rand_m1hom.column(0)
Rand_m2hom = Rand_m2hom.column(0)
Rand_m3hom = Rand_m3hom.column(0)
Rand_m4hom = Rand_m4hom.column(0)

#normalize
Rand_m1hom = Rand_m1hom/Rand_m1hom[2]
Rand_m2hom = Rand_m2hom/Rand_m2hom[2]
Rand_m3hom = Rand_m3hom/Rand_m3hom[2]
Rand_m4hom = Rand_m4hom/Rand_m4hom[2]

#substitute random values for f, u0, v0
Rand_m1hom = Rand_m1hom(f=Rand_f,s=1,u0=Rand_u0,v0=Rand_v0)
Rand_m2hom = Rand_m2hom(f=Rand_f,s=1,u0=Rand_u0,v0=Rand_v0)
Rand_m3hom = Rand_m3hom(f=Rand_f,s=1,u0=Rand_u0,v0=Rand_v0)
Rand_m4hom = Rand_m4hom(f=Rand_f,s=1,u0=Rand_u0,v0=Rand_v0)

# printing the randomly choosen values
print "ground truth: f=", Rand_f, "; ratio=", Rand_width/Rand_height

# substitute all the variables in the equations:
print "calculated: f= ",\
f_(k2=k2_,k3=k3_)(s=1,u0=Rand_u0,v0=Rand_v0)(
  m1x=Rand_m1hom[0],m1y=Rand_m1hom[1],
  m2x=Rand_m2hom[0],m2y=Rand_m2hom[1],
  m3x=Rand_m3hom[0],m3y=Rand_m3hom[1],
  m4x=Rand_m4hom[0],m4y=Rand_m4hom[1],
),"; 1/ratio=", \
1/whRatio(f=f_)(k2=k2_,k3=k3_)(s=1,u0=Rand_u0,v0=Rand_v0)(
  m1x=Rand_m1hom[0],m1y=Rand_m1hom[1],
  m2x=Rand_m2hom[0],m2y=Rand_m2hom[1],
  m3x=Rand_m3hom[0],m3y=Rand_m3hom[1],
  m4x=Rand_m4hom[0],m4y=Rand_m4hom[1],
)

print "k2 = ", k2_(
  m1x=Rand_m1hom[0],m1y=Rand_m1hom[1],
  m2x=Rand_m2hom[0],m2y=Rand_m2hom[1],
  m3x=Rand_m3hom[0],m3y=Rand_m3hom[1],
  m4x=Rand_m4hom[0],m4y=Rand_m4hom[1],
), "; k3 = ", k3_(
  m1x=Rand_m1hom[0],m1y=Rand_m1hom[1],
  m2x=Rand_m2hom[0],m2y=Rand_m2hom[1],
  m3x=Rand_m3hom[0],m3y=Rand_m3hom[1],
  m4x=Rand_m4hom[0],m4y=Rand_m4hom[1],
)

# ATTENTION: testing revealed, that the whRatio 
# is actually the height/width ratio, 
# not the width/height ratio
# This contradicts [zhang-single]
# if anyone can find the error that caused this, I'd be grateful

    ground truth: f= 72.1045134124554 ; ratio= 3.46538779959142
    calculated: f=  72.1045134125 ; 1/ratio= 3.46538779959
    k2 =  0.99114614987 ; k3 =  1.57376280159
28
HugoRune

更新

アップデートを読み、最初のリファレンス(ホワイトボードのスキャンと画像の強調)を確認すると、欠落しているポイントがどこにあるかがわかります。

問題の入力データは、4倍(A、B、C、D)、[〜#〜]および[〜#〜]投影された画像の中心Oです。この記事では、u0 = v0 = 0という仮定に対応しています。この点を追加すると、問題は長方形のアスペクト比を取得するのに十分に制約されます。

次に、問題を次のように言い換えます。Z= 0平面に4つ(A、B、C、D)がある場合、目の位置E(0,0、h)、h> 0、および3D平面Pを次のように見つけます。 Pへの(A、B、C、D)の射影は長方形です。

PはEによって決定されることに注意してください。平行四辺形を取得するには、Pに(EU)および(EV)への平行四辺形が含まれている必要があります。ここでU =(AB)x(CD)およびV =(AD)x(BC)です。

実験的に、この問題には一般に、長方形のw/h比の一意の値に対応する1つの一意の解決策があるようです。

alt textalt text

前の投稿

いいえ、投影から長方形の比率を決定することはできません。

一般的なケースでは、Z = 0平面の4つの非同一線上の点の4倍(A、B、C、D)は、無限に多くの幅/高さの比率を持つ無限に多くの長方形の投影です。

(AB)と(CD)とVの交点である2つの消失点U、(AD)と(BC)の交点、および2つの対角線(AC)と(BD)の交点である点Iについて考えてみます。 ABCDとして投影するには、中心Iの平行四辺形が点Iを通る(UV)に平行な線を含む平面上にある必要があります。そのような平面の1つに、ABCDに投影する多くの長方形があります。すべて異なるw/h比です。

Cabri3Dで行われたこれらの2つの画像を参照してください。 2つのケースでは、ABCDは変更されておらず(灰色のZ = 0平面上)、長方形を含む青い平面も変更されていません。部分的に隠されている緑色の線は(UV)線であり、表示されている緑色の線はそれに平行であり、Iを含んでいます。

alt textalt text

7
Eric Bainville

結果がw/hではなくh/wを与える理由の質問について:上記の式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)
           )
1
HooKooDooKu

この答えによって幅/高さを決定できます その影の座標で長方形の3D座標を計算しますか? 。長方形が交差点の対角線上で回転すると仮定して、幅と高さを計算します。しかし、仮定の影の平面と実際の影の平面の間の距離を長方形に比例して変更すると、計算された幅/高さと同じになります!

1
Ivan.s

サイズは実際には必要ありませんし、プロポーションも必要ありません。そして、彼がドキュメントの写真/スキャンを使用していることを考えると、どちら側が上かを知ることは、一種の無関係です。彼がそれらの裏側をスキャンしようとしているのではないかと思います。

「コーナー交差点」は遠近法を修正する方法です。これは役立つかもしれません:

遠近法を描く方法-2Dで正しいグリッド

1
Neil N

「カメラ」の距離を知らずにこの長方形の幅を知ることは不可能です。

5センチメートルの距離から見た小さな長方形は、メートル離れたところから見た大きな長方形と同じように見えます

0
Toad

これらの2つの消失点と地平線の下(つまり、長方形と同じ地平線の側)に3番目の点がある直角二等辺三角形を描画します。その3番目の点が原点になり、消失点への2本の線が軸になります。原点から消失点までの距離をpi/2と呼びます。次に、長方形の辺を消失点から軸まで延長し、それらが軸と交差する場所にマークを付けます。軸を選択し、2つのマークから原点までの距離を測定し、それらの距離を変換します:x-> tan(x)。差はその辺の「真の」長さになります。他の軸についても同じようにします。これらの2つの長さの比率をとると、完了です。

0
Beta

Dropboxの技術ブログには、スキャナーアプリの問題をどのように解決したかを説明する広範な記事があります。

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

ドキュメントの修正

入力ドキュメントは物理的な世界では長方形であると想定していますが、カメラに正確に向いていない場合、画像の結果のコーナーは一般的な凸四角形になります。したがって、最初の目標を達成するには、キャプチャプロセスによって適用された幾何学的変換を元に戻す必要があります。この変換は、カメラの焦点距離(固有パラメーター)などに加えて、ドキュメントに対するカメラの視点(これらはいわゆる外部パラメーター)に依存します。キャプチャシナリオの図は次のとおりです。

幾何学的変換を元に戻すには、最初に前述のパラメータを決定する必要があります。対称性の高いカメラ(非点収差やスキューなどがない)を想定した場合、このモデルの未知数は次のとおりです。

  • ドキュメントに対するカメラの3D位置(3自由度)、
  • ドキュメントに対するカメラの3D方向(3自由度)、
  • ドキュメントの寸法(2自由度)、および
  • カメラの焦点距離(1自由度)。

反対に、検出された4つのドキュメントコーナーのx座標とy座標は、事実上8つの制約を与えます。制約(8)よりも未知数(9)の方が多いように見えますが、未知数は完全に自由変数ではありません。同じ写真を取得するために、ドキュメントを物理的に拡大縮小してカメラから遠ざけることを想像できます。この関係は追加の制約を課すので、完全に制約されたシステムを解決する必要があります。 (私たちが解く実際の連立方程式には、他にもいくつかの考慮事項があります。関連するウィキペディアの記事に良い要約があります: https://en.wikipedia.org/wiki/Camera_resectioning

パラメータが復元されたら、キャプチャプロセスによって適用された幾何学的変換を元に戻して、ニースの長方形の画像を取得できます。ただし、これは潜在的に時間のかかるプロセスです。出力ピクセルごとに、ソース画像内の対応する入力ピクセルの値を検索します。もちろん、GPUは、仮想空間でテクスチャをレンダリングするようなタスク用に特別に設計されています。ビュー変換が存在します。これは、たまたま解決したカメラ変換の逆です。これを使用して、入力画像全体をレンダリングし、修正されたドキュメントを取得できます。 (これを確認する簡単な方法は、電話の画面に完全な入力画像が表示されたら、画面上のドキュメント領域の投影が直線的に見えるように電話を傾けて移動できることに注意することです。)

最後に、スケールに関してあいまいさがあったことを思い出してください。たとえば、ドキュメントがレターサイズの紙(8.5 "x 11")なのかポスターボード(17 "x 22")なのかわかりません。出力画像のサイズはどうあるべきですか?このあいまいさを解決するために、入力画像の四辺形内のピクセル数をカウントし、このピクセル数に一致するように出力解像度を設定します。画像をアップサンプリングまたはダウンサンプリングしすぎないようにするという考え方です。

0
adius

この興味深い問題については、まだ混乱が生じているようです。問題が解決できる場合とできない場合について、わかりやすい説明をしたいと思います。

制約と自由度

通常、このような問題に直面した場合、最初に行うことは、未知の自由度(DoF)Nの数と、未知のDoFを制約するために持つ独立方程式Mの数を評価することです。 NがMを超える場合(未知数よりも制約が少ないことを意味します)、問題を解決することは不可能です。これが当てはまる場合、すべての問題を解決できないものとして除外できます。 NがMを超えない場合、独自の解決策で問題を解決できる可能性がありますが、これは保証されません(最後から2番目の段落を参照)例として)。

p 1、p 2、p 3、p 4を使用して、の4つの角の位置を示します。世界座標の平面。 [〜#〜] r [〜#〜]およびtを使用して、これらをカメラ座標に変換する3D回転および平行移動にしましょう。 [〜#〜] k [〜#〜]を使用して、3x3カメラの固有のマトリックスを示しましょう。レンズの歪みは今のところ無視します。カメラの画像のi番目のコーナーの2D位置は、q i = f([ 〜#〜] k [〜#〜]Rp i + t))ここで、fは射影関数f(x、y、z)=(x/z、y/z)。この方程式を使用すると、画像の各コーナーで未知数に関する2つの方程式(つまり、2つの制約)が得られることがわかります。1つはq iのx成分から、もう1つはy成分からです。したがって、合計8つの制約を処理する必要があります。これらの制約の正式名称は、再投影制約です。

では、未知のDoFは何ですか?確かに[〜#〜] r [〜#〜]tは不明です。これは、世界座標でのカメラのポーズがわからないためです。したがって、すでに6つの未知のDoFがあります。3つは[〜#〜] r [〜#〜](例:ヨー、ピッチ、ロール)、3つはtです。したがって、残りの用語([〜#〜] k [〜#〜]には、最大2の未知数が存在する可能性があります。 、p 1、p 2、p 3、p 4)。

さまざまな問題

[〜#〜] k [〜#〜]p 1、p 2のどの2つの項に応じて、さまざまな問題を構築できます。 、p 3、p 4)不明と見なします。この時点で、[〜#〜] k [〜#〜]を通常の形式で書きましょう:[〜#〜] k [〜#〜]=(fx 、0、cx; 0、fy、cy; 0,0,1)ここで、fxとfyは焦点距離の項(fx/fyは通常画像のアスペクト比と呼ばれます)であり、(cx、cy)は主点(画像の投影の中心)。

Fxとfyを2つの未知数として持つことで、1つの問題を取得でき、(cx、cy、p 1、p 2、p 3、p 4)はすべて既知です。実際、この問題は、チェッカーボードの平面ターゲットの画像を使用して、OpenCVのカメラキャリブレーション方法で使用および解決されています。これは、主点が画像の中心にあると仮定して、fxとfyの初期推定値を取得するために使用されます(これはほとんどのカメラにとって非常に合理的な仮定です)。

あるいは、fx = fyと仮定して別の問題を作成することもできます。これも多くのカメラにとって非常に合理的であり、この焦点距離(fで示される)はonly不明[〜#〜] k [〜#〜]。したがって、まだ1つの未知数が残っています(最大2つの未知数を持つことができることを思い出してください)。それで、平面の形状が長方形としてわかっていると仮定して、これを使用しましょう(これは質問の元の仮定でした)。したがって、コーナーを次のように定義できます。p 1 =(0,0,0)、p 2 =(0、w、0)、p 3 =(h、0,0)およびp 4 =(h、w、0)、ここで、hおよびwは長方形の高さと幅を示します。不明なものが1つしか残っていないので、これを平面のアスペクト比x = w/hとして設定します。ここで問題は、8つの再投影制約からx、f、[〜#〜] r [〜#〜]tを同時に回復できるかどうかです。答えはイエスです!そして、解決策は、質問で引用された張の論文に記載されています。

スケールのあいまいさ

別の問題を解決できるかどうか疑問に思うかもしれません。[〜#〜] k [〜#〜]が既知であり、2つの未知数がhとwであると仮定した場合。それらは再射影方程式から解くことができますか?答えはノーです。飛行機のサイズとカメラまでの飛行機の深さの間にあいまいさが存在するためです。具体的には、コーナーをスケーリングする場合p iをsでスケーリングし、tをsでスケーリングすると、sは再射影方程式でキャンセルされます。したがって、平面の絶対スケールは回復できません。

未知のDoFのさまざまな組み合わせには、他の問題がある可能性があります。たとえば、主要なポイントコンポーネントの1つである[〜#〜] r [〜#〜]t平面の幅は不明です。ただし、どのケースが実用的であるかを考える必要があります。それでも、すべての有用な組み合わせに対する体系的なソリューションのセットはまだ見ていません。

その他のポイント

平面と画像の間にポイントの対応を追加したり、平面のエッジを利用したりすると、8つ以上の未知のDoFを回復できると考えるかもしれません。悲しいことに、答えはノーです。これは、独立した制約が追加されていないためです。その理由は、4つのコーナーが平面から画像への変換を完全に記述しているためです。これは、4つのコーナーを使用してホモグラフィ行列をフィッティングすることで確認できます。これにより、画像内の平面上の他のすべてのポイントの位置を決定できます。

0
Toby Collins

より多くの情報が必要です。その変換された図は、任意の視点が与えられた任意の平行四辺形から得られる可能性があります。

したがって、最初に何らかのキャリブレーションを行う必要があると思います。

編集:私が間違っていると言った人のために、同じ射影をもたらす長方形/カメラの無限の組み合わせがあるという数学的証明がここにあります:

問題を単純化するために(辺の比率のみが必要なので)、長方形が次の点で定義されていると仮定しましょう: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、wiから4、比率rに対して1)があり、残りは既知の値です(txityiが指定されています)。

システムが過小指定されていなくても、未知数の一部(rおよびmi0製品)がそれらの間で乗算され、システムが非線形になります(各製品に新しい名前を割り当てる線形システムに変換できますが、あなたはまだ13の未知数で終わり、そのうちの3つは無限の解に拡張されます)。

推論や数学に欠陥を見つけたら、私に知らせてください。

0
fortran