Python OpenCV: geometría epipolar

La configuración general de la geometría epipolar. La región gris es el plano epipolar. La línea naranja es la línea base, mientras que las dos líneas azules son las líneas epipolares.

Python-OpenCV-Epipolar-Geometry

A menudo, en la geometría de vista múltiple, existen relaciones interesantes entre las múltiples cámaras, un punto 3D y las proyecciones de ese punto en cada uno de los planos de imagen de la cámara. La geometría que relaciona las cámaras, los puntos en 3D y las observaciones correspondientes se denomina geometría epipolar de un par estéreo.

La configuración de geometría epipolar estándar involucra dos cámaras que observan el mismo punto 3D P, cuya proyección en cada uno de los planos de la imagen se ubica en p y p’ respectivamente. Los centros de las cámaras están ubicados en O1 y O2, y la línea entre ellos se denomina línea base. Llamamos al plano definido por los dos centros de cámara y P el plano epipolar. Las ubicaciones donde la línea de base se cruza con los dos planos de la imagen se conocen como epipolos e y e’. Finalmente, las líneas definidas por la intersección del plano epipolar y los dos planos de la imagen se conocen como líneas epipolares. Las líneas epipolares tienen la propiedad de que se cruzan con la línea de base en los respectivos epipolos en el plano de la imagen.

Python-OpenCV-Epipolar-Geometry
When the two image planes are parallel, then the epipoles e and e’ are located at infinity. Notice that the epipolar lines are parallel to u axis of each image plane.

En la Figura 4 se muestra un caso interesante de geometría epipolar, que ocurre cuando los planos de la imagen son paralelos entre sí. Cuando los planos de la imagen son paralelos entre sí, entonces los epipolos e y e’ estarán situados en el infinito ya que la línea de base que une los centros O1, O2 es paralela a los planos de la imagen. Otro subproducto importante de este caso es que las líneas epipolares son paralelas a un eje de cada plano de imagen. Este caso es especialmente útil y se tratará con mayor detalle en el siguiente apartado sobre rectificación de imágenes.

En situaciones del mundo real, sin embargo, no se nos da la ubicación exacta de la ubicación 3D P, pero podemos determinar su proyección en uno de los planos de imagen p. También deberíamos poder conocer las ubicaciones, orientaciones y arrays de la cámara. ¿Qué podemos hacer con este conocimiento? Con el conocimiento de las ubicaciones de las cámaras O1, O2 y el punto de imagen p, podemos definir el plano epipolar. Con este plano epipolar podemos entonces determinar las líneas epipolares1. Por definición, la proyección de P en la segunda imagen p0 debe ubicarse en la línea epipolar de la segunda imagen. Por lo tanto, una comprensión básica de la geometría epipolar nos permite crear una fuerte restricción entre pares de imágenes sin conocer la estructura 3D de la escena.

Python-OpenCV-Epipolar-Geometry
The setup for determining the essential and fundamental matrices, which help map points and epipolar lines across views.

Ahora intentaremos desarrollar formas sencillas de hacer puntos de mapa y líneas epipolares a través de las vistas. Si tomamos la configuración proporcionada en el marco de geometría epipolar original (Figura 5), ​​definiremos además M y M0 para que sean las arrays de proyección de cámara que mapean puntos 3D en sus respectivas ubicaciones de plano de imagen 2D. Supongamos que el sistema de referencia mundial está asociado a la primera cámara con la segunda cámara oset primero por una rotación R y luego por una traslación T. Esto especifica que las arrays de proyección de la cámara sean:

M = K[I 0]   M' = K'[R T]

Ahora encontramos Array Fundamental (F) y Array Esencial (E) . Essential Matrix contiene la información sobre traslación y rotación, que describe la ubicación de la segunda cámara en relación con la primera en coordenadas globales.

Fundamental Matrix contiene información equivalente a Essential Matrix además del conocimiento sobre los intrínsecos de ambas cámaras para que podamos relacionar las 2 cámaras en coordenadas de píxeles. (Si estamos usando imágenes rectificadas y normalizamos el punto dividiendo por las distancias focales, F=E). En palabras sencillas, la Array Fundamental F asigna cierta extensión de una imagen a una línea (epilina) dentro de la otra imagen. Esto se calcula a partir de los puntos coincidentes de ambas imágenes. Se requiere un mínimo de 8 de esos puntos para buscar la array elemental (mientras se usa el algoritmo de 8 puntos). Se prefieren más puntos y se usa RANSAC para instar a un resultado más sólido.

