Вопрос

Дано двумерное изображение прямоугольника, искаженного перспективой:

enter image description here

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

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

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

Обновить:

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

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

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

  • Чжэнью Чжан, Ли-Вэй Хэ, "Сканирование белой доски и улучшение изображения" http://research.microsoft.com/en-us/um/people/zhang/papers/tr03-39.pdf с.11

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

  • РОБЕРТ М.ХАРАЛИК "Определение параметров камеры по перспективной проекции прямоугольника" http://portal.acm.org/citation.cfm?id=87146

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

Это было полезно?

Решение

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

Я некоторое время манипулировал уравнениями в SAGE и придумал этот псевдокод в стиле си:


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

Обновить:вот как определяются эти уравнения:

Ниже приведен код в МУДРЕЦ.С ним можно ознакомиться онлайн по адресу http://www.sagenb.org/home/pub/704/.(Sage действительно полезен при решении уравнений и может использоваться в любом браузере, проверьте это)

# CALCULATING THE ASPECT RATIO OF A RECTANGLE DISTORTED BY PERSPECTIVE

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

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

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

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

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


# the following equations are later used in calculating the the focal length 
# and the rectangle'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

Другие советы

Обновлять

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

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

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

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

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

alt text alt text

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

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

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

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

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

alt text alt text

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

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

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

На вопрос, почему результаты дают h/w, а не w/h:Мне интересно, правильно ли выражение приведенного выше уравнения 20.Опубликовано:

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

Когда я пытаюсь выполнить это с помощью OpenCV, я получаю исключение.Но все работает правильно, когда я использую следующее уравнение, которое мне больше похоже на уравнение 20:Но, судя по уравнению 20, это выглядит так:

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

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

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

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

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

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

Думаю, сначала нужно провести какую-то калибровку.

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

Чтобы упростить задачу (поскольку нам нужно только соотношение сторон), давайте предположим, что наш прямоугольник определяется следующими точками: R=[(0,0),(1,0),(1,r),(0,r)] (это упрощение равнозначно преобразованию любой задачи к эквивалентной в аффинном пространстве).

Преобразованный многоугольник определяется как: T=[(tx0,ty0),(tx1,ty1),(tx2,ty2),(tx3,ty3)]

Существует матрица преобразования M = [[m00,m01,m02],[m10,m11,m12],[m20,m21,m22]] это удовлетворяет (Rxi,Ryi,1)*M=wi(txi,tyi,1)'

если мы расширим приведенное выше уравнение для точек,

для R_0 мы получаем: m02-tx0*w0 = m12-ty0*w0 = m22-w0 = 0

для R_1 мы получаем: m00-tx1*w1 = m10-ty1*w1 = m20+m22-w1 = 0

для R_2 мы получаем: m00+r*m01-tx2*w2 = m10+r*m11-ty2*w2 = m20+r*m21+m22-w2 = 0

и для R_3 мы получаем: m00+r*m01-tx3*w3 = m10+r*m11-ty3*w3 = m20 + r*m21 + m22 -w3 = 0

На данный момент у нас есть 12 уравнений, 14 неизвестных переменных (9 из матрицы, 4 из wi, и 1 для отношения r), а остальные — известные значения (txi и tyi дано).

Даже если система не была занижена, некоторые неизвестные перемножаются между собой (r и mi0 продукты), делая систему нелинейной (вы можете преобразовать ее в линейную систему, присвоив каждому продукту новое имя, но в итоге вы все равно получите 13 неизвестных, и 3 из них будут расширены до бесконечных решений).

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

В своем техническом блоге Dropbox есть обширная статья, в которой они описывают, как они решили проблему со своим приложением-сканером.

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

Исправление документа

Мы предполагаем, что входной документ имеет прямоугольную форму в физическом мире, но если он не обращен точно к камере, результирующие углы изображения будут представлять собой общий выпуклый четырехугольник.Итак, чтобы достичь нашей первой цели, мы должны отменить геометрическое преобразование, примененное в процессе захвата.Это преобразование зависит от точки зрения камеры относительно документа (это так называемые внешние параметры), а также от таких вещей, как фокусное расстояние камеры (внутренние параметры).Вот схема сценария захвата:

Чтобы отменить геометрическое преобразование, мы должны сначала определить указанные параметры.Если мы предположим, что камера хорошо симметрична (без астигматизма, без перекоса и т. д.), неизвестными в этой модели будут:

  • 3D расположение камеры относительно документа (3 степени свободы),
  • 3D ориентация камеры относительно документа (3 степени свободы),
  • размеры документа (2 степени свободы) и
  • фокусное расстояние камеры (1 степень свободы).

