Apuntes / Visión por Computador / Apunte 5 de 6

Read in English

Geometría epipolar

Dónde puede aparecer en una segunda imagen un punto visto en la primera, la matriz fundamental que lo dice y cómo estimarla, con figuras interactivas.

m2TFm1 = 0

Dos píxeles pueden ser imágenes del mismo punto del espacio solo si pasan esta prueba.

F = [BC1]×BA+

La matriz fundamental se obtiene de las dos cámaras, o de ocho pares de puntos correspondientes.

En esta página, los puntos se dibujan con tinta roja y las rectas con tinta azul. Usa el punto sobre una recta y la recta que pasa por dos puntos de los apuntes de coordenadas homogéneas, el modelo de cámara de los apuntes de transformaciones 3D, y la matriz de proyección y su centro óptico de los apuntes de calibración de cámaras.

1Dos imágenes de un punto

Una sola imagen no puede decir a qué distancia está un punto. Un píxel m1 fija el rayo en que está su punto del espacio, el rayo que sale del centro óptico C1 y pasa por m1, pero no en qué lugar de ese rayo. Toma ahora una segunda imagen desde otro lugar. Un punto M del espacio aparece en ambas, como m1 en la primera y m2 en la segunda. Dos píxeles así se llaman puntos correspondientes: imágenes del mismo punto del espacio.

Conociendo solo m1, ¿dónde puede estar m2? M está en algún lugar del rayo de m1, y cada punto de ese rayo es un candidato. La segunda cámara ve cada candidato desde su propio centro óptico C2. Una cámara lleva una recta del espacio a una recta de la imagen, así que las imágenes de todos los candidatos están sobre una recta de la segunda imagen. Esa recta es la línea epipolar de m1, ℓ2.

Esta es la restricción epipolar: si m1 y m2 son puntos correspondientes, entonces m2 está sobre la línea epipolar de m1. La restricción es necesaria, pero no suficiente. Todos los píxeles de la línea la cumplen, y solo uno de ellos es la imagen de M. Una tercera imagen puede señalar cuál, como muestran los apuntes de múltiples vistas. Aun así, convierte la búsqueda de m2 en toda la segunda imagen en una búsqueda a lo largo de una línea. En una imagen de N × N píxeles, eso son N candidatos en vez de N2.

2El plano epipolar y los epipolos

Los dos centros ópticos y M están en un mismo plano, el plano epipolar π. Ambos rayos están en él: el rayo de m1 une C1 y M, y el rayo de m2 une C2 y M. Cada plano de imagen corta a π en una recta, y esas dos rectas son las líneas epipolares. Con R1 y R2 para los dos planos de imagen,

ℓ1 = π ∩ R1,  ℓ2 = π ∩ R2

Así, la restricción funciona en ambos sentidos. m1 está sobre ℓ1, la línea epipolar de m2 en la primera imagen.

La recta que pasa por los dos centros ópticos es la línea base. Otro punto M′ del espacio tiene su propio plano epipolar π′, con otras líneas epipolares. Pero todo plano epipolar contiene a C1 y a C2, así que todos contienen la línea base. Por eso todas las líneas epipolares de una imagen pasan por un mismo punto, donde la línea base cruza su plano de imagen. Ese punto es el epipolo de la imagen:

e1 = ⟨C1, C2⟩ ∩ R1,  e2 = ⟨C1, C2⟩ ∩ R2

La línea base pasa por ambos centros, así que e1 es donde la primera cámara ve a C2, y e2 es donde la segunda cámara ve a C1.

El ejemplo

El ejemplo de esta página es una serie de imágenes de rayos X, de 2688 × 2208 píxeles cada una, de un objeto que gira 2° en torno a un eje vertical entre una imagen y la siguiente. La fuente de rayos X hace el papel del centro óptico, como en los apuntes de transformaciones 3D. Vista desde el objeto, la fuente recorre un círculo horizontal. Las imágenes 1 y 82 están a 162° una de otra en ese círculo, así que sus fuentes casi se miran de frente. De ahí salen dos cosas.

  • El plano del círculo contiene ambos centros ópticos, así que es un plano epipolar. Los dos epipolos están sobre la recta en que ese plano corta las imágenes, que es casi una fila de píxeles, en v ≈ 1285.
  • Cada fuente está casi justo enfrente de la otra, así que cada imagen ve la otra fuente, cerca de su borde: los dos epipolos caen dentro de sus imágenes.

3La matriz fundamental a partir de las dos cámaras

Ahora en ecuaciones. Llama A y B a las matrices de proyección generales de las dos cámaras, como en los apuntes de calibración de cámaras. Un punto M = [X Y Z 1]T, en las mismas coordenadas para ambas cámaras, aparece en

λ1m1 = AM,  λ2m2 = BM

El objetivo es la línea epipolar ℓ2 a partir de m1, A y B solamente.

Dos puntos del rayo

ℓ2 es la imagen del rayo de m1, y una recta queda fijada por dos de sus puntos, así que bastan dos puntos del rayo. Uno es C1. Todos los rayos de la primera cámara parten de ahí, así que A lo lleva al vector cero, AC1 = 0, y se puede encontrar a partir de A solamente, como en los apuntes de calibración de cámaras.

El otro punto sale de m1. Cualquier M con AM = m1 se proyecta en m1, así que está sobre el rayo. Tres ecuaciones no fijan cuatro incógnitas, pero la pseudo-inversa de A elige una solución:

M+ = A+m1,  A+ = AT(AAT)−1

AAT es una matriz de 3 × 3, invertible porque A tiene rango 3. Entonces AA+ = AAT(AAT)−1 = I, así que AM+ = m1. El producto en el otro orden, ATA, no serviría: es de 4 × 4 pero sigue teniendo rango 3, así que no tiene inversa.

M+ es un punto distinto de C1, porque A lo lleva a m1, no a 0. De todos los puntos del rayo, es aquel cuyo vector [X Y Z W]T es más corto, lo que lo hace perpendicular a C1 como vector de cuatro números. Esa elección es cosa del álgebra: cualquier otro punto del rayo daría la misma recta.

Sus imágenes en la segunda vista

B proyecta ambos puntos en la segunda imagen:

e2 = BC1,  m2+ = BM+

El primero es el epipolo, la imagen de C1. El segundo es algún punto de ℓ2.

La recta que pasa por ellos

La recta que pasa por dos puntos es su producto cruz, como en los apuntes de coordenadas homogéneas:

ℓ2 = e2 × m2+ = BC1 × BA+m1

El producto cruz con un vector fijo u es lineal en el otro factor, así que es un producto de matriz por vector, u × v = [u]×v, con la matriz antisimétrica

[u]× = 0−u3u2u30−u1−u2u10

Multiplicarla por v = [v1 v2 v3]T da las tres componentes de u × v; la primera es u2v3 − u3v2. Con u = BC1, la recta queda como una matriz por m1:

ℓ2 = Fm1,  F = [BC1]×BA+

La matriz F de 3 × 3 es la matriz fundamental. Depende solo de A y B, no de m1, m2 ni M: una sola matriz da la línea epipolar de cada píxel de la primera imagen.

La restricción epipolar

Un punto está sobre una recta cuando su producto punto es cero, ℓTm = 0, como en los apuntes de coordenadas homogéneas. Así, m2 está sobre ℓ2 = Fm1 exactamente cuando

m2TFm1 = 0

Esa es la restricción epipolar en una sola ecuación, que cumple todo par de puntos correspondientes.

Segunda imagen:

Arrastra m1 en la imagen 1, y ℓ2 gira en torno a e2. Desliza M por su rayo en la vista de abajo, y m2 se desliza por ℓ2. Arrastra m2 fuera de la línea, y los dos rayos dejan de cortarse. Cambia la segunda imagen para mover C2 por el círculo, y arrastra el fondo de la vista de abajo para girarla. Cada imagen se dibuja delante de su fuente, donde la pone el modelo de cámara. Con el teclado, selecciona un punto, la vista de abajo o el campo con Tab y usa las flechas.

4Propiedades de F

Líneas epipolares en la primera imagen

Trasponer la restricción da m1TFTm2 = 0, que dice que m1 está sobre la recta FTm2. Así,

ℓ2 = Fm1,  ℓ1 = FTm2

F lleva puntos de la primera imagen a rectas de la segunda, y FT va en sentido contrario. Intercambiar las cámaras, con B como la primera y A como la segunda, da FT, salvo un factor de escala.

Escala

Para cualquier número k ≠ 0, kF da las mismas rectas y la misma restricción. Así, F es homogénea, como A y B.

Su determinante es 0

[u]×u = u × u = 0, así que [u]× lleva un vector distinto de 0 a 0, y es singular. F la tiene como factor, así que det F = det [BC1]× · det BA+ = 0. Una matriz homogénea de 3 × 3 tiene ocho números libres, y det F = 0 quita uno más: F tiene siete grados de libertad.

Los epipolos

Todas las líneas epipolares de la segunda imagen pasan por e2, así que e2TFm1 = 0 para todo m1. Eso solo puede ocurrir si e2TF es la fila cero, y lo mismo vale para el otro epipolo:

Fe1 = 0,  FTe2 = 0

Fe1 = 0 también tiene una imagen. El rayo de e1 es la propia línea base, que pasa por C2, así que la segunda cámara ve todo el rayo como un solo punto, e2, no como una recta. Y el vector cero no representa ninguna recta.

