J'utilise des descripteurs SURF pour la comparaison d'images. Je prévois de faire correspondre une image donnée à une base de données d'images.
import cv2
import numpy as np
surf = cv2.xfeatures2d.SURF_create(400)
img1 = cv2.imread('box.png',0)
img2 = cv2.imread('box_in_scene.png',0)
kp1,des1 = surf.detectAndCompute(img1,None)
kp2,des2 = surf.detectAndCompute(img2,None)
bf = cv2.BFMatcher(cv2.NORM_L1,crossCheck=True)
#I am planning to add more descriptors
bf.add(des1)
bf.train()
#This is my test descriptor
bf.match(des2)
Le problème est avec bf.match
est que je reçois l'erreur suivante:
OpenCV Error: Assertion failed (type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U)) in batchDistance, file /build/opencv/src/opencv-3.1.0/modules/core/src/stat.cpp, line 3749
Traceback (most recent call last):
File "image_match4.py", line 16, in <module>
bf.match(des2)
cv2.error: /build/opencv/src/opencv-3.1.0/modules/core/src/stat.cpp:3749: error: (-215) type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U) in function batchDistance
L'erreur est similaire à this post. L'explication donnée est incomplète et inadéquate. Je veux savoir comment résoudre ce problème. J'ai aussi utilisé des descripteurs ORB, BFMatcher ayant NORM_HAMMING
distance. L'erreur refait surface . Toute aide sera appréciée.
Les deux images que j'ai utilisées pour cela sont:
box.png
box_in_scene.png
J'utilise Python 3.5.2 et OpenCV 3.1.x sous Linux.
Pour rechercher entre les descripteurs de deux images, utilisez:
img1 = cv2.imread('box.png',0)
img2 = cv2.imread('box_in_scene.png',0)
kp1,des1 = surf.detectAndCompute(img1,None)
kp2,des2 = surf.detectAndCompute(img2,None)
bf = cv2.BFMatcher(cv2.NORM_L1,crossCheck=False)
matches = bf.match(des1,des2)
Pour rechercher parmi plusieurs images
La méthode add
est utilisée pour ajouter un descripteur de plusieurs images de test. Une fois que tous les descripteurs sont indexés, vous exécutez la méthode train
pour construire une structure de données sous-jacente (exemple: KdTree qui sera utilisé pour la recherche dans le cas de FlannBasedMatcher). Vous pouvez ensuite exécuter match
pour déterminer si l'image de test correspond le mieux à quelle image de requête. Vous pouvez vérifier K-d_tree et voir comment il peut être utilisé pour rechercher des vecteurs multidimensionnels (Surf donne un vecteur à 64 dimensions).
Remarque: - BruteForceMatcher, comme son nom l’indique, n’a pas de recherche interne optimisant la structure des données et a donc une méthode de train vide.
Exemple de code pour la recherche d'images multiples
import cv2
import numpy as np
surf = cv2.xfeatures2d.SURF_create(400)
# Read Images
train = cv2.imread('box.png',0)
test = cv2.imread('box_in_scene.png',0)
# Find Descriptors
kp1,trainDes1 = surf.detectAndCompute(train, None)
kp2,testDes2 = surf.detectAndCompute(test, None)
# Create BFMatcher and add cluster of training images. One for now.
bf = cv2.BFMatcher(cv2.NORM_L1,crossCheck=False) # crossCheck not supported by BFMatcher
clusters = np.array([trainDes1])
bf.add(clusters)
# Train: Does nothing for BruteForceMatcher though.
bf.train()
matches = bf.match(testDes2)
matches = sorted(matches, key = lambda x:x.distance)
# Since, we have index of only one training image,
# all matches will have imgIdx set to 0.
for i in range(len(matches)):
print matches[i].imgIdx
Pour la sortie DMatch de bf.match, voir docs .
Voir l'exemple complet pour cela ici: Documents opencv3.0 .
Autre info
OS: Mac.
Python: 2.7.10.
Opencv: 3.0.0-dev [Si souvenez-vous bien, installé en utilisant infusion].
J'ai trouvé que j'avais la même erreur. Il a fallu un certain temps pour comprendre - certaines de mes images étaient quelque peu dépourvues de traits, donc aucun point clé n'a été trouvé, et detectAndCompute
a retourné None
pour les descripteurs. Cela vaut peut-être la peine de vérifier la liste des descripteurs pour les éléments None
avant de passer à BFMatcher.add()
.
J'avais la même erreur. Mais dans mon cas, c’était parce que j’utilisais SIFT avec la métrique cv2.NORM_HAMMING
dans cv2.BFMatcher_create
. Le fait de changer la métrique en cv2.NORM_L1
a résolu le problème.
Citation de documents pour BFMatcher :
normType
- L'un desNORM_L1
,NORM_L2
,NORM_HAMMING
,NORM_HAMMING2
.L1
et les normesL2
sont des choix préférables pour les descripteurs SIFT et SURF,NORM_HAMMING
doit être utilisé avec ORB, BRISK et BRIEF,NORM_HAMMING2
doit être utilisé avec ORB lorsqueWTA_K==3
ou4
(voir la description du constructeurORB::ORB
.__).
Édition: Versions utilisées Python 3.6, OpenCV 3.4.1
J'ai eu beaucoup de mal à préparer un programme qui utiliseSIFTouORBselon le choix de l'utilisateur. Enfin, je pourrais trouver les paramètres corrects pour BFMatcher pourSIFTetORB
import cv2
import numpy as np
# ask user whether to use SIFT or ORB
detect_by = input("sift or orb")
Création d'objet matcher
if detect_by == "sift":
matcher = cv2.BFMatcher(normType=cv2.NORM_L2, crossCheck=False)
Elif detect_by is "orb":
matcher = cv2.BFMatcher(normType=cv2.NORM_HAMMING, crossCheck=False)
Lors de la capture et du traitement des images
while there_is_frame_to_process:
if detect_by is "sift":
matches = matcher.knnMatch(np.asarray(gray_des, np.float32), np.asarray(target_des, np.float32), k=2)
Elif detect_by is "orb":
matches = matcher.knnMatch(np.asarray(gray_des, np.uint8), np.asarray(target_des, np.uint8), k=2)