[MODIFIER] J'ai conçu du code pour la comparaison d'images. La partie correspondante est encore un peu imparfaite et j'aimerais de l'aide. Le projet peut être trouvé à - GitHub .
J'ai ces deux images Img1 et Img2:
Quand j'utilise la commande suivante dans openCV
Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg");
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg");
try{
double l2_norm = Core.norm( img1, img2 );
tv.setText(l2_norm+"");
} catch(Exception e) {
//image is not a duplicate
}
J'obtiens une double valeur pour l2_norm. Cette double valeur varie pour les paires d'images en double. Mais si les images sont différentes, une exception est levée. Est-ce ainsi que j'identifie les images en double? Ou y a-t-il une meilleure méthode? J'ai abondamment cherché sur Google et je n'ai pas trouvé de réponse vraiment convaincante. J'aimerais connaître le code et expliquer comment comparer deux images et obtenir une valeur booléenne de true
ou false
en fonction des images.
MODIFIER
Scalar blah= Core.sumElems(img2);
Scalar blah1=Core.sumElems(img1);
if(blah.equals(blah1))
{
tv.setText("same image");
}
}
J'ai essayé cela, mais la condition if
n'est jamais satisfaite. Je suppose qu'il y a quelques différences, mais il n'y a pas de fonction compare
pour Scalar
. Que fais-je?
MODIFIER
try{
Scalar blah= Core.sumElems(img2);
Scalar blah1=Core.sumElems(img1);
String b=blah.toString();
String b1=blah1.toString();
System.out.println(b+" "+b1);
double comp=b.compareTo(b1);
tv.setText(""+comp);
}
Cette méthode est encore imparfaite. Bien qu'il puisse être utilisé pour comparer des images avec une précision décente, il échoue lorsque les images sont de tailles différentes.
Lorsque les images sont de tailles différentes et que j'imprime les valeurs scalaires, je reçois ceci:
[9768383.0, 1.0052889E7, 1.0381814E7, 0.0] [1.5897384E7, 1.6322252E7, 1.690251E7, 0.0]
La différence entre les deuxième et troisième nombres, bien que peu, est assez grande comparée à celle obtenue lorsque les images de même taille sont comparées. Le premier nombre subit toutefois le plus de changement.
Quel serait le meilleur moyen le plus rapide de comparer le contenu de deux images?
[MODIFIER]
J'utilise le code que j'ai trouvé ici .
Ce que je ne peux pas comprendre, c'est comment initialiser les variables MatOfKeyPoint
keypoints
et logoKeypoints
. Voici mon extrait de code:
FeatureDetector detector = FeatureDetector.create(FeatureDetector.SURF);
//FeatureDetector detector = FeatureDetector.create(FeatureDetector.FAST);
//Imgproc.cvtColor(img1, img1, Imgproc.COLOR_RGBA2RGB);
//Imgproc.cvtColor(img2, img2, Imgproc.COLOR_RGBA2RGB);
DescriptorExtractor SurfExtractor = DescriptorExtractor
.create(DescriptorExtractor.SURF);
//extract keypoints
MatOfKeyPoint keypoints, logoKeypoints;
long time= System.currentTimeMillis();
detector.detect(img1, keypoints);
Log.d("LOG!", "number of query Keypoints= " + keypoints.size());
detector.detect(img2, logoKeypoints);
Log.d("LOG!", "number of logo Keypoints= " + logoKeypoints.size());
Log.d("LOG!", "keypoint calculation time elapsed" + (System.currentTimeMillis() -time));
//Descript keypoints
long time2 = System.currentTimeMillis();
Mat descriptors = new Mat();
Mat logoDescriptors = new Mat();
Log.d("LOG!", "logo type" + img2.type() + " intype" + img1.type());
SurfExtractor.compute(img1, keypoints, descriptors);
SurfExtractor.compute(img2, logoKeypoints, logoDescriptors);
Log.d("LOG!", "Description time elapsed" + (System.currentTimeMillis()- time2));
Je ne peux évidemment pas initialiser les variables keypoints
et logoKeypoints
à null parce que je recevrai alors une exception de pointeur null. Comment puis-je les initialiser?
Vous devez comprendre que ce n’est pas une question simple et que vous pouvez suivre différents concepts. Je ne signalerai que deux solutions sans code source.
J'espère que cela aide. S'il vous plaît demander si vous avez des questions.
[UPDATE-1] Un tutoriel en C++: http://morf.lv/modules.php?name=tutorials&lasit=2#.UR-ewKU3vCk
Quelques tutoriels JavaCV: http://code.google.com/p/javacv/w/list
[UPDATE-2] Voici un exemple avec SIFT-Detector et SIFT-Descriptor utilisant les paramètres par défaut. RANSAC-Seuil pour l'homographie est 65, l'erreur de reprojection (epsilon) est 10, la validation croisée est activée. Vous pouvez essayer de compter les appariés. Si le ratio Inliner-Outlier-Ratio est trop élevé, vous pourriez voir cette paire comme des doublons. Par exemple: Ces images génèrent 180 points clés dans IMG1 et 198 dans IMG2. Les descripteurs appariés sont 163, dont 3 seulement sont des valeurs aberrantes. Cela donne donc un très bon rapport qui pourrait signifier que ces images pourraient être dupliquées.
[UPDATE-3] Je ne comprends pas pourquoi vous pouvez initialiser les MatOfKeypoints. J'ai lu l'API et il y a un constructeur public. ET: Vous pouvez utiliser le tapis de l'image que vous souhaitez analyser. C'est très gentil. =)
MatOfKeyPoint reference = new MatOfKeyPoint(matOfReferenceImage);
Pour la correspondance, utilisez un (descripteur BRUTEFORCE_SL2 _ car vous aurez besoin de la distance euclidienne pour SURF ou SIFT.
Utilisez cv2.absDiff
pour calculer la différence entre les images et cv2.sumElems
pour obtenir la somme de toutes les différences en pixels.
Puis inventez un seuil permettant de juger si deux images sont similaires ou non.
Vous pouvez essayer le code suivant:
Mat img1 = Highgui.imread("mnt/sdcard/IMG-20121228.jpg");
Mat img2 = Highgui.imread("mnt/sdcard/IMG-20121228-1.jpg");
Mat result = new Mat();
Core.compare(img1,img2,result,Core.CMP_NE);
int val = Core.countNonZero(result);
if(val == 0) {
//Duplicate Image
} else {
//Different Image
}
Ici, dans la fonction de comparaison de code, deux images sont comparées, puis s'il y a une similitude entre les images, la valeur de la matrice est alors 255 et toutes les autres valeurs sont égales à zéro. Ensuite, vous pouvez compter le nombre de valeurs non nulles pour déterminer si les images étaient égales. Cela ne fonctionnerait que pour exactement les mêmes images.
Si vous souhaitez comparer des images en ignorant les effets de lumière, je vous suggère de générer d'abord l'image Edge (en utilisant la fonction intuitive d'OpenCV), puis de comparer les images.
J'espère que cette réponse vous aide !!