2011-10-24 27 views
6

tengo una imagen de muestra que contiene un objeto, tal como los pendientes en la siguiente imagen:Detectar si un objeto de una imagen está en otra imagen con OpenCV

http://imgur.com/luj2Z

que luego tiene un gran candidato conjunto de imágenes para las que necesito para determinar cuál de ellas muy probablemente contiene el objeto, por ejemplo:

http://imgur.com/yBWgc

por eso es necesario para producir una puntuación para cada imagen, donde la puntuación más alta corresponde a la imagen que muy probablemente contiene el objeto de destino. Ahora, en este caso, tengo las siguientes condiciones/restricciones para trabajar con/alrededor de:

1) Puedo obtener múltiples imágenes de muestra en diferentes ángulos.

2) Es probable que las imágenes de muestra tengan diferentes resoluciones, ángulos y distancias que las imágenes candidatas.

3) Hay MUCHAS imágenes candidatas (> 10,000), por lo que debe ser razonablemente rápido.

4) Estoy dispuesto a sacrificar algo de precisión por velocidad, así que si eso significa que tenemos que buscar entre los 100 primeros en vez de solo los 10 principales, está bien y se puede hacer manualmente.

5) Puedo manipular manualmente las imágenes de muestra, como esbozar el objeto que deseo detectar; las imágenes candidatas no se pueden manipular manualmente ya que son demasiadas.

6) No tengo ninguna experiencia real en OpenCV o visión artificial, así que estoy empezando desde cero aquí.

Mi idea inicial es comenzar dibujando un contorno aproximado alrededor del objeto en la imagen de muestra. Entonces, pude identificar las esquinas en el objeto y las esquinas de la imagen candidata. Podría hacer un perfil de los píxeles alrededor de cada esquina para ver si se ven similares y clasificarlos por la suma de las puntuaciones de similitud máxima de cada esquina. Tampoco estoy seguro de cómo cuantificar píxeles similares. Supongo que solo la distancia euclidiana de sus valores RGB?

El problema es que ignora el centro del objeto. En los ejemplos anteriores, si las esquinas de los pendientes están todas cerca del marco dorado, entonces no consideraría las piedras rojas, verdes y azules dentro del pendiente. Supongo que podría mejorar esto mirando a todos los pares de esquinas y determinando la similitud mediante el muestreo de algunos puntos a lo largo de la línea que los separa.

así que tengo un par de preguntas:

a) ¿esta línea de pensamiento tiene sentido en general, o hay algo que me falta?

B) ¿Qué algoritmos específicos de OpenCV debo investigar? Soy consciente de que existen algoritmos de detección de esquinas múltiples, pero solo necesito uno y si todas las diferencias se están optimizando en los márgenes, estoy bien con el más rápido.

C) ¿Algún código de ejemplo usando los algoritmos que serían útiles para ayudar en mi comprensión?

Mis opciones para idiomas son Python o C#.

Respuesta

4

Echa un vistazo a las características SURF, que son parte de openCV.La idea aquí es que tienes un algoritmo para encontrar "puntos de interés" en dos imágenes. También tiene un algoritmo para calcular un descriptor de un parche de imagen alrededor de cada punto de interés. Normalmente, este descriptor captura la distribución de las orientaciones de los bordes en el parche. Luego tratas de encontrar correspondencias de puntos, i. mi. para cada punto de interés en la imagen A intente encontrar el punto de interés correspondiente en la imagen B. Esto se logra comparando los descriptores y buscando las coincidencias más cercanas. Entonces, si tiene un conjunto de correspondencias que están relacionadas por alguna transformación geométrica, tiene una detección.

Por supuesto, esta es una explicación de alto nivel. El diablo está en los detalles, y para ellos debes leer algunos documentos. Comience con Distinctive image features from scale-invariant keypoints por David Lowe, y luego lea los documentos en SURF.

Además, considere mover esta pregunta a Signal and Image Processing Stack Exchange

0

Como se ha dicho, algoritmos como SIFT y SURF contienen un punto de función, que es invariante a una serie de distorsiones y un descriptor, que tiene como objetivo modelar robusta punto la función de su alrededores.

Este último se usa cada vez más para categorizar e identificar imágenes en lo que comúnmente se conoce como el enfoque de "bolsa de palabras" o "palabras visuales".

