2012-07-04 17 views
11

Ho bisogno di un algoritmo di hashing dell'immagine (preferibilmente semplice e veloce). Il valore di hash viene utilizzato in una tabella di ricerca, non per la crittografia.Algoritmo di hashing dell'immagine semplice e veloce

Alcune delle immagini sono "computer graphic" - cioè ripieni a colori pieni, testi rasterizzati e così via, mentre ci sono anche immagini "fotografiche" - contenenti uno spettro di colori ricco, per lo più regolare, con un'ampiezza di rumore ragionevole.

Mi piacerebbe anche che l'algoritmo di hash potesse essere applicato a specifiche parti dell'immagine. Voglio dire, l'immagine può essere divisa in celle di griglia e la funzione di hash di ogni cella dovrebbe dipendere solo dal contenuto di questa cella. In modo che si possa individuare rapidamente se due immagini hanno aree comuni (nel caso siano allineate in modo appropriato).

Nota: Ho solo bisogno di sapere se due immagini (o loro parti) sono identici . Cioè, non ho bisogno di abbinare immagini simili, non c'è bisogno di riconoscimento delle funzioni, correlazione e altre tecniche DSP.

Mi chiedo quale sia l'algoritmo di hashing preferito.

Per le immagini "fotografiche", solo XOR-in tutti i pixel all'interno di una cella della griglia è ok più o meno. La probabilità dello stesso valore di hash per immagini diverse è piuttosto bassa, soprattutto perché la presenza del rumore (quasi bianco) rompe tutte le simmetrie potenziali. Inoltre, lo spettro di tale funzione di hash sembra buono (qualsiasi valore è possibile con quasi la stessa probabilità).

Ma un algoritmo così ingenuo non può essere utilizzato con la grafica "artificiale". Pixel identici, pattern ripetuti, invarianza di offset geometrica sono molto comuni per tali immagini. XOR-tutti i pixel daranno 0 per ogni immagine con un numero pari di pixel identici.

L'utilizzo di qualcosa come CRT-32 sembra un po 'promettente, ma mi piacerebbe immaginare qualcosa di più veloce. Ho pensato di formula iterativa, ogni nuovo pixel muta il valore hash corrente, in questo modo:

hashValue = (hashValue * /*something*/ | newPixelValue) % /* huge prime */ 

Facendo numero primo modulo dovrebbe probabilmente dare una buona dispersione, in modo che io sto sporgendosi verso questa opzione. Ma mi piacerebbe sapere se ci sono varianti migliori.

Grazie in anticipo.

+0

perché non usi un semplice algoritmo di hashing come md5? –

+0

@Karoly Horvath: buona domanda. In effetti, questo è ciò di cui ho bisogno più o meno. Comunque MD5 è (presumibilmente) affamato di CPU, è progettato per essere una funzione hash unidirezionale. OTOH Ho bisogno di qualcosa di molto più semplice, dal momento che non ho considerazioni sulla sicurezza. Ho pensato a CRC-32. Ma mi piacerebbe capire qualcosa di ancora più semplice – valdo

+0

Se lo fai su molte immagini, il collo di bottiglia sarà la tua velocità del disco .. –

risposta

7

Se si desidera renderlo molto veloce, è consigliabile prendere in considerazione un sottoinsieme casuale dei pixel per evitare di leggere l'intera immagine. Quindi, calcola una funzione hash sulla sequenza di valori a quei pixel. Il sottoinsieme casuale deve essere selezionato da un generatore di numeri pseudo-casuali deterministico con seme fisso in modo che le immagini identiche producano sottoinsiemi identici e di conseguenza hash identici.

Questo dovrebbe funzionare abbastanza bene anche per le immagini artificiali. Tuttavia, se si dispone di immagini che differiscono l'una dall'altra per un piccolo numero di pixel, questo darà collisioni di hash. Altre iterazioni danno una maggiore affidabilità. Se questo è il caso, ad esempio, se è probabile che le tue immagini abbiano coppie con un pixel diverso, devi leggere ogni pixel per calcolare il valore hash. Prendere una semplice combinazione lineare con coefficienti pseudo-casuali sarebbe abbastanza buono anche per le immagini artificiali.

pseudo-codice di un semplice algoritmo

Random generator = new generator(2847) // Initialized with fixed seed 
int num_iterations = 100 

int hash(Image image) { 
    generator.reset() //To ensure consistency on each evaluation 
    int value = 0 
    for num_iteration steps { 
     int nextValue = image.getPixel(generator.nextInt()%image.getSize()).getValue() 
     value = value + nextValue*generator.nextInt() 
    } 
    return value 
} 
+0

Grazie per la risposta. Non ho alcun problema a leggere l'intera cella della griglia. Le mie celle della griglia sono piuttosto piccole (8x8 o 16x16). Inoltre, quando i valori hash di due immagini sono uguali, sono sicuro che le immagini siano uguali. L'unico parametro mancante è la funzione di hash stessa. Cosa dovrebbe essere? – valdo

+2

Se non si richiede la sicurezza crittografica e si preoccupano solo delle immagini artificiali, una semplice combinazione lineare dei valori dei pixel con coefficienti casuali dovrebbe essere sufficiente, come ho descritto. Il problema è analogo al trovare l'hash di un array intero come v1 = [34,2,4,92,3], v2 = [10,3,5,20,3]. Il tuo obiettivo è quello di trovare hash di loro per vedere quali sono uguali. Scegli un vettore fisso scelto a caso m = [72,37,1,4,34] inizialmente. Per ogni vettore di input, il valore hash di v1 è v1 * m = 34 * 72 + 2 * 37 + 4 * 1 + 92 * 4 + 3 * 34. Puoi calcolare questo modulo anche in primo piano, se vuoi. – akashnil

5

Date un'occhiata a questo tutorial l'algoritmo phash http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html che viene utilizzato per trovare le immagini corrispondenti a stretto contatto.

+0

Grazie per l'attenzione, ma questo non è quello che voglio IMHO. L'algoritmo descritto è utile per trovare immagini "simili", ma è anche invariante. Il mio problema è molto più semplice e voglio una soluzione molto più efficiente. – valdo

+0

@valdo: ho aggiunto ulteriori informazioni. – Bytemain

Problemi correlati