Questa non è la soluzione migliore, ma è una soluzione. Mi piacerebbe conoscere tecniche migliori:
Se non fossero stati ruotati o ridimensionati, è possibile utilizzare una semplice correlazione incrociata delle immagini. Ci sarà un picco luminoso ovunque l'immagine piccola si presenti nell'immagine grande.
È possibile accelerare la correlazione incrociata utilizzando un metodo FFT, ma se si sta semplicemente abbinando un'immagine di origine piccola con un'immagine di destinazione di grandi dimensioni, il metodo di moltiplicare e aggiungere forza bruta a volte (in genere) è più veloce.
Fonte:
Bersaglio:
Cross-correlazione:
I due punti luminosi sono le posizioni che corrispondono.
Ma voi fare avere un parametro di rotazione dell'immagine ad esempio, in modo che non funziona da solo. Se è consentita solo la rotazione e non il ridimensionamento, è comunque possibile utilizzare la correlazione incrociata, ma è necessario correlare in modo incrociato, ruotare la sorgente, correlarla in modo incrociato con l'intera immagine di destinazione, ruotarla di nuovo, ecc. Per tutte le rotazioni.
Nota che questo non troverà necessariamente l'immagine. Se l'immagine sorgente è un rumore casuale e il bersaglio è un rumore casuale, non lo troverai a meno che non cerchi esattamente l'angolo giusto. Per situazioni normali, probabilmente lo troverà, ma dipende dalle proprietà dell'immagine e dagli angoli in cui si cerca.
Questa pagina mostra un esempio di come sarebbe fatto, ma non fornisce l'algoritmo.
Qualsiasi offset in cui la somma è al di sopra di una certa soglia è una corrispondenza. Puoi calcolare la bontà della partita correlando l'immagine sorgente con se stessa e dividendo tutte le tue somme per questo numero. Una corrispondenza perfetta sarà 1.0.
Questo sarà molto pesante dal punto di vista computazionale, tuttavia, e probabilmente ci sono metodi migliori per abbinare modelli di punti (che vorrei sapere).
Esempio di Python rapido usando la scala di grigi e il metodo 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
Bitmap a 1 colore
Per bitmap a 1 colore, questo sarebbe molto più veloce, però. La correlazione incrociata diventa:
- Posiziona l'immagine di origine sull'immagine di destinazione
- Sposta l'immagine sorgente di 1 pixel
- bit-AND-tutti i pixel sovrapposti
- sommare tutti gli 1
- ...
Limitare un'immagine in scala di grigi a binario e quindi farlo potrebbe essere abbastanza buono.
Nuvola di punti
Se l'origine e il target sono entrambi modelli di punti, un metodo più rapido sarebbe quello di trovare i centri di ciascun punto (correlare una volta con un punto noto e quindi trovare i picchi) e memorizzarli come un insieme di punti, quindi abbinare l'origine mirare ruotando, traducendo e trovando l'errore dei minimi quadrati tra i punti più vicini nei due set.