С другой стороны, координаты X и Y четырех обнаруженных углов документа дают нам фактически восемь ограничений.Хотя на первый взгляд неизвестных (9) больше, чем ограничений (8), неизвестные не являются полностью свободными переменными — можно представить себе физическое масштабирование документа и размещение его дальше от камеры, чтобы получить идентичную фотографию.Это соотношение накладывает дополнительное ограничение, поэтому мы имеем полностью ограниченную систему, которую нужно решить.(Фактическая система уравнений, которую мы решаем, включает в себя несколько других соображений;соответствующая статья в Википедии дает хорошее резюме: https://en.wikipedia.org/wiki/Camera_resectioning)

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

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

Кажется, по поводу этой интересной проблемы все еще существует некоторая путаница.Я хочу дать простое объяснение того, когда проблема может и не может быть решена.

Ограничения и степени свободы

Обычно, когда мы сталкиваемся с такой проблемой, первое, что нужно сделать, — это оценить количество неизвестных степеней свободы (DoF) N и количество независимых уравнений M, которые у нас есть для ограничения неизвестных степеней свободы.Невозможно решить задачу, если N превышает M (это означает, что ограничений меньше, чем неизвестных).Мы можем исключить все проблемы, в которых это имеет место, как неразрешимые.Если N не превосходит M, то может возможно решить проблему с помощью единственного решения, но это не гарантируется (пример см. в предпоследнем абзаце).

Давайте использовать п1, п2, п3 и п4 для обозначения положений 4 углов плоской поверхности в мировых координатах.Давайте использовать р и т быть трехмерным вращением и перемещением, которое преобразует их в координаты камеры.Давайте использовать К для обозначения внутренней матрицы камеры 3x3.На данный момент мы будем игнорировать искажения объектива.2D-положение яугол изображения камеры определяется выражением дя = е(К(рупийя+т)) где f — функция проекции f(x,y,z)=(x/z,y/z).Используя это уравнение, мы знаем, что каждый угол изображения дает нам два уравнения (т.е.два ограничения) на наши неизвестные:один из компонента x дя и один из компонента y.Итак, у нас есть в общей сложности 8 ограничений для работы.Официальное название этих ограничений — ограничения перепроецирования.

Так каковы же наши неизвестные глубины резкости?Конечно р и т неизвестны, поскольку мы не знаем положения камеры в мировых координатах.Следовательно, у нас уже есть 6 неизвестных степеней свободы:3 для р (например.рыскание, тангаж и крен) и 3 за т.Следовательно, может быть максимум из два неизвестные в остальных членах (К, п1, п2, п3, п4). 

Различные проблемы

Мы можем строить разные задачи в зависимости от того, какие два члена в (К, п1, п2, п3, п4) будем считать неизвестными.На этом этапе давайте распишем К в обычном виде: К=(FX, 0, CX;0, фй, су;0,0,1), где fx и fy — коэффициенты фокусного расстояния (fx/fy обычно называют соотношением сторон изображения), а (cx,cy) — главная точка (центр проекции изображения).

Мы могли бы получить одну задачу, взяв fx и fy в качестве двух неизвестных и предположив (cx, cy, п1, п2, п3, п4) все известны.Действительно, эта самая проблема используется и решается в методе калибровки камеры OpenCV с использованием изображений плоской цели в виде шахматной доски.Это используется для получения первоначальной оценки fx и fy, предполагая, что главная точка находится в центре изображения (что является очень разумным предположением для большинства камер).

В качестве альтернативы мы можем создать другую проблему, предположив, что fx=fy, что опять же вполне разумно для многих камер, и предположив, что это фокусное расстояние (обозначенное как f) является только неизвестный в К.Поэтому у нас все еще остается одно неизвестное (напомним, что неизвестных может быть максимум два).Итак, давайте воспользуемся этим, предположив, что мы знаем форму плоскости:как прямоугольник (что было исходным предположением в вопросе).Поэтому мы можем определить углы следующим образом: п1=(0,0,0), п2=(0,ш,0), п3=(h,0,0) и п4=(h,w,0), где h и w обозначают высоту и ширину прямоугольника.Теперь, поскольку у нас осталось только 1 неизвестное, давайте установим это соотношение сторон плоскости:х=ш/ч.Теперь вопрос в том, можем ли мы одновременно восстановить x, f, р и т из 8 ограничений перепроецирования?Оказывается, да!И решение дано в статье Чжана, цитируемой в вопросе.

Неоднозначность масштаба

Можно задаться вопросом, можно ли решить еще одну проблему:если мы предположим К известно, а два неизвестных — h и w.Можно ли их решить с помощью уравнений перепроецирования?Ответ — нет, потому что существует неоднозначность между размером плоскости и глубиной плоскости для камеры.В частности, если мы масштабируем углы пя по S и масштабу т на s, то s сокращается в уравнениях перепроецирования.Поэтому абсолютный масштаб плоскости восстановить невозможно.

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

Больше баллов

Мы могли бы подумать, что если бы мы добавили дополнительные соответствия точек между плоскостью и изображением или использовали края плоскости, мы могли бы восстановить более 8 неизвестных степеней свободы.К сожалению, ответ — нет.Это связано с тем, что они не добавляют никаких дополнительных независимых ограничений.Причина в том, что 4 угла описывают полностью преобразование плоскости в изображение.Это можно увидеть, подобрав матрицу гомографии с использованием четырех углов, которая затем может определить положения всех других точек на плоскости изображения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top