Esta no es la mejor solución, pero es una solución. Me gustaría aprender mejores técnicas:
Si no se iban a rotar o escalar, podría usar una simple correlación cruzada de las imágenes. Habrá un pico brillante donde sea que aparezca la imagen pequeña en la imagen grande.
Puede acelerar la correlación cruzada utilizando un método FFT, pero si solo está haciendo coincidir una imagen de origen pequeña con una imagen de destino grande, el método de multiplicar y agregar fuerza bruta es a veces (no generalmente) más rápido.
Fuente:
Objetivo:
Correlación cruzada:
Los dos puntos brillantes son las ubicaciones que coinciden.
Pero sí tiene un parámetro de rotación en su imagen de ejemplo, por lo que no funcionará por sí solo. Si solo se permite la rotación, y no la escala, entonces todavía es posible usar la correlación cruzada, pero debe correlacionar cruzada, rotar la fuente, correlacionarla cruzada con toda la imagen objetivo, rotarla nuevamente, etc. para Todas las rotaciones.
Tenga en cuenta que esto no necesariamente encontrará la imagen. Si la imagen de origen es ruido aleatorio y el objetivo es ruido aleatorio, no lo encontrará a menos que busque exactamente en el ángulo correcto. Para situaciones normales, probablemente lo encontrará, pero depende de las propiedades de la imagen y los ángulos en los que busque.
Esta página muestra un ejemplo de cómo se haría, pero no proporciona el algoritmo.
Cualquier compensación donde la suma está por encima de un umbral es una coincidencia. Puede calcular la bondad de la coincidencia correlacionando la imagen de origen consigo misma y dividiendo todas sus sumas por este número. Una combinación perfecta será 1.0.
Sin embargo, esto será muy pesado desde el punto de vista informático, y probablemente haya mejores métodos para hacer coincidir los patrones de puntos (que me gustaría saber).
Ejemplo rápido de Python usando escala de grises y método FFT:
from __future__ import division
from pylab import *
import Image
import ImageOps
source_file = 'dots source.png'
target_file = 'dots target.png'
# Load file as grayscale with white dots
target = asarray(ImageOps.invert(Image.open(target_file).convert('L')))
close('all')
figure()
imshow(target)
gray()
show()
source_Image = ImageOps.invert(Image.open(source_file).convert('L'))
for angle in (0, 180):
source = asarray(source_Image.rotate(angle, expand = True))
best_match = max(fftconvolve(source[::-1,::-1], source).flat)
# Cross-correlation using FFT
d = fftconvolve(source[::-1,::-1], target, mode='same')
figure()
imshow(source)
# This only finds a single peak. Use something that finds multiple peaks instead:
peak_x, peak_y = unravel_index(argmax(d),shape(d))
figure()
plot(peak_y, peak_x,'ro')
imshow(d)
# Keep track of all these matches:
print angle, peak_x, peak_y, d[peak_x,peak_y] / best_match
Mapas de bits de 1 color
Sin embargo, para mapas de bits de 1 color, esto sería mucho más rápido. La correlación cruzada se convierte en:
- Coloque la imagen de origen sobre la imagen de destino
- Mueve la imagen de origen en 1 píxel
- bitwise-Y todos los píxeles superpuestos
- suma todos los 1s
- ...
Umbralizar una imagen en escala de grises a binario y luego hacer esto podría ser lo suficientemente bueno.
Punto de nube
Si la fuente y el objetivo son patrones de puntos, un método más rápido sería encontrar los centros de cada punto (correlacionar una vez con un punto conocido y luego encontrar los picos) y almacenarlos como un conjunto de puntos, luego hacer coincidir la fuente para apuntar girando, traduciendo y encontrando el error de mínimos cuadrados entre los puntos más cercanos en los dos conjuntos.