6

Ho passato post ed esempi negli ultimi due giorni e tutti i frammenti che ho provato e ampiamente testato si sono dimostrati abbastanza inutili, almeno per i miei scopi.Confronto immagini per immagini vettoriali (basato sul rilevamento dei bordi)?

Quello che voglio fare è confrontare un simbolo vettoriale nero fotografato su un muro o un pezzo di carta (qualità simile a immagini scansionate male si potrebbe dire) e confrontarlo con una versione elettronica dello stesso simbolo o simile (che sarebbe essere memorizzati localmente e confrontati con la fotografia). Si prega di dare un'occhiata alle due immagini allegate, la prima pulita (immagine di riferimento) è la versione del database del simbolo e la seconda è un disegno schifoso che ho fatto su un pezzo di carta che ho poi fotografato con il mio iPad.

Reference Image

Test Image

ho voluto la procedura di andare come segue:

  • Le due immagini vengono caricate e poi tagliati usando una versione modificata di questo algoritmo rifilatura ho trovato qui: Trimming images with PIL . Ho trovato che un valore 'soglia' di 50 e un valore 'ovvietà' di 20 (parametri nello script linked) danno buoni risultati di tali immagini
  • Le immagini saranno quindi ridimensionate alla stessa dimensione e comparati

Ora per il confronto, ho provato un sacco di approcci diversi suggeriti ma finora i risultati sono terribili. Posso effettivamente ottenere risultati di confronto migliori con un'immagine casuale rispetto a quella testata. Ho provato RMS difference comparison in base alle immagini effettive, ai loro bordi (creati con la funzione 'filtro' con ImageFilter.CONTOUR o ImageFilter.FIND_EDGES), Pixel-Based Comparison ma finora nulla ho trovato online (nonostante il mio googliling incessante) o qui in StackOverflow ha mi ha dato risultati decenti.

Credo che il problema risieda nello sfondo rumoroso dell'immagine di prova ma non sono stato in grado di dimostrarlo. Qualcuno sa se c'è un modo per ottenere un contorno vettoriale dai bordi di queste immagini e confrontarle non solo come immagini ma come vettori di immagini? Nonostante il mio schifoso disegno, trovo che queste due immagini siano abbastanza simili e dovrebbe essere possibile ottenere un buon paragone.

+0

Ci sono problemi con il metodo basato su vettori, come si gestiscono i segni vaganti errati o le immagini disegnate con proporzioni diverse? In aggiunta alla mia risposta, se riesci a ottenere immagini normalizzate, un approccio rasterizzato usando le eigenfaces (vedi wiki) può essere utile qui (anche se richiede un'intensità computazionale e richiede un'algebra lineare). – Hooked

risposta

4

Per ottenere una risposta migliore è necessario limitare meglio l'ambito dell'applicazione. Ecco qualcosa che potrebbe aiutarti. Suppongo che il tuo input "crappy drawing" sia sempre simile a quello che hai fornito nel senso che ha bordi forti, e il colore presente su di esso è irrilevante. Per risolvere (o, meglio, per avvicinarti a una soluzione per) il tuo problema in modo semplice, devi descrivere entrambe le immagini in termini di descrittori invarianti di scala.

La mia opinione su di esso: binarize entrambe le immagini, contare il numero di componenti collegati (CC) in entrambi, scartare CC di dimensione irrilevante (troppo lontano dalla media, media, relativa a stddev, ecc, si decide). Potresti voler integrare il secondo passo, per discriminare meglio l'immagine da altri input, ad esempio, più potente vuoi il tuo approccio, più descrittori discriminanti ti serviranno. Ad un certo punto potresti anche prendere in considerazione l'utilizzo di SVM o altre tecniche di apprendimento automatico.

Quindi, la fase di binarizzazione: esegue un gradiente morfologico e scarta gradiente debole. Questo è molto facile se gli input sono simili a ciò che è stato pubblicato. Ecco quello che ottengo con una soglia di intensità a 60 (sto assumendo anche l'input è nel range [0, 255]):

enter image description here enter image description here

ho subito sperimentato con soglie che vanno fino al 90, e tutti loro hanno lavorato per queste immagini. Ritaglio questi è facile, e si può anche Riempi lo sfondo e l'oggetto:

enter image description here enter image description here

Ora è possibile estrarre i componenti collegati in bianco e fare l'analisi su di essi. In questo caso, la cosa più semplice da fare è contarli. Per questi input, otteniamo 12 nell'immagine "perfetta" e 14 nella "cattiva". Ma, in quella "cattiva", abbiamo 2 componenti di dimensione 1 (c'è solo un pixel in ognuno di essi), che sono eliminati banalmente. Ci sono molti altri modi per confrontare i componenti connessi, ma spero che questo possa farti iniziare. Se hai bisogno del codice per queste attività, posso includerlo.

+0

Wow mi hai solo fatto saltare in aria :) Qualcosa mi dice che questa non era la tua prima volta: P Puoi per favore includere il codice per i test in modo che io possa sperimentarlo (non devi incollarlo qui, un file allegato sarebbe fantastico)? Grazie mille! – somada141

+0

Che bello, spero che tu possa usarlo. Ecco il codice suddiviso in due file: http://pastebin.com/SGhw0fMZ e http://pastebin.com/mRZ0mzVa, è molto semplice e può essere migliorato in molti modi. – mmgp

0

Penso che se visualizzi le linee come bordi su un grafico e le intersezioni come nodi, anche se uno è fugace, il computer dovrebbe essere in grado di vedere che sono lo stesso segno. Gioca con i livelli per ottenere i tuoi bianchi e neri, quindi prova ad analizzare i punti neri contigui.

+0

Grazie per la risposta Voronoi, potresti per caso sapere come fare ciò che stai suggerendo? Non riesco a trovare alcuna informazione sulle immagini vettoriali con PIL – somada141

+0

http://codeboje.de/pysvg/ è una libreria SVG decente che puoi provare. Quello che stai facendo è abbastanza difficile, quindi MIGLIORE DI FORTUNA. – VoronoiPotato

+0

per il rilevamento dei bordi cerco pixel neri che si trovano accanto a pixel bianchi/pixel grigi dopo il contrasto. Definisci il loop esterno per così dire, trova i bordi interni, prova ad associare prendendo una fila di pixel e facendo l'analisi di (bianco, nero, bianco, nero) – VoronoiPotato

1

Non sono sicuro di come farlo in modo specifico con PIL, ma posso indicarvi alcuni buoni esempi di lavoro per aiutarvi ad apprendere da soli (questo è un compito non banale per l'elaborazione delle immagini!).

Un buon esempio di lavoro è DeTeXify, un programma che corrisponde a un simbolo disegnato con il mouse con una grande libreria di simboli noti (in questo caso i simboli che è possibile creare nel programma di composizione LaTeX). Sono disponibili il codice sorgente per il fronte e il back-end.

Un altro esempio è ShapeCatcher cui:

... usi cosiddetti "contesto della forma" per trovare le somiglianze tra le due forme. Contesti di forme, un robusto modo matematico di descrivere il concetto di somiglianza tra le forme, è un descrittore di funzioni proposto per la prima volta da Serge Belongie e Jitendra Malik.

Un documento di ricerca disponibile gratuitamente per contesti di forme può essere trovato sul loro Berkeley site.

+0

Grazie per i tuoi suggerimenti Hooked, sfortunatamente voglio che questo codice funzioni su Pythonista, l'ambiente iOS di Python che sfortunatamente non consente l'installazione di librerie di terze parti e non è nemmeno dotato di numpy o scipy, quindi ho bisogno di trovare un modo per far funzionare quanto sopra con le librerie Python standard. Ho sperato che sarebbe stato un compito facile con PIL ma mi stavo ingannando :) – somada141

+1

@ somada141 Capito (anche se sarebbe stato bello conoscere i vincoli nella domanda!). Continuo a pensare che i riferimenti siano validi in quanto è possibile vedere gli algoritmi coinvolti in un'implementazione a livello di produzione. – Hooked

0

C'è un metodo chiamato SIFT. OpenCV lo usa e c'è anche un'implementazione in Python OpenCV. L'implementazione è SURF in OpenCV, si possono trovare varie domande ed esempi, e funziona bene. C'è un esempio nella domanda this.

(Distacco questa risposta come un riferimento in più)

0

So che questo è già stato risposto, ma forse qualcuno sarà ancora trovare questo.

Diversamente dalla risposta accettata, non avrei affrontato il gradiente per eseguire la binarizzazione, ma guarderei invece a Otsu's Thresholding. Questo dovrebbe funzionare bene se tutte le tue immagini contengono solo regioni molto scure e molto chiare, dato che cerca i due picchi nell'istogramma delle immagini (uno per tutti i pixel chiari, uno per tutti i pixel scuri) e quindi le soglie su un valore in tra le due cime.