Reconocimiento de imágenes con SURF con OpenCV en Android

Estoy tratando de construir una aplicación de reconocimiento de hoja simple con Android y OpenCV; Mi base de datos consta de sólo 3 entradas (3 imágenes de 3 tipos de hojas) y me gustaría ser capaz de reconocer si una de las imágenes de la base de datos está dentro de otra imagen capturada por el teléfono inteligente. Estoy utilizando el método SURF para extraer los puntos clave de las imágenes de la base de datos y luego los comparo con los puntos clave extraídos de la imagen capturada buscando una coincidencia. Mi problema es que el resultado aparece como una "coincidencia de colores", más que una "coincidencia de características": cuando comparo una imagen de la base de datos y la capturada, el número de coincidencias es igual a las 3 entradas y así obtengo una Coincidencia incorrecta.

Éste de la imagen de la base de datos (nota que está sin backgroud)

Imagen de la base de datos

Y este es el resultado que obtengo:

Captura de pantalla con los partidos

La imagen en la parte superior es la capturada desde el teléfono inteligente y la imagen de abajo es el resultado con las coincidencias resaltadas.

Aquí está el código que implementé:

Mat orig = Highgui.imread(photoPathwithoutFile); Mat origBW = new Mat(); Imgproc.cvtColor(orig, origBW, Imgproc.COLOR_RGB2GRAY); MatOfKeyPoint kpOrigin = createSURFdetector(origBW); Mat descOrig = extractDescription(kpOrigin, origBW); Leaf result = findMatches(descOrig); Mat imageOut = orig.clone(); Features2d.drawMatches(orig, kpOrigin, maple, keypointsMaple, resultMaple, imageOut); public MatOfKeyPoint createSURFdetector (Mat origBW) { FeatureDetector surf = FeatureDetector.create(FeatureDetector.FAST); MatOfKeyPoint keypointsOrig = new MatOfKeyPoint(); surf.detect(origBW, keypointsOrig); return keypointsOrig; } public Mat extractDescription (MatOfKeyPoint kpOrig, Mat origBW) { DescriptorExtractor surfExtractor = DescriptorExtractor.create(FeatureDetector.SURF); Mat origDesc = new Mat(); surfExtractor.compute(origBW, kpOrig, origDesc); return origDesc; } public Leaf findMatches (Mat descriptors) { DescriptorMatcher m = DescriptorMatcher.create(DescriptorMatcher.BRUTEFORCE); MatOfDMatch max = new MatOfDMatch(); resultMaple = new MatOfDMatch(); resultChestnut = new MatOfDMatch(); resultSwedish = new MatOfDMatch(); Leaf match = null; m.match(descriptors, mapleDescriptors, resultMaple); Log.d("Origin", resultMaple.toList().size()+" matches with Maples"); if (resultMaple.toList().size() > max.toList().size()) { max = resultMaple; match = Leaf.MAPLE; } m.match(descriptors, chestnutDescriptors, resultChestnut); Log.d("Origin", resultChestnut.toList().size()+" matches with Chestnut"); if (resultChestnut.toList().size() > max.toList().size()) { max = resultChestnut; match = Leaf.CHESTNUT; } m.match(descriptors, swedishDescriptors, resultSwedish); Log.d("Origin", resultSwedish.toList().size()+" matches with Swedish"); if (resultSwedish.toList().size() > max.toList().size()) { max = resultSwedish; match = Leaf.SWEDISH; } //return the match object with more matches return match; } 

¿Cómo puedo obtener una coincidencia más precisa no basada en los colores sino en las singularidades reales de la imagen?

Bueno, SURF no es el mejor candidato para esta tarea. El descriptor de SURF básicamente codifica algunas estadísticas de gradiente en un pequeño barrio de una esquina. Esto le da invariancia a muchas transformaciones, pero usted pierde el "cuadro grande" al hacer esto. Este descriptor se utiliza para reducir una gama de correspondencias entre los puntos que se van a emparejar, y luego algunos contratiempos geométricos entran en juego.

En su caso, parece que los descriptores no están haciendo un gran trabajo en los puntos de coincidencia, y ya que hay un montón de ellos cada punto finalmente obtiene un partido (aunque es extraño que las pruebas geométricas no impidió que).

Puedo sugerirle que pruebe diferentes enfoques para hacer coincidir, tal vez HOG con descriptores entrenados para detectar tipos de hojas, o incluso algo basado en contornos, ya que la forma es lo que es realmente diferente entre sus imágenes. Usted puede por ejemplo detectar el contorno de la hoja, normalizar su longitud, encontrar su centro y luego en intervalos iguales calcular la distancia de cada punto al centro – que será su descriptor. Que encontrar la longitud más grande y desplazar circularmente este descriptor para comenzar en los extremos y dividir por este valor – que le dará alguna invariancia básica a la elección del punto de inicio del contorno, la rotación y la escala. Pero lo más probable es que fracase en perspectiva y transformaciones afines.

Si desea experimentar más con puntos de características, intente detectar menos de ellos, pero los más representativos (filtrar por gradiente de fuerza, puntaje de esquina o algo). Tal vez use SIFT en lugar de SURF – debe ser un poco más preciso. Compruebe la cantidad de inliers después de hacer coincidir – el mejor partido debe tener mayor proporción.

Pero honestamente, esto se parece más a una tarea de aprendizaje de máquina que a una visión por computadora.

Edit: He comprobado su código y se enteró de que usted no está realizando controles geométricos en los partidos, por lo tanto, por qué está recibiendo partido incorrecto. Intente realizar findHomography después de hacer coincidir y, a continuación, considere sólo los puntos que se han establecido en un argumento de salida de mask . Esto hará que sólo se consideran puntos que pueden ser deformados entre sí mediante la homografía y puede mejorar la coincidencia de un lote.

Edit2: agregó un fragmento de código (lo siento, pero no puedo probar Java en este momento, por lo que está en Python)

 import cv2 import numpy as np # read input a = cv2.imread(r'C:\Temp\leaf1.jpg') b = cv2.imread(r'C:\Temp\leaf2.jpg') # convert to gray agray = cv2.cvtColor(a, cv2.COLOR_BGR2GRAY) bgray = cv2.cvtColor(b, cv2.COLOR_BGR2GRAY) # detect features and compute descriptors surf = cv2.SURF() # better use SIFT instead kp1, d1 = surf.detectAndCompute(agray,None) kp2, d2 = surf.detectAndCompute(bgray,None) print 'numFeatures1 =', len(kp1) print 'numFeatures2 =', len(kp2) # use KNN matcher bf = cv2.BFMatcher() matches = bf.knnMatch(d1,d2, k=2) # Apply Lowe ratio test good = [] for m,n in matches: if m.distance < 0.75*n.distance: good.append(m) print 'numMatches =', len(matches) print 'numGoodMatches =', len(good) # if have enough matches - try to calculare homography to discard matches # that don't fit perspective transformation model if len(good)>10: # convert matches into correct format (python-specific) src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2) dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2) M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC,5.0) print 'numMatches =', sum(mask.ravel().tolist()) # calc number of 1s in mask else: print "not enough good matches are found" 

Me da la siguiente salida para diferentes hojas usando SURF

 numFeatures1 = 685 numFeatures2 = 1566 numMatches = 685 numGoodMatches = 52 numMatches = 11 

Puede ver que la cantidad de partidos "reales" es muy pequeña. Pero, desafortunadamente, numMatches es similar cuando hacemos coincidir diferentes imágenes del mismo tipo de hoja. Tal vez usted puede mejorar el resultado de ajustar los parámetros, pero creo que utilizando puntos clave aquí es sólo un enfoque no muy bueno. Tal vez sea debido a la variación de la hoja incluso dentro de una misma clase.

  • Android: OpenCV: imwrite devuelve siempre false y falla al escribir
  • OpenCv en Android: detección de puntos clave en imágenes de archivo
  • Grabación de procesamiento en vivo de OpenCV en Android
  • Error: no se puede encontrar la variable de símbolo GL_TEXTURE_EXTERNAL_OES + OpenCV en Android Studio
  • Cómo extraer líneas de cada contorno en OpenCV para Android?
  • ¿Cómo comprobar si dos imágenes son similares o no usando openCV en java?
  • Matcher Assertions error error opencv Android
  • Pasar una matriz de Mats a código nativo
  • Utilizar NDK en Android Studio (OpenCV)
  • Creación de un paquete de biblioteca de Android que incluye un paquete externo (nativo o Java)
  • Problema de orientación de la cámara OpenCV
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.