Questo post è stato il punto di partenza della mia soluzione, molte buone idee qui quindi ho pensato di condividere i miei risultati. L'intuizione principale è che ho trovato un modo per aggirare la lentezza della corrispondenza delle immagini basata su punti chiave sfruttando la velocità di phash.
Per la soluzione generale, è meglio utilizzare diverse strategie. Ogni algoritmo è più adatto per determinati tipi di trasformazioni di immagini e puoi trarne vantaggio.
Nella parte superiore, gli algoritmi più veloci; in fondo il più lento (anche se più preciso). Potresti saltare quelli lenti se si trova una buona corrispondenza al livello più veloce.
- basato su file hash (md5, sha1, ecc.) per duplicati esatti
- hashing percettivo (phash) per le immagini ridimensionate
- basato su funzionalità (SIFT) per immagini modificate
Sto ottenendo ottimi risultati con Phash. La precisione è buona per le immagini ridimensionate. Non va bene per le immagini (percettivamente) modificate (ritagliate, ruotate, specchiate, ecc.). Per gestire la velocità di hashing dobbiamo utilizzare una cache / database del disco per mantenere gli hash per il pagliaio.
La cosa veramente bella di phash è che una volta creato il tuo database di hash (che per me è di circa 1000 immagini / sec), le ricerche possono essere molto, molto veloci, in particolare quando puoi tenere in memoria l'intero database di hash. Questo è abbastanza pratico poiché un hash ha solo 8 byte.
Ad esempio, se si dispone di 1 milione di immagini, sarebbe necessario un array di 1 milione di valori hash a 64 bit (8 MB). Su alcune CPU questo si adatta alla cache L2 / L3! Nell'uso pratico ho visto un corei7 comparare a oltre 1 Giga-hamm / sec, è solo una questione di larghezza di banda di memoria della CPU. Un database da 1 miliardo di immagini è pratico su una CPU a 64 bit (sono necessari 8 GB di RAM) e le ricerche non supereranno 1 secondo!
Per le immagini modificate / ritagliate sembrerebbe una caratteristica invariante trasformata / rilevatore di punti chiave come SIFT è la strada da percorrere. SIFT produrrà buoni punti chiave che rileveranno ritaglia / ruota / specchia ecc. Tuttavia, il confronto del descrittore è molto lento rispetto alla distanza di percussione usata da Phash. Questa è una grande limitazione. Ci sono molti paragoni da fare, poiché ci sono paragoni IxJxK massimi comparabili per cercare un'immagine (I = immagini del pagliaio num, J = punti chiave target per immagine del pagliaio, K = punti chiave target per immagine dell'ago).
Per aggirare il problema della velocità, ho provato a usare phash attorno a ciascun punto chiave trovato, usando la dimensione / raggio della funzione per determinare il rettangolo secondario. Il trucco per far funzionare bene questo è aumentare / ridurre il raggio per generare diversi livelli di sottoretto (sull'immagine dell'ago). In genere il primo livello (senza scala) corrisponderà, tuttavia spesso ne occorrono alcuni di più. Non sono sicuro al 100% del perché funzioni, ma posso immaginare che abiliti funzionalità troppo piccole per far funzionare phash (phash ridimensiona le immagini fino a 32x32).
Un altro problema è che SIFT non distribuirà i punti chiave in modo ottimale. Se c'è una sezione dell'immagine con molti bordi, i punti chiave si raggrupperanno lì e non ne otterrai nessuno in un'altra area. Sto usando GridAdaptedFeatureDetector in OpenCV per migliorare la distribuzione. Non sono sicuro di quale sia la dimensione migliore della griglia, sto usando una piccola griglia (1x3 o 3x1 a seconda dell'orientamento dell'immagine).
Probabilmente vuoi ridimensionare tutte le immagini del pagliaio (e dell'ago) su una dimensione più piccola prima del rilevamento delle caratteristiche (io uso 210 px lungo la dimensione massima). Ciò ridurrà il rumore nell'immagine (sempre un problema per gli algoritmi di visione artificiale), inoltre focalizzerà il rilevatore su funzioni più importanti.
Per le immagini di persone, potresti provare il rilevamento del viso e utilizzarlo per determinare la dimensione dell'immagine su cui ridimensionare e la dimensione della griglia (ad esempio il viso più grande ridimensionato su 100px). Il rilevatore di funzionalità tiene conto di più livelli di scala (usando le piramidi) ma esiste un limite al numero di livelli che utilizzerà (questo è ovviamente sintonizzabile).
Il rilevatore di punti chiave probabilmente funziona meglio quando restituisce meno del numero di funzioni desiderate. Ad esempio, se chiedi 400 e ne ricevi 300, va bene. Se ne ritorni 400 ogni volta, probabilmente alcune caratteristiche interessanti dovevano essere tralasciate.
L'immagine dell'ago può avere meno punti chiave rispetto alle immagini del pagliaio e ottenere comunque buoni risultati. Aggiungere di più non comporta necessariamente enormi guadagni, ad esempio con J = 400 e K = 40 il mio tasso di successo è di circa il 92%. Con J = 400 e K = 400 la percentuale di successo arriva solo al 96%.
Possiamo sfruttare l'estrema velocità della funzione di martellamento per risolvere il ridimensionamento, la rotazione, il mirroring, ecc. È possibile utilizzare una tecnica a più passaggi. Ad ogni iterazione, trasforma i rettangoli secondari, ri-hash ed esegui di nuovo la funzione di ricerca.