Comparer la similarité des images à l'aide d'OpenCV avec Python
Je suis en train de comparer une image à une liste d'autres images, et le retour d'une sélection d'images (tels que la recherche Google images) de cette liste avec jusqu'à 70% de similarité.
- Je obtenir ce code dans ce post et de changement pour mon contexte
# 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()
Ma question est, comment puis-je comparer l'image avec la liste des images et obtenir uniquement des images similaires? Existe t'il une méthode pour faire cela?
Vous devez vous connecter pour publier un commentaire.
Je vous suggère de prendre un coup d'oeil à la terre de déménageur à distance (EMD) entre les images.
Cette métrique donne un sentiment sur la façon dont il est difficile de transformer un normalisée en niveaux de gris de l'image en une autre, mais peut être généralisée pour les images en couleur. Une très bonne analyse de cette méthode peut être trouvée dans le document suivant:
robotics.stanford.edu/~rubner/documents/rubnerIjcv00.pdf
Il peut être fait à la fois sur l'ensemble de l'image et sur l'histogramme (qui est vraiment plus rapide que l'ensemble de la méthode de l'image). Je ne suis pas sûr de la méthode permettant une image de comparaison, mais pour l'histogramme de comparaison, vous pouvez utiliser le cv.CalcEMD2 fonction.
Le seul problème est que cette méthode ne permet pas de définir un pourcentage de similitude, mais une distance que vous pouvez filtrer sur.
Je sais que ce n'est pas un travail complet de l'algorithme, mais c'est toujours une base, donc j'espère que cela aide.
EDIT:
Voici une parodie de la façon dont les EMD fonctionne selon le principe d'. L'idée principale est d'avoir deux normalisé matrices (deux images en niveaux de gris, divisée par la somme), et la définition d'un flux de matrice qui décrivent la façon dont vous déplacez le gris d'un pixel à l'autre à partir de la première image pour obtenir la deuxième (il peut être défini, même pour les non normalisé un, mais il est plus difficile).
En termes mathématiques la matrice de flux est en fait un quadridimensional tenseur qui donne le flux à partir du point (i,j) de la vieille image du point (k,l) de la nouvelle, mais si vous aplatir vos images, vous pouvez le transformer en une matrice normale, juste un peu plus dur à lire.
Cette matrice de Flux a trois contraintes: chaque terme devrait être positif, de la somme de chaque ligne doit retourner la même valeur de la desitnation pixel et la somme de chaque colonne doit retourner la valeur du pixel de départ.
Compte tenu de ce que vous avez à minimiser le coût de la transformation, donné par la somme des produits de chaque flux de (i,j) (k,l) pour la distance entre (i,j) et (k,l).
Ça a l'air un peu compliqué dans les mots, voici donc le code de test. La logique est correcte, je ne suis pas sûr pourquoi, la scipy solveur se plaint à ce sujet (vous devriez peut-être regarder à openOpt ou quelque chose de similaire):
la variable res contient le résultat de la minimisation...mais comme je l'ai dit je ne suis pas sûr pourquoi elle se plaint d'une matrice singulière.
Le seul problème de cet algorithme est qu'il est pas très rapide, il n'est donc pas possible de le faire sur demande, mais vous avez à effectuer avec patience sur la création de la base de données et de les stocker quelque part les résultats
J'ai écrit un programme pour faire quelque chose de très similaire, peut-être il y a 2 ans à l'aide de Python/Cython. Plus tard, je l'ai réécrit à Aller pour obtenir de meilleures performances. L'idée de base vient de findimagedupes IIRC.
Essentiellement, il calcule une "empreinte digitale" pour chaque image, puis de comparer ces empreintes digitales pour correspondre à des images similaires.
L'empreinte digitale est généré par le redimensionnement de l'image pour 160x160, convertir en niveaux de gris, ajoutant un peu de flou, la normalisation, puis la redimensionner à 16x16 monochrome. À la fin, vous disposez de 256 bits de sortie: c'est l'empreinte de votre. C'est très facile à faire en utilisant
conversion
:(Le
[0]
danspath[0]
est uniquement utilisée pour extraire la première image de GIFs animés; si vous n'êtes pas intéressés par de telles images, vous pouvez simplement le supprimer.)Après l'application de cette à 2 images, vous aurez 2 (256-bit) les empreintes digitales,
fp1
etfp2
.Le score de similarité de ces 2 images est ensuite calculée en XORing ces 2 valeurs et de compter les bits mis à 1. Pour ce faire bit de comptage, vous pouvez utiliser le
bitsoncount()
fonction de cette réponse:score
sera un nombre entre 0 et 256 indiquant le degré de similitude de vos images. Dans mon application je le divise par 2.56 (normaliser au 0-100) et j'ai trouvé que les images avec une note normalisée de 20 ou moins, sont souvent identiques.Si vous souhaitez mettre en œuvre cette méthode et l'utiliser pour comparer des lots d'images, j'ai fortement vous suggérons d'utiliser Cython (ou tout simplement C) autant que possible: XORing et bit de comptage est très lent, pur Python entiers.
Je suis vraiment désolé, mais je ne trouve pas mon code Python plus. Maintenant je n'ai qu'un Go version, mais je crains que je ne peux pas le poster ici (étroitement intégré dans d'autres codes, et probablement un peu moche comme c'était mon premier programme sérieux dans le jeu de Go...).
Il y a aussi un très bon "recherche par similarité" dans GQView/Geeqie; sa source est ici.
Vous vous embarquez sur un problème de masse, dénommé "content based image retrieval", ou CBIR. C'est un énorme et champ actif. Il n'y a pas terminé les algorithmes ou les approches standard et pourtant, bien qu'il existe beaucoup de techniques de tous avec plus ou moins de succès.
Même recherche d'images de Google de ne pas le faire (pour l'instant) - ils n'texte-image basée sur la recherche - par exemple, rechercher du texte dans une page, comme le texte recherché. (Et je suis sûr qu'ils sont de travail sur l'utilisation de CBIR; c'est le saint graal pour beaucoup de traitement d'image chercheurs)
Si vous disposez d'un délai serré ou besoin d'obtenir ce fait et de travail bientôt... aïe.
Voici une tonne de papiers sur le sujet:
http://scholar.google.com/scholar?q=content+base+image+récupération
Généralement vous aurez besoin de faire quelques petites choses:
Cela peut impliquer fonction des descripteurs, image gist, plusieurs instances d'apprentissage. etc.
Pour une simplification de la mise en œuvre de la Terre de Déménageur à Distance (aka la Distance de Wasserstein) en Python, vous pouvez utiliser Scipy: