8

Sono nuovo di elaborazione delle immagini e ho cercato di individuare le linee verticali di utilizzare questo code-rilevamento Line in immagine

image=imread('benzene.jpg'); 
BW = im2bw(image); 
w1=[-1 2 -1 ; -1 2 -1 ; -1 2 -1]; 
g=(imfilter(double(BW),w1)); 
g=abs(g); 
T=max(g(:)); 
g=g>=T; 
imshow(g); 

Questa era la mia immagine-

enter image description here

E questo è ciò che Ho ottenuto dopo aver eseguito le operazioni - enter image description here

Quindi la mia domanda è perché sto ricevendo questa uscita? Ci sono 10 ver linee verticali se i doppi legami verticali sono contati come 2 linee verticali distinte. Inoltre, se voglio ottenere orizzontale, verticale, 45 e -45 tutte le linee, come posso usare tutte e 4 le maschere per ottenere una singola uscita?

+0

può fare un collegamento on-line a questa immagine? Non riesco a trovarlo sulla rete – roni

+0

Ho risolto la mia domanda. Ho capito il mio errore, ma ora sto ottenendo di nuovo un risultato inaspettato. – Noober

+0

@roni Puoi salvare questa immagine da qui come non ho il link all'immagine ora. – Noober

risposta

11

Un semplice suggerimento che ho è quello di rilevare il gradiente e determinare l'orientamento di un punto di bordo. Ricordare che l'orientamento è nella direzione che è perpendicolare sul bordo. Pertanto, se si desidera trovare linee verticali, la direzione perpendicolare a una linea verticale è orizzontale, ovvero 180 gradi o -180 gradi rispetto al piano cartesiano. Pertanto, per ogni orientamento dei punti di bordo rilevati, se l'orientamento è -180 gradi o 180 gradi, impostare l'uscita di questa posizione su true, oppure su false. Per rilevare gli orientamenti dei gradienti, utilizzare imgradient dalla casella degli strumenti di elaborazione delle immagini. Sto assumendo questo è disponibile come sono stati utilizzati sia imread e im2bw e sono entrambi parte di quella cassetta degli attrezzi:

im = imread('http://i.stack.imgur.com/bdNOt.png'); 
tol = 5; 
[~,ang] = imgradient(im); 
out = (ang >= 180 - tol | ang <= -180 + tol); 
imshow(out); 

Il codice utilizza una variabile denominata tol per definire una tolleranza negli angoli si desidera rilevare a conto di rumore o bordi che sembrano verticali ma quando l'angolo è calcolato, potrebbe non sembrare. Fondamentalmente, stiamo cercando qualsiasi punto i cui angoli siano entro 180 gradi o -180 gradi.

Questo è quello che si ottiene:

enter image description here

Come mezzo di post-elaborazione, si potrebbe usare bwareaopen per filtrare le regioni di pixel le cui aree di scendere al di sotto di un certo importo.Approfittando del fatto che le linee verticali hanno una superficie maggiore rispetto alle altre pixel, si potrebbe fare qualcosa di simile:

out_filter = bwareaopen(out, 50); 

Otteniamo:

enter image description here


Ora, se si vuoi rilevare le linee orizzontali, dovresti trovare gli orientamenti dei gradienti che possono essere sia -90 o 90 gradi. Questo ha senso perché quelle linee che sono orizzontali, la direzione perpendicolare a una linea orizzontale è effettivamente verticale, e cioè sia -90 o 90 gradi. Se si desiderano le linee oblique, se si desidera una linea di appoggio a sinistra, cercare angoli di 45 gradi o -135 gradi e una linea di appoggio a destra, a -45 gradi o 135 gradi. Ti lascerò capire perché questi angoli sono davvero rappresentativi di questi tipi di linee.

Non sono righe orizzontali nell'immagine che hai fornito, quindi mi limiterò a cercare linee inclinate: linee che si appoggiano

Sinistra

Nota: ho dovuto aumentare la tolleranza dovuta agli errori di quantizzazione.

im = imread('http://i.stack.imgur.com/bdNOt.png'); 
tol = 20; 
[~,ang] = imgradient(im); 
out = (ang >= 45 - tol & ang <= 45 + tol) | (ang >= -135 - tol & ang <= -135 + tol); 
out_filter = bwareaopen(out, 50); 
imshow(out_filter); 

enter image description here

linee destro inclinate:

anche dovuto aumentare la tolleranza anche qui:

im = imread('http://i.stack.imgur.com/bdNOt.png'); 
tol = 20; 
[~,ang] = imgradient(im); 
out = (ang >= 135 - tol & ang <= 135 + tol) | (ang >= -45 - tol & ang <= -45 + tol); 
out_filter = bwareaopen(out, 50); 
imshow(out_filter); 

enter image description here

+2

Seguitelo con 'out = bwareaopen (out, 50);' (potrebbe essere necessario adattare la soglia un bit) per rimuovere le righe relative alle lettere. – Jonas