Estas ecuaciones dan los epipolos a partir de F solamente. FTe2 = 0 dice que e2 es perpendicular a todas las columnas de F, así que es el producto cruz de dos columnas de F, dividido por su tercera componente para leerlo. Del mismo modo, e1 es el producto cruz de dos filas de F.

Dos imágenes desde un mismo centro óptico

Si C2 = C1, entonces BC1 = 0 y F = 0: no hay línea base, ni epipolo, ni línea epipolar. Ambas imágenes muestran entonces los mismos rayos, y se relacionan, en cambio, por una homografía, como en los apuntes de transformaciones 2D.

5La misma F a partir de un determinante

La misma F sale de las dos ecuaciones de proyección sin dibujar ninguna recta. Pasa todos sus términos a la izquierda, AM − λ1m1 = 0 y BM − λ2m2 = 0. Son seis ecuaciones con seis incógnitas, las cuatro componentes de M, λ1 y λ2, y forman un solo sistema Gv = 0:

Am10B0m2M−λ1−λ2 = 0

Aquí G es de 6 × 6: A y B llenan sus cuatro primeras columnas, y m1 y m2 las dos últimas. Si m1 y m2 se corresponden, el punto M del que vienen da una solución v ≠ 0. Un sistema cuadrado con lado derecho 0 tiene una solución distinta de 0 solo cuando su determinante es 0, así que det G = 0.

Desarrolla det G por sus dos últimas columnas, las únicas que contienen los píxeles. Elegir la componente j de m1 elimina la fila j de A, y elegir la componente i de m2 elimina la fila i de B. Cada término es el producto de esas dos componentes por el determinante de 4 × 4 de las filas que quedan: dos filas de A y dos de B. Así, det G es lineal en m1 y lineal en m2, que es justo la forma m2TFm1, con

Fij = (−1)i+j det A sin la fila jB sin la fila i

Para las dos imágenes del ejemplo, esta F es igual a [BC1]×BA+ salvo un factor de escala, hasta once cifras significativas. Además muestra por qué la restricción tiene esta forma y no otra: det G es lineal en cada píxel, sea cual sea la posición de las cámaras.

6Los puntos medidos no caen en la línea

Los píxeles reales se miden y A y B se estiman, así que un par de puntos correspondientes casi nunca cumple m2TFm1 = 0 exactamente: m2 queda cerca de su línea epipolar, no sobre ella. Por eso la restricción se usa con una tolerancia. m2 se acepta como posible correspondiente cuando su distancia a ℓ2 = Fm1 = [a b c]T es menor que cierta d0:

d = |m2TFm1|√(a2 + b2) < d0

Por qué esta es la distancia: (a, b) es perpendicular a la recta ax + by + c = 0. Mover un punto una distancia t en la dirección del vector unitario (a, b)/√(a2 + b2) cambia ax + by + c en t√(a2 + b2), y el valor es 0 sobre la recta. Así, el valor en m2, que es m2TFm1, dividido por √(a2 + b2), es la distancia de m2 a la recta. Una recta escalada para que a2 + b2 = 1 da la distancia directamente, con un signo que indica el lado.

La tolerancia depende de qué tan bien se conocen los píxeles y las cámaras: un píxel o dos para esquinas encontradas por un programa, más para puntos marcados a mano. Con una tercera imagen, la prueba se vuelve mucho más estricta, como muestran los apuntes de múltiples vistas.

7Estimar F a partir de puntos correspondientes

Hasta aquí, F salió de A y B. Cuando las cámaras no están calibradas, F se puede estimar solo a partir de las imágenes, con pares de puntos que se sabe que se corresponden, como la misma esquina encontrada en ambas. Cada par m1 = [x1 y1 1]T, m2 = [x2 y2 1]T cumple m2TFm1 = 0. Al multiplicar,

(F11x1 + F12y1 + F13)x2 + (F21x1 + F22y1 + F23)y2 + F31x1 + F32y1 + F33 = 0

Fij multiplica la componente i de m2 y la componente j de m1, y los píxeles son números conocidos, así que la ecuación es lineal en las nueve entradas de F. Apilándolas fila por fila en f = [F11 F12 … F33]T, cada par da una fila:

[x1x2 y1x2 x2 x1y2 y1y2 y2 x1 y1 1] f = 0

Ocho pares

F es homogénea, así que se puede fijar una entrada, como se hizo con a34 en la calibración: F33 = 1. El último término de cada fila pasa al lado derecho, y las ocho incógnitas que quedan, f′ = [F11 … F32]T, cumplen

Qf′ = r

donde cada fila de Q es [x1x2 y1x2 x2 x1y2 y1y2 y2 x1 y1] y cada entrada de r es −1. Ocho pares dan un sistema cuadrado, que se resuelve como f′ = Q−1r. Con más pares se ajusta por mínimos cuadrados, como en la calibración: f′ = (QTQ)−1QTr.

