Característica de OpenCV para múltiples imágenes

¿Cómo puedo optimizar la coincidencia de la función SIFT para muchas imágenes utilizando FLANN?

Tengo un ejemplo de trabajo tomado de los documentos de Python OpenCV. Sin embargo, esto es comparar una imagen con otra y es lento. Lo necesito para buscar características que coincidan en una serie de imágenes (unos pocos miles) y necesito que sea más rápido.

Mi idea actual:

  1. Ejecutar a través de todas las imágenes y guardar las características. ¿Cómo?
  2. Compara una imagen de una cámara con esta sobre la base y encuentra la correcta. ¿Cómo?
  3. Dame el resultado, emparejando imagen o algo.

http://docs.opencv.org/trunk/doc/py_tutorials/py_feature2d/py_feature_homography/py_feature_homography.html

 Importar sys # Para depuración solamente
 importar numpy como np
 importar cv2
 desde matplotlib importar pyplot as plt

 MIN_MATCH_COUNT = 10

 img1 = cv2.imread ('image.jpg', 0) # queryImage
 img2 = cv2.imread ('target.jpg', 0) # trainImage

 # Inicia el detector SIFT
 sift = cv2.SIFT ()

 # encontrar los puntos clave y descriptores con SIFT
 kp1, des1 = sift.detectAndCompute (img1, Ninguno)
 kp2, des2 = sift.detectAndCompute (img2, Ninguno)

 FLANN_INDEX_KDTREE = 0
 index_params = dict (algoritmo = FLANN_INDEX_KDTREE, árboles = 5)
 search_params = dict (cheques = 50)

 flann = cv2.FlannBasedMatcher (index_params, search_params)

 coincide = flann.knnMatch (des1, des2, k = 2)

 # almacene todas las buenas coincidencias según la prueba de relación de Lowe's.
 bien = []
 para m, n en los partidos:
     si m.distance MIN_MATCH_COUNT:
     src_pts = np.float32 ([kp1 [m.queryIdx] .pt para m en bien]). remodelar (-1,1,2)
     dst_pts = np.float32 ([kp2 [m.trainIdx] .pt para m en bien]). remodelar (-1,1,2)

     M, mask = cv2.findHomography (src_pts, dst_pts, cv2.RANSAC, 5.0)
     matchesMask = mask.ravel (). tolist ()

     h, w = img1.shape
     pts = np.float32 ([[0,0], [0, h-1], [w-1, h-1], [w-1,0]]). remodelar (-1,1,2)
     dst = cv2.perspectiveTransform (pts, M)

     img2 = cv2.polylines (img2, [np.int32 (dst)], True, 255,3, cv2.LINE_AA)

 más:
     print "No se encontraron suficientes coincidencias -% d /% d"% (len (bueno), MIN_MATCH_COUNT)
     matchesMask = Ninguno

 draw_params = dict (matchColor = (0,255,0), # dibujar coincidencias en color verde
                    singlePointColor = Ninguno,
                    matchesMask = matchesMask, # draw solo inliers
                    banderas = 2)

 img3 = cv2.drawMatches (img1, kp1, img2, kp2, bueno, Ninguno, ** draw_params)

 plt.imshow (img3, 'gris'), plt.show ()

ACTUALIZAR

Después de probar muchas cosas podría haber estado más cerca de la solución ahora. Espero que sea posible construir el índice y luego buscarlo de esta manera:

 flann_params = dict (algoritmo = 1, árboles = 4)
 flann = cv2.flann_Index (npArray, flann_params)
 idx, dist = flann.knnSearch (queryDes, 1, params = {})

Sin embargo, todavía no he logrado comstackr un npArray aceptado para el parámetro flann_Index.

 recorrer todas las imágenes como imagen:
   npArray.append (sift.detectAndCompute (imagen, Ninguna))
 npArray = np.array (npArray)

Nunca resolví esto en Python, sin embargo, cambié el entorno a C ++, donde obtienes más ejemplos de OpenCV y no tengo que usar un contenedor con menos documentación.

Puede encontrar un ejemplo del problema que tuve con la coincidencia en varios archivos aquí: https://github.com/Itseez/opencv/blob/2.4/samples/cpp/matching_to_many_images.cpp