Entonces, primero debemos encontrar tantas coincidencias posibles entre dos imágenes para encontrar la array fundamental. Para esto, usamos descriptores SIFT con emparejador basado en FLANN y prueba de proporción.

import numpy as np
import cv2
from matplotlib import pyplot as plt
   
# Load the left and right images
# in gray scale
imgLeft = cv2.imread('image_l.png', 
                     0)
imgRight = cv2.imread('image_r.png',
                      0)
   
# Detect the SIFT key points and 
# compute the descriptors for the 
# two images
sift = cv2.xfeatures2d.SIFT_create()
keyPointsLeft, descriptorsLeft = sift.detectAndCompute(imgLeft,
                                                       None)
  
keyPointsRight, descriptorsRight = sift.detectAndCompute(imgRight,
                                                         None)
   
# Create FLANN matcher object
FLANN_INDEX_KDTREE = 0
indexParams = dict(algorithm=FLANN_INDEX_KDTREE,
                   trees=5)
searchParams = dict(checks=50)
flann = cv2.FlannBasedMatcher(indexParams,
                              searchParams)
   
  
# Apply ratio test
goodMatches = []
ptsLeft = []
ptsRight = []
   
for m, n in matches:
      
    if m.distance < 0.8 * n.distance:
          
        goodMatches.append([m])
        ptsLeft.append(keyPointsLeft[m.trainIdx].pt)
        ptsRight.append(keyPointsRight[n.trainIdx].pt)

Imagen izquierda
Python-OpenCV-Epipolar-Geometry
Imagen derecha
Python-OpenCV-Epipolar-Geometry

Notemos la Matrix básica.

          
ptsLeft = np.int32(ptsLeft)
ptsRight = np.int32(ptsRight)
F, mask = cv2.findFundamentalMat(ptsLeft,
                                 ptsRight,
                                 cv2.FM_LMEDS)
  
# We select only inlier points
ptsLeft = ptsLeft[mask.ravel() == 1]
ptsRight = ptsRight[mask.ravel() == 1]

A continuación, encontramos las epilinas. Las epilíneas correspondientes a los puntos de la primera imagen se dibujan en la segunda imagen. Así que mencionar las imágenes correctas es importante aquí. Obtenemos una array de líneas. Entonces definimos una nueva función para dibujar estas líneas en las imágenes.

def drawlines(img1, img2, lines, pts1, pts2):
    
    r, c = img1.shape
    img1 = cv2.cvtColor(img1, cv2.COLOR_GRAY2BGR)
    img2 = cv2.cvtColor(img2, cv2.COLOR_GRAY2BGR)
      
    for r, pt1, pt2 in zip(lines, pts1, pts2):
          
        color = tuple(np.random.randint(0, 255,
                                        3).tolist())
          
        x0, y0 = map(int, [0, -r[2] / r[1] ])
        x1, y1 = map(int, 
                     [c, -(r[2] + r[0] * c) / r[1] ])
          
        img1 = cv2.line(img1, 
                        (x0, y0), (x1, y1), color, 1)
        img1 = cv2.circle(img1,
                          tuple(pt1), 5, color, -1)
        img2 = cv2.circle(img2, 
                          tuple(pt2), 5, color, -1)
    return img1, img2

Ahora encontramos las epilinas en ambas imágenes y las dibujamos.

# Find epilines corresponding to points
# in right image (second image) and
# drawing its lines on left image
linesLeft = cv2.computeCorrespondEpilines(ptsRight.reshape(-1,
                                                           1,
                                                           2),
                                          2, F)
linesLeft = linesLeft.reshape(-1, 3)
img5, img6 = drawlines(imgLeft, imgRight, 
                       linesLeft, ptsLeft,
                       ptsRight)
   
# Find epilines corresponding to 
# points in left image (first image) and
# drawing its lines on right image
linesRight = cv2.computeCorrespondEpilines(ptsLeft.reshape(-1, 1, 2), 
                                           1, F)
linesRight = linesRight.reshape(-1, 3)
  
img3, img4 = drawlines(imgRight, imgLeft, 
                       linesRight, ptsRight,
                       ptsLeft)
   
plt.subplot(121), plt.imshow(img5)
plt.subplot(122), plt.imshow(img3)
plt.show()

Producción:
Python-OpenCV-Epipolar-Geometry

Publicación traducida automáticamente

Artículo escrito por gauravmoney26 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *