Esta publicación fue el punto de partida de mi solución, muchas buenas ideas aquí, así que pensé en compartir mis resultados. La idea principal es que he encontrado una manera de evitar la lentitud de la coincidencia de imágenes basada en puntos clave mediante la explotación de la velocidad de phash.
Para la solución general, es mejor emplear varias estrategias. Cada algoritmo es el más adecuado para ciertos tipos de transformaciones de imagen y puede aprovecharlo.
En la parte superior, los algoritmos más rápidos; en la parte inferior la más lenta (aunque más precisa). Puede omitir los lentos si se encuentra una buena coincidencia en el nivel más rápido.
- basado en hash de archivo (md5, sha1, etc.) para duplicados exactos
- hashing perceptual (phash) para imágenes redimensionadas
- basado en funciones (SIFT) para imágenes modificadas
Estoy teniendo muy buenos resultados con phash. La precisión es buena para las imágenes reescaladas. No es bueno para imágenes modificadas (perceptualmente) (recortadas, rotadas, reflejadas, etc.). Para lidiar con la velocidad de hash debemos emplear un caché de disco / base de datos para mantener los hashes para el pajar.
Lo realmente bueno de phash es que una vez que construye su base de datos hash (que para mí es de aproximadamente 1000 imágenes / seg), las búsquedas pueden ser muy, muy rápidas, en particular cuando puede mantener toda la base de datos hash en la memoria. Esto es bastante práctico ya que un hash tiene solo 8 bytes.
Por ejemplo, si tiene 1 millón de imágenes, requeriría una matriz de 1 millón de valores hash de 64 bits (8 MB). ¡En algunas CPU esto cabe en el caché L2 / L3! En el uso práctico, he visto una comparación corei7 a más de 1 Giga-hamm / seg, solo es una cuestión de ancho de banda de memoria para la CPU. ¡Una base de datos de 1 mil millones de imágenes es práctica en una CPU de 64 bits (se necesitan 8 GB de RAM) y las búsquedas no excederán 1 segundo!
Para imágenes modificadas / recortadas, parecería una característica invariante de transformación / detector de punto clave como SIFT es el camino a seguir. SIFT producirá buenos puntos clave que detectarán recorte / rotación / espejo, etc. Sin embargo, la comparación del descriptor es muy lenta en comparación con la distancia de hamming utilizada por phash. Esta es una limitación importante. Hay muchas comparaciones que hacer, ya que el descriptor IxJxK máximo se compara con la búsqueda de una imagen (I = num imágenes de pajar, J = puntos clave de destino por imagen de pajar, K = puntos clave de objetivo por imagen de aguja).
Para evitar el problema de la velocidad, intenté usar phash alrededor de cada punto clave encontrado, usando el tamaño / radio de la función para determinar el sub-rectángulo. El truco para hacer que esto funcione bien es hacer crecer / reducir el radio para generar diferentes niveles sub-rect (en la imagen de la aguja). Por lo general, el primer nivel (sin escala) coincidirá, sin embargo, a menudo se necesitan algunos más. No estoy 100% seguro de por qué esto funciona, pero me imagino que habilita características que son demasiado pequeñas para que phash funcione (phash reduce las imágenes a 32x32).
Otro problema es que SIFT no distribuirá los puntos clave de manera óptima. Si hay una sección de la imagen con muchos bordes, los puntos clave se agruparán allí y no obtendrá ninguno en otra área. Estoy usando el GridAdaptedFeatureDetector en OpenCV para mejorar la distribución. No estoy seguro de qué tamaño de cuadrícula es mejor, estoy usando una cuadrícula pequeña (1x3 o 3x1 dependiendo de la orientación de la imagen).
Probablemente desee escalar todas las imágenes del pajar (y la aguja) a un tamaño más pequeño antes de la detección de características (uso 210 px a lo largo de la dimensión máxima). Esto reducirá el ruido en la imagen (siempre es un problema para los algoritmos de visión por computadora), también enfocará el detector en características más prominentes.
Para las imágenes de personas, puede intentar la detección de rostros y usarla para determinar el tamaño de la imagen a escalar y el tamaño de la cuadrícula (por ejemplo, el rostro más grande escalado a 100px). El detector de características tiene en cuenta los niveles de escala múltiple (usando pirámides) pero hay una limitación en la cantidad de niveles que usará (esto se puede ajustar, por supuesto).
El detector de puntos clave probablemente funciona mejor cuando devuelve menos que la cantidad de características que deseaba. Por ejemplo, si solicita 400 y obtiene 300 de vuelta, eso es bueno. Si recuperas 400 cada vez, probablemente algunas buenas características tuvieron que omitirse.
La imagen de la aguja puede tener menos puntos clave que las imágenes del pajar y aún así obtener buenos resultados. Agregar más no necesariamente te brinda grandes ganancias, por ejemplo, con J = 400 y K = 40, mi tasa de aciertos es de aproximadamente 92%. Con J = 400 y K = 400, la tasa de aciertos solo sube al 96%.
Podemos aprovechar la velocidad extrema de la función hamming para resolver el escalado, la rotación, la duplicación, etc. Se puede utilizar una técnica de paso múltiple. En cada iteración, transforme los sub-rectángulos, vuelva a hacer hash y vuelva a ejecutar la función de búsqueda.