Aquí hay varias piezas de mi consejo:

  1. Debe reducir la cantidad de datos de puntos utilizando técnicas adecuadas.
  2. Calcular la imagen de referencia repetidamente es un desperdicio. Debes persistir toda referencia calculada.
  3. No ponga el cálculo en un dispositivo móvil. Será mejor que cargue la referencia calculada de una imagen capturada a un servidor potente y haga la búsqueda allí.

Este es un tema muy interesante. Mis oídos se están abriendo también.

Junto con la respuesta de @stanleyxu2005, me gustaría agregar algunos consejos sobre cómo hacer todo el emparejamiento ya que actualmente estoy trabajando en algo así.

  1. Recomiendo encarecidamente crear una clase personalizada que se ajuste al cv :: Mat, pero que también almacene otros datos esenciales. En mi caso, tengo un ImageContainer que almacena la imagen original (que usaré para la costura final), la procesada (en escala de grises, sin distorsión, etc.), sus puntos clave y los descriptores para ellos. Al hacerlo, puede acceder a toda la información relevante para la coincidencia de forma bastante bien organizada. Puede implementar la extracción de punto clave y la generación de descriptores en él o hacerlo fuera de la clase y simplemente almacenar los resultados en ese contenedor.
  2. Almacene todos los contenedores de imágenes en algún tipo de estructura (por lo general, el vector es una buena opción) para un fácil acceso.
  3. También creé una clase llamada ImageMultiMatchContainer, que almacena un puntero a una imagen de consulta determinada (todas las imágenes son imágenes de consulta), un vector con punteros a todas las imágenes de trenes (para una única imagen de consulta del conjunto de imágenes, todas las demás son imágenes de trenes) que coincidieron con él y también un vector de los vectores de coincidencia para cada uno de esos partidos. Aquí me topé con un problema de almacenamiento: primero, debe omitir la coincidencia de una imagen consigo misma porque no tiene sentido y, segundo, tiene el problema de comparar dos imágenes dos veces y generar una sobrecarga considerable si tiene muchas imágenes. El segundo problema se debe al hecho de que recorremos todas las imágenes (imágenes de consulta) y las comparamos con el rest del conjunto (imágenes de trenes). En algún momento tenemos la imagen X (consulta) emparejada con la imagen Y (tren), pero luego también tenemos la imagen Y (ahora consulta) emparejada con la imagen X (ahora tren). Como puede ver, esto tampoco tiene sentido, ya que básicamente hace coincidir dos veces el mismo par de imágenes. Esto se puede resolver (actualmente trabajando en esto) creando una clase (MatchContainer) que almacena un puntero a cada una de las dos imágenes en un par coincidente y también el vector de coincidencia. Almacena esto en una ubicación central (en mi caso, esta es mi clase de emparejador) y para cada imagen como imagen de consulta, verifica la lista de imágenes coincidentes de la imagen del tren. Si está vacío, crea un nuevo MatchContainer y lo agrega al rest de los MatchContainers. Si no lo está, mire en él y vea si la imagen de la consulta actual no está presente allí (comparar punteros es una operación rápida). Si es así, simplemente pasa el puntero al elemento vectorial de ese MatchContainer que almacena las coincidencias para esas dos imágenes. Si ese no es el caso, hágalo como si estuviera vacío y cree un nuevo MatchContainer, etc. MatchingContainers debe almacenarse en una estructura de datos con un tiempo de acceso reducido, ya que los verá mucho y repetirá de principio a fin. mucho tiempo. Estoy considerando usar un mapa, pero tal vez un árbol de algún tipo también pueda ofrecer algunas ventajas.
  4. La estimación de la homografía es una parte muy complicada. Aquí te recomiendo que mires el ajuste de bloque de paquete . Vi que la clase de agrupador en OpenCV tiene una clase BundleBase pero aún no la he probado para ver qué contiene.

Una recomendación general es mirar el proceso de costura en OpenCV y leer el código fuente. El canal de costura es un conjunto de procesos sencillo y solo tiene que ver cómo puede implementar exactamente los pasos individuales.