En la forma más simple, uno puede recopilar todos los datos de todos los descriptores de todas las imágenes y agruparlos, por ejemplo, utilizando k-means. Cada imagen original tiene descriptores que contribuyen a una cantidad de clusters. Los centroides de estos clústeres, es decir, las palabras visuales, se pueden usar como un nuevo descriptor para la imagen. Estos pueden ser utilizados en una arquitectura con un diseño de archivo invertido.

Este enfoque permite una coincidencia suave y una cierta generalización de la cantidad, por ejemplo, recuperar todas las imágenes con aviones.

  • El VLfeat website contiene, junto a una excelente biblioteca SIFT, una buena demostración de este enfoque, la clasificación del conjunto de datos caltech 101.

  • Caltech ofrece el software Matlab/C++ junto con publicaciones relevantes.

  • También un buen comienzo es la obra de LEAR

5

Afortunadamente, los chicos tipo de OpenCV acaban de hacer eso para usted. Compruebe en la carpeta de muestras "opencv \ samples \ cpp \ matching_to_many_images.cpp". Compila y pruébalo con las imágenes predeterminadas.

El algoritmo se puede adaptar fácilmente para hacerlo más rápido o más preciso.

Principalmente, los algoritmos de reconocimiento de objetos se dividen en dos partes: detección de punto clave & descripción y coincidencia de objetos. Para ambos hay muchos algoritmos/variantes, con los que puedes jugar directamente en OpenCV.

La detección/descripción se puede realizar mediante: SIFT/SURF/ORB/GFTT/STAR/FAST y otros.

Para hacer coincidir tiene: fuerza bruta, hamming, etc.(Algunos métodos son específicos para un algoritmo de detección determinado)

pistas para empezar:

  • recortar la imagen original, por lo que el objeto interesante cubre tanto como sea posible del área de imagen. Úselo como entrenamiento.

  • SIFT es el descriptor más preciso y perezoso. FAST es una buena combinación de precisión y precisión. GFTT es viejo y bastante poco confiable. ORB se ha agregado recientemente a OPENCV y es muy prometedor, tanto en velocidad como en precisión.

  • Los resultados dependen de la pose del objeto en la otra imagen. Si se cambia de tamaño, se gira, se aprieta, se cubre parcialmente, etc., intente con SIFT. si es una tarea simple (es decir, aparece en casi el mismo tamaño/rotación/etc., la mayoría de los descriptores funcionarán bien)
  • Puede que ORB aún no esté en la versión de OpenCV. Intente descargar lo último desde el tronco de openCV y compilarlo https://code.ros.org/svn/opencv/trunk

Así que puede encontrar la mejor combinación para usted por prueba y error.

Para los detalles de cada implementación, debe leer los documentos/tutoriales originales. Google Scholar es un buen comienzo

2

En caso de que alguien venga en el futuro, aquí hay una pequeña muestra que hace esto con openCV. Se basa en el opencv sample, pero (en mi opinión), esto es un poco más claro, así que lo estoy incluyendo también.

probado con OpenCV 2.4.4

#!/usr/bin/env python 

''' 
Uses SURF to match two images. 
    Finds common features between two images and draws them 

Based on the sample code from opencv: 
    samples/python2/find_obj.py 

USAGE 
    find_obj.py <image1> <image2> 
''' 

import sys 

import numpy 
import cv2 


############################################################################### 
# Image Matching 
############################################################################### 

def match_images(img1, img2, img1_features=None, img2_features=None): 
    """Given two images, returns the matches""" 
    detector = cv2.SURF(3200) 
    matcher = cv2.BFMatcher(cv2.NORM_L2) 

    if img1_features is None: 
     kp1, desc1 = detector.detectAndCompute(img1, None) 
    else: 
     kp1, desc1 = img1_features 

    if img2_features is None: 
     kp2, desc2 = detector.detectAndCompute(img2, None) 
    else: 
     kp2, desc2 = img2_features 

    #print 'img1 - %d features, img2 - %d features' % (len(kp1), len(kp2)) 

    raw_matches = matcher.knnMatch(desc1, trainDescriptors=desc2, k=2) 
    kp_pairs = filter_matches(kp1, kp2, raw_matches) 
    return kp_pairs 


def filter_matches(kp1, kp2, matches, ratio=0.75): 
    """Filters features that are common to both images""" 
    mkp1, mkp2 = [], [] 
    for m in matches: 
     if len(m) == 2 and m[0].distance < m[1].distance * ratio: 
      m = m[0] 
      mkp1.append(kp1[m.queryIdx]) 
      mkp2.append(kp2[m.trainIdx]) 
    kp_pairs = zip(mkp1, mkp2) 
    return kp_pairs 


############################################################################### 
# Match Diplaying 
############################################################################### 

def draw_matches(window_name, kp_pairs, img1, img2): 
    """Draws the matches""" 
    mkp1, mkp2 = zip(*kp_pairs) 

    H = None 
    status = None 

    if len(kp_pairs) >= 4: 
     p1 = numpy.float32([kp.pt for kp in mkp1]) 
     p2 = numpy.float32([kp.pt for kp in mkp2]) 
     H, status = cv2.findHomography(p1, p2, cv2.RANSAC, 5.0) 

    if len(kp_pairs): 
     explore_match(window_name, img1, img2, kp_pairs, status, H) 


def explore_match(win, img1, img2, kp_pairs, status=None, H=None): 
    """Draws lines between the matched features""" 
    h1, w1 = img1.shape[:2] 
    h2, w2 = img2.shape[:2] 
    vis = numpy.zeros((max(h1, h2), w1 + w2), numpy.uint8) 
    vis[:h1, :w1] = img1 
    vis[:h2, w1:w1 + w2] = img2 
    vis = cv2.cvtColor(vis, cv2.COLOR_GRAY2BGR) 

    if H is not None: 
     corners = numpy.float32([[0, 0], [w1, 0], [w1, h1], [0, h1]]) 
     reshaped = cv2.perspectiveTransform(corners.reshape(1, -1, 2), H) 
     reshaped = reshaped.reshape(-1, 2) 
     corners = numpy.int32(reshaped + (w1, 0)) 
     cv2.polylines(vis, [corners], True, (255, 255, 255)) 

    if status is None: 
     status = numpy.ones(len(kp_pairs), numpy.bool_) 
    p1 = numpy.int32([kpp[0].pt for kpp in kp_pairs]) 
    p2 = numpy.int32([kpp[1].pt for kpp in kp_pairs]) + (w1, 0) 

    green = (0, 255, 0) 
    red = (0, 0, 255) 
    for (x1, y1), (x2, y2), inlier in zip(p1, p2, status): 
     if inlier: 
      col = green 
      cv2.circle(vis, (x1, y1), 2, col, -1) 
      cv2.circle(vis, (x2, y2), 2, col, -1) 
     else: 
      col = red 
      r = 2 
      thickness = 3 
      cv2.line(vis, (x1 - r, y1 - r), (x1 + r, y1 + r), col, thickness) 
      cv2.line(vis, (x1 - r, y1 + r), (x1 + r, y1 - r), col, thickness) 
      cv2.line(vis, (x2 - r, y2 - r), (x2 + r, y2 + r), col, thickness) 
      cv2.line(vis, (x2 - r, y2 + r), (x2 + r, y2 - r), col, thickness) 
    vis0 = vis.copy() 
    for (x1, y1), (x2, y2), inlier in zip(p1, p2, status): 
     if inlier: 
      cv2.line(vis, (x1, y1), (x2, y2), green) 

    cv2.imshow(win, vis) 

############################################################################### 
# Test Main 
############################################################################### 

if __name__ == '__main__': 
    if len(sys.argv) < 3: 
     print "No filenames specified" 
     print "USAGE: find_obj.py <image1> <image2>" 
     sys.exit(1) 

    fn1 = sys.argv[1] 
    fn2 = sys.argv[2] 

    img1 = cv2.imread(fn1, 0) 
    img2 = cv2.imread(fn2, 0) 

    if img1 is None: 
     print 'Failed to load fn1:', fn1 
     sys.exit(1) 

    if img2 is None: 
     print 'Failed to load fn2:', fn2 
     sys.exit(1) 

    kp_pairs = match_images(img1, img2) 

    if kp_pairs: 
     draw_matches('find_obj', kp_pairs, img1, img2) 
    else: 
     print "No matches found" 

    cv2.waitKey() 
    cv2.destroyAllWindows() 
+1

Gracias, esto me señaló en la dirección correcta. Lo aprecio. –

Cuestiones relacionadas