Fijar F33 = 1 falla solo si el verdadero F33 es 0. F33 es m2TFm1 para m1 = m2 = [0 0 1]T, así que eso ocurre cuando el píxel (0, 0) de la segunda imagen está sobre la línea epipolar del píxel (0, 0) de la primera. La elección también se puede evitar, como con las homografías y la calibración: mantén las nueve incógnitas y resuelve Qf = 0 con ‖f‖ = 1, cuya respuesta es el vector singular derecho de Q con el menor valor singular.

Por qué ocho, si F tiene siete grados de libertad

El método lineal trata las ocho razones de F como independientes. No puede imponer además det F = 0, que no es una condición lineal en las entradas de F, así que necesita ocho ecuaciones. Y una estimación a partir de píxeles medidos no es exactamente singular.

Qué pares

Ocho pares no bastan si sus puntos del espacio están todos en un mismo plano. Los píxeles de un plano en dos imágenes se relacionan por una homografía, como en los apuntes de transformaciones 2D, y entonces Q tiene rango 6 a lo más: toda una familia de matrices cumple cada ecuación. Los puntos deben repartirse en profundidad, fuera de un único plano.

Qué tan sensible es

En píxeles, las columnas de Q tienen tamaños muy distintos: x1x2 llega a 7·106 en imágenes de este tamaño, mientras x1 no pasa de 3000. Las entradas de F difieren en el sentido contrario, y los errores pequeños en los píxeles se amplifican. Con exactamente ocho pares, la estimación hace pasar cada línea epipolar exactamente por su m2, incluso uno erróneo, y las líneas de todos los demás puntos pagan el costo. Más pares, ajustados por mínimos cuadrados, permiten que el ajuste note el erróneo: su línea ya no lo sigue, y las demás se mueven menos.

En la figura de abajo, los pares son puntos del objeto, proyectados en las imágenes 1 y 82 y redondeados a píxeles enteros. El redondeo por sí solo deja las líneas de otros puntos del objeto a 1.10 píxeles de sus verdaderos correspondientes en promedio con ocho pares, y a 0.47 con dieciséis. Mover 30 píxeles hacia abajo el punto del par 3 en la imagen 82 deja clara la diferencia. Con ocho pares, su línea lo sigue exactamente, y las líneas de los demás puntos se desvían 22.38 píxeles en promedio. Con dieciséis, su línea queda a 21.12 píxeles de él, y las demás se desvían solo 2.90.

Selecciona un par haciendo clic en su punto de la imagen 82, y luego arrastra ese punto en el acercamiento, hasta 30 píxeles, como si se hubiera marcado en el lugar equivocado. Las líneas azules son las líneas epipolares que la F estimada da en la imagen 82 para los puntos de la imagen 1. La línea punteada es la verdadera del par seleccionado, a partir de las dos cámaras. En el acercamiento, las líneas de la cuadrícula están a 10 píxeles una de otra. Con el teclado, selecciona el punto de un par con Tab y presiona Enter, luego selecciona el punto del acercamiento y usa las flechas; se mueve un píxel por pulsación.

8Resumen

Las ideas clave junto a sus equivalentes en NumPy. En código, A, B y F son mat_a, mat_b y mat_f, y los píxeles son vectores homogéneos como m1 = np.array([x1, y1, 1]).

Centro óptico
AC1 = 0
c1 = np.linalg.svd(mat_a)[2][-1]
Pseudo-inversa
A+ = AT(AAT)−1, AA+ = I
np.linalg.pinv(mat_a)
El producto cruz como matriz
[u]×v = u × v
def skew(u):
    return np.array([
        [0, -u[2], u[1]],
        [u[2], 0, -u[0]],
        [-u[1], u[0], 0]])
Matriz fundamental
F = [BC1]×BA+
mat_f = skew(mat_b @ c1) @ mat_b \
    @ np.linalg.pinv(mat_a)
Líneas epipolares
ℓ2 = Fm1, ℓ1 = FTm2
ell_2 = mat_f @ m1
ell_1 = mat_f.T @ m2
¿Son correspondientes?
|m2TFm1| / √(a2 + b2) < d0
d = abs(m2 @ ell_2) / np.hypot(
    ell_2[0], ell_2[1])
Epipolos
Fe1 = 0, FTe2 = 0
e2 = np.cross(mat_f[:, 0],
    mat_f[:, 1])
e2 = e2 / e2[2]
Ocho o más pares, F33 = 1
Qf′ = r, f′ = (QTQ)−1QTr
Q = np.column_stack([
    x1*x2, y1*x2, x2, x1*y2,
    y1*y2, y2, x1, y1])
f = np.linalg.lstsq(
    Q, -np.ones(len(Q)),
    rcond=None)[0]
mat_f = np.append(f, 1)
mat_f = mat_f.reshape(3, 3)