+1

@ Jonas - Mi hai letto nella mente ... In realtà l'ho fatto solo lol. È anche molto divertente che tu ed io abbiamo scelto esattamente le stesse soglie. – rayryeng

+1

ottima risposta non riuscivo a capirlo da solo! – roni

2

Sono ancora in procinto di farlo. Ma fino adesso ho questo. Non ho usato il filtro ma piuttosto uno diverso.

Ho usato la prima immagine che hai fornito. I filtri sono descritti qui: image_filters.

enter image description here

image=imread('benzene.png'); 
BW = im2bw(image); 
w1=(1/3)*[1 0 -1;1 0 -1;1 0 -1]; 
g=(imfilter(double(BW),w1)); 
g(g<1)=0; 
imshow(g); 

L'output che ho ottenuto è questa: Come si può vedere il risultato non è ancora completa. Posso suggerirti di provare due cose: usa l'operatore dell'erosione morfologica per rimuovere i piccoli elementi. È inoltre possibile utilizzare i componenti connessi per farlo.

output

Nel frattempo cercare di fare quello che ho suggerito. Se avrò la risposta, la aggiornerò.

+2

Invece di operazioni morfologiche c'è un modo più facile di rilevare questa retta (dopo il filtraggio). Prendili uno per uno (per esempio con "imlabel") e calcola la larghezza su ogni altezza. Se è costante, allora è una linea retta, altrimenti è un po 'di rumore che vuoi evitare/ –

+0

Stavo pensando più alle linee della trasformazione di Hough. Ma non potrei applicarlo – roni

+0

@AnderBiguri puoi mostrarmi come usare imlabel? non potrei trovarlo in MATLAB ... – roni

7

Un approccio diverso è quello di utilizzare il fatto che tutte le linee che descrivono i legami hanno lo stesso rapporto di aspetto e area. dopo aver filtrato l'immagine lasciandola solo con i legami, possiamo osservare l'orientamento o l'elenco degli indici che li compongono per rilevare se sono verticali o quant'altro. Tutto questo può essere fatto usando regionprops.

image=rgb2gray(imread('benzene.png')); 
d=abs(255-image); % inverse the image 
d=im2bw(d); 
stat=regionprops(d,'Area', 'Orientation','PixelIdxList'); 
areas=[stat.Area]; 
hist(areas) 

enter image description here

Controllo dell'istogramma mostra dove tagliare per le linee, le linee hanno aree più piccole rispetto alle lettere, e dovrebbero avere approssimativamente la stessa superficie. Così ho tagliato per le aree sotto i 1000 pixel:

idx=find(areas<1000); 
angs=round([stat(idx).Orientation]); 

Ora è possibile utilizzare il angs e idx per ottenere che mai tipo di linea che si desidera. Per esempio consente solo tracciare le linee di 30 gradi:

d2=zeros(size(d)); 
d2(vertcat(stat(idx(angs==30)).PixelIdxList))=1; 
imagesc(d2) 

enter image description here

Si noti che al momento ho iniziato a rispondere a questa domanda l'immagine che ho preso era il file benzene.png. Ora mi rendo conto che hai fornito un'immagine diversa da quella originale, in modo tale che le linee che raffigurano i legami non siano separate, piuttosto che tu abbia "anelli". Vedrò più tardi se potrò occuparmi anche di questo se vuoi che lo faccia.

EDIT:

trovare la linea rilevante per la nuova immagine, in cui si dispone di anelli, l'unica differenza le linee hanno è che, beh, sono "linee" rette e non curvo. Così ho ricorrere al amata Hough transform a raccoglierli:

image=imread('http://i.stack.imgur.com/bdNOt.png'); 
d=abs(1-image); % inverse the image 
BW=im2bw(d); 
BW = bwmorph(BW,'skel',1); 
[H, T, R] = hough(BW,'Theta',-90:10:80); 
P = houghpeaks(H, 100,'NHoodSize',[3 3],'threshold',1); 
lines = houghlines(BW, T, R, P, 'FillGap',5, 'MinLength', 35); 

Diamo ottenere gli angoli delle linee rilevate:

angs=round([lines.theta]); 

vedrai che qui angs genererà valori di 0, -60 o 60 gradi.

che vogliate tracciare solo quelli che sono a 0 gradi:

p1=vertcat(lines(angs==0).point1); 
p2=vertcat(lines(angs==0).point2); 

imshow(BW, 'InitialMag',200, 'Border','tight'), hold on 

for k = 1:size(p1,1) 
    line([p1(k,1) p2(k,1)],[p1(k,2) p2(k,2)], 'LineWidth',4,... 
    'Color',[1 0 0]); hold on 
end 
hold off 

enter image description here

+0

Grazie mille. Ma come hai deciso di tagliare solo per meno di 1000? – Noober

+0

Inoltre, come posso usare 'angoli 'e' idx'? Puoi per favore dare qualche esempio. – Noober

+1

Ho aggiunto un esempio – bla