ruido reconocimiento para objetos manipulacion imagenes gaussiano filtros entre diferencia deteccion con comparar comparacion python opencv computer-vision

reconocimiento - Compara similitud de imágenes usando OpenCV con Python



reconocimiento de imagenes python (4)

Intento comparar una imagen con una lista de otras imágenes y devolver una selección de imágenes (como imágenes de búsqueda de Google) de esta lista con hasta un 70% de similitud.

Obtengo este código en esta publicación y cambio para mi contexto

# Load the images img =cv2.imread(MEDIA_ROOT + "/uploads/imagerecognize/armchair.jpg") # Convert them to grayscale imgg =cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # SURF extraction surf = cv2.FeatureDetector_create("SURF") surfDescriptorExtractor = cv2.DescriptorExtractor_create("SURF") kp = surf.detect(imgg) kp, descritors = surfDescriptorExtractor.compute(imgg,kp) # Setting up samples and responses for kNN samples = np.array(descritors) responses = np.arange(len(kp),dtype = np.float32) # kNN training knn = cv2.KNearest() knn.train(samples,responses) modelImages = [MEDIA_ROOT + "/uploads/imagerecognize/1.jpg", MEDIA_ROOT + "/uploads/imagerecognize/2.jpg", MEDIA_ROOT + "/uploads/imagerecognize/3.jpg"] for modelImage in modelImages: # Now loading a template image and searching for similar keypoints template = cv2.imread(modelImage) templateg= cv2.cvtColor(template,cv2.COLOR_BGR2GRAY) keys = surf.detect(templateg) keys,desc = surfDescriptorExtractor.compute(templateg, keys) for h,des in enumerate(desc): des = np.array(des,np.float32).reshape((1,128)) retval, results, neigh_resp, dists = knn.find_nearest(des,1) res,dist = int(results[0][0]),dists[0][0] if dist<0.1: # draw matched keypoints in red color color = (0,0,255) else: # draw unmatched in blue color #print dist color = (255,0,0) #Draw matched key points on original image x,y = kp[res].pt center = (int(x),int(y)) cv2.circle(img,center,2,color,-1) #Draw matched key points on template image x,y = keys[h].pt center = (int(x),int(y)) cv2.circle(template,center,2,color,-1) cv2.imshow(''img'',img) cv2.imshow(''tm'',template) cv2.waitKey(0) cv2.destroyAllWindows()

Mi pregunta es, ¿cómo puedo comparar la imagen con la lista de imágenes y obtener solo las imágenes similares? ¿Hay algún método para hacer esto?


Escribí un programa para hacer algo muy similar hace 2 años usando Python / Cython. Más tarde lo reescribí para obtener un mejor rendimiento. La idea base proviene de findimagedupes IIRC.

Básicamente, calcula una "huella digital" para cada imagen, y luego compara estas huellas digitales para que coincidan con imágenes similares.

La huella dactilar se genera cambiando el tamaño de la imagen a 160x160, convirtiéndola a escala de grises, agregando un poco de desenfoque, normalizándolo y redimensionándolo a monocromo de 16x16. Al final tienes 256 bits de salida: esa es tu huella digital. Esto es muy fácil de hacer usando convert :

convert path[0] -sample 160x160! -modulate 100,0 -blur 3x99 / -normalize -equalize -sample 16x16 -threshold 50% -monochrome mono:-

(El [0] en la path[0] se usa para extraer solo el primer cuadro de GIF animados; si no está interesado en esas imágenes, simplemente puede eliminarlo).

Después de aplicar esto a 2 imágenes, tendrá 2 huellas digitales (256 bits), fp1 y fp2 .

El puntaje de similitud de estas 2 imágenes se calcula bitsoncount() estos 2 valores y contando los bits establecidos en 1. Para hacer este conteo de bits, puede usar la función bitsoncount() partir de esta respuesta :

# fp1 and fp2 are stored as lists of 8 (32-bit) integers score = 0 for n in range(8): score += bitsoncount(fp1[n] ^ fp2[n])

score será un número entre 0 y 256 que indica qué tan similares son sus imágenes. En mi aplicación, lo divido por 2.56 (normalizo a 0-100) y he encontrado que las imágenes con una puntuación normalizada de 20 o menos son a menudo idénticas.

Si desea implementar este método y usarlo para comparar muchas imágenes, le sugiero que use Cython (o simplemente C) tanto como sea posible: XORing y el conteo de bits es muy lento con enteros puros de Python.

Lo siento mucho, pero ya no puedo encontrar mi código Python. En este momento solo tengo una versión Go, pero me temo que no puedo publicarla aquí (estrechamente integrada en otro código, y probablemente un poco fea, ya que fue mi primer programa serio en Go ...).

También hay una muy buena función "buscar por similitud" en GQView / Geeqie; su fuente está here .


Para una implementación más simple de la Distancia de Earth Mover (también conocida como Wasserstein Distance) en Python, puedes usar Scipy:

from scipy.stats import wasserstein_distance from scipy.ndimage import imread import numpy as np def get_histogram(img): '''''' Get the histogram of an image. For an 8-bit, grayscale image, the histogram will be a 256 unit vector in which the nth value indicates the percent of the pixels in the image with the given darkness level. The histogram''s values sum to 1. '''''' h, w = img.shape hist = [0.0] * 256 for i in range(h): for j in range(w): hist[img[i, j]] += 1 return np.array(hist) / (h * w) a = imread(''a.jpg'') b = imread(''b.jpg'') a_hist = get_histogram(a) b_hist = get_histogram(b) dist = wasserstein_distance(a_hist, b_hist) print(dist)


Se está embarcando en un problema masivo, conocido como "recuperación de imágenes basada en contenido", o CBIR. Es un campo masivo y activo. Aún no hay algoritmos terminados o enfoques estándar, aunque hay muchas técnicas, todas con diferentes niveles de éxito.

Incluso la búsqueda de imágenes de Google no hace esto (todavía): realizan búsquedas de imágenes basadas en texto, por ejemplo, buscan texto en una página similar al texto buscado. (Y estoy seguro de que están trabajando en el uso de CBIR, es el santo grial de muchos investigadores de procesamiento de imágenes)

Si tiene un plazo ajustado o necesita terminarlo y trabajar pronto ... ¡sí!

Aquí hay un montón de artículos sobre el tema:

http://scholar.google.com/scholar?q=content+based+image+retrieval

En general, deberá hacer algunas cosas:

  1. Funciones de extracción (ya sea en puntos de interés local, o globalmente, o de alguna manera, SIFT, SURF, histogramas, etc.)
  2. Cluster / construir un modelo de distribuciones de imágenes

Esto puede incluir descriptores de características , imágenes gráficas , aprendizaje de instancias múltiples . etc.


Te sugiero que eches un vistazo a la distancia del movedor de tierra (EMD) entre las imágenes. Esta métrica da una idea de lo difícil que es transformar una imagen normalizada en escala de grises en otra, pero se puede generalizar para imágenes en color. Un muy buen análisis de este método se puede encontrar en el siguiente documento:

robotics.stanford.edu/~rubner/papers/rubnerIjcv00.pdf

Se puede hacer tanto en la imagen completa como en el histograma (que es realmente más rápido que el método de la imagen completa). No estoy seguro de qué método permite una comparación de imágenes completa, pero para la comparación de histogramas puede usar la función cv.CalcEMD2 .

El único problema es que este método no define un porcentaje de similitud, sino una distancia que puede filtrar.

Sé que este no es un algoritmo de trabajo completo, pero sigue siendo una base para él, así que espero que ayude.

EDITAR:

Aquí hay una parodia de cómo funciona el EMD en principio. La idea principal es tener dos matrices normalizadas (dos imágenes en escala de grises divididas por su suma) y definir una matriz de flujo que describa cómo se mueve el gris de un píxel al otro desde la primera imagen para obtener el segundo (se puede definir incluso para uno no normalizado, pero es más difícil).

En términos matemáticos, la matriz de flujo es en realidad un tensor cuadridimensional que proporciona el flujo desde el punto (i, j) de la imagen anterior hasta el punto (k, l) del nuevo, pero si aplana sus imágenes, puede transformarlo a una matriz normal, solo un poco más difícil de leer.

Esta matriz de Flujo tiene tres restricciones: cada término debe ser positivo, la suma de cada fila debe devolver el mismo valor del píxel de desición y la suma de cada columna debe devolver el valor del píxel de inicio.

Dado esto, debe minimizar el costo de la transformación, dado por la suma de los productos de cada flujo desde (i, j) hasta (k, l) para la distancia entre (i, j) y (k, l).

Parece un poco complicado en palabras, así que aquí está el código de prueba. La lógica es correcta, no estoy seguro de por qué el solucionador de errores se queja de eso (debería mirar tal vez a openOpt o algo similar):

#original data, two 2x2 images, normalized x = rand(2,2) x/=sum(x) y = rand(2,2) y/=sum(y) #initial guess of the flux matrix # just the product of the image x as row for the image y as column #This is a working flux, but is not an optimal one F = (y.flatten()*x.flatten().reshape((y.size,-1))).flatten() #distance matrix, based on euclidean distance row_x,col_x = meshgrid(range(x.shape[0]),range(x.shape[1])) row_y,col_y = meshgrid(range(y.shape[0]),range(y.shape[1])) rows = ((row_x.flatten().reshape((row_x.size,-1)) - row_y.flatten().reshape((-1,row_x.size)))**2) cols = ((col_x.flatten().reshape((row_x.size,-1)) - col_y.flatten().reshape((-1,row_x.size)))**2) D = np.sqrt(rows+cols) D = D.flatten() x = x.flatten() y = y.flatten() #COST=sum(F*D) #cost function fun = lambda F: sum(F*D) jac = lambda F: D #array of constraint #the constraint of sum one is implicit given the later constraints cons = [] #each row and columns should sum to the value of the start and destination array cons += [ {''type'': ''eq'', ''fun'': lambda F: sum(F.reshape((x.size,y.size))[i,:])-x[i]} for i in range(x.size) ] cons += [ {''type'': ''eq'', ''fun'': lambda F: sum(F.reshape((x.size,y.size))[:,i])-y[i]} for i in range(y.size) ] #the values of F should be positive bnds = (0, None)*F.size from scipy.optimize import minimize res = minimize(fun=fun, x0=F, method=''SLSQP'', jac=jac, bounds=bnds, constraints=cons)

la variable res contiene el resultado de la minimización ... pero como he dicho, no estoy seguro de por qué se queja de una matriz singular.

El único problema con este algoritmo es que no es muy rápido, por lo que no es posible hacerlo bajo demanda, pero debes hacerlo con paciencia en la creación del conjunto de datos y almacenar en alguna parte los resultados.