Come riconoscere i rettangoli in questa immagine?
-
08-07-2019 - |
Domanda
Ho un'immagine con linee orizzontali e verticali. In effetti, questa immagine è il sito Web della BBC convertito in linee orizzontali e verticali. Il mio problema è che voglio essere in grado di trovare tutti i rettangoli nell'immagine. Voglio scrivere un programma per computer per trovare tutti i rettangoli. Qualcuno sa come fare questo o suggerire idee su come iniziare? Questo compito è facile per me come persona trovare i rettangoli visivi, ma non sono sicuro di come descriverlo come programma.
L'immagine è il sito Web della BBC qui http://www.bbc.co.uk/
Aggiornamento a questo, ho scritto il codice che converte l'immagine del sito Web della BBC in linea orizzontale e verticale, il problema è che queste linee non si incontrano completamente agli angoli e a volte non formano completamente un rettangolo. Grazie!
Soluzione
Opencv (libreria di elaborazione delle immagini e visione artificiale scritta in c) ha un'implementazione per Hough Transform ( la semplice trasformazione hough trova linee in un'immagine, mentre quella generalizzata trova oggetti più complessi), quindi potrebbe essere un buon inizio. Per i rettangoli che hanno angoli chiusi ci sono anche rilevatori di angoli come cornerHarris che possono aiutare.
Ho eseguito la demo di houghlines fornita con opencv ed ecco il risultato sull'immagine che hai dato (linee rilevate contrassegnate in rosso):
(fonte: splintec.com )
Altri suggerimenti
Credo che tu stia cercando la trasformazione Hough generalizzata .
Nella visione artificiale esiste un algoritmo chiamato Generalized Hough Transform che forse può risolvere il tuo problema . Dovrebbe esserci un codice open source che ha implementato questo algoritmo. Basta cercarlo.
Supponendo che sia un'immagine ragionevolmente priva di rumore (non un video di uno schermo), allora uno dei semplici algoritmi di allagamento dovrebbe funzionare. Potrebbe essere necessario eseguire una dilatazione / erosione sull'immagine per colmare le lacune.
Il modo normale di trovare le linee è una trasformazione di Hough (quindi trova le linee ad angolo retto) Opencv è il modo più semplice.
Dai un'occhiata a questa domanda OpenCV Object Detection - Center Point
Esistono diversi approcci al problema. Vorrei utilizzare uno elaborazione morfologica di immagini come questo . Avrai la flessibilità di definire "rettangolo" anche qualcosa che non è "chiuso esattamente" (dove l'algoritmo di riempimento fallirà).
Un'altra possibilità potrebbe essere quella di utilizzare un approccio machine learning , che sostanzialmente è più dati- guidato da definizione guidato come quello precedente. Dovrai fornire al tuo algoritmo diversi "esempi" di cosa sia un rettangolo e alla fine imparerà (con un bias e un tasso di errore) .
iterare da sinistra a destra fino a quando non si colpisce un pixel di colore, quindi utilizzare l'algoritmo di riempimento flood modificato. maggiori informazioni sull'algo flood flood @ wiki
un altro approccio sarebbe quello di trovare QUALSIASI pixel colorato sull'immagine e poi andare con
while(pixel under current is colored)
{
lowest pixel coordinate = pixel under current
current = pixel under
}
quindi fai lo stesso verso l'alto. ora hai definito una sola riga. quindi usa le estremità delle linee per approssimare le linee in rettangoli. se non sono pixel perfetti, potresti fare una sorta di tresholding.
Il riempimento dell'inondazione funzionerebbe oppure potresti utilizzare una modifica di un algoritmo di tracciamento dei bordi.
quello che fai è: crea un array 2d (o qualsiasi altra struttura di dati d2): ogni riga rappresenta una linea di pixel orizzontale sullo schermo e ogni colonna una linea verticale
scorre tutti i pixel, da sinistra a destra, e ogni volta che ne trovi uno colorato aggiungi le sue coordinate all'array
itera attraverso l'array e trova le linee e memorizza il pixel iniziale e finale per ognuno (diversa struttura di dati)
sapendo che l'inizio di ogni riga è il suo pixel sinistro / superiore, puoi facilmente verificare se 4 righe comprendono un rettangolo
Per ottenere dall'immagine che hai con le linee orizzontali e verticali quasi toccanti solo i rettangoli:
- Converti in binario (cioè tutte le righe sono bianchi, il resto è nero)
- Esegui una Dilatazione binaria (qui crei ogni pixel che tocca un pixel bianco nell'immagine sorgente o è un pixel bianco nell'immagine sorgente bianco. Il tocco è solo dritto (quindi ogni pixel "tocca" i pixel a sinistra, a destra, sopra e sotto di esso) questo è chiamato "4-connesso" ;
- ripeti il ??passaggio 3 alcune volte se gli spazi tra le estremità sono più grandi di 2 pixel di larghezza, ma non troppo spesso!
- Esegui un'operazione scheletro (qui rendi neri tutti i pixel dell'immagine di output se si tratta di un pixel bianco nell'immagine sorgente che tocca almeno un pixel nero e i pixel bianchi che tocca (nell'immagine sorgente) si toccano tutti Di nuovo tocco definito con 4-connessione. Vedi esempio sotto.
- Ripeti il ??passaggio 4 fino a quando l'immagine non cambia dopo una ripetizione (tutti i pixel bianchi sono estremità di linea o connettori)
Questo, con un po 'di fortuna, mostrerà prima le scatole con linee grasse spesse, lasciando artefatti grassi spessi su tutta l'immagine (dopo il passaggio 3) e poi dopo il passaggio 5 saranno stati rimossi tutti gli artefatti grassi spessi, mentre rimangono tutte le scatole. È necessario modificare il numero di ripetizioni nel passaggio 3 per ottenere i migliori risultati. Se sei interessato alla morfologia delle immagini, questo è il libro di un corso introduttivo davvero buono che ho seguito.
Esempio: (0 = nero, 1 = bianco, i pixel al centro di ciascun blocco 3x3 sono considerati, input left, output right)
011 => 011
011 => 001 all other white pixels touch, so eliminate
011 => 011
010 => 010
010 => 010 top pixel would become disconnected, so leave
010 => 010
010 => 010
010 => 000 touches only one white pixel, so remove
000 => 000
010 => 010
111 => 111 does not touch black pixels, leave
010 => 010
010 => 010
011 => 011 other pixels do not touch. so leave
000 => 000