8

Ich bin neu in der Bildverarbeitung und ich habe versucht, vertikale Linien zu erkennen, mit diesem code-Linienerkennung im Bild

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); 

Das ist mein image-

enter image description here

war Und das ist, was Ich habe nach der Durchführung der Operationen -

Also meine Frage ist, warum bekomme ich diese Ausgabe? Es gibt 10 ver Linien, wenn vertikale Doppelbindungen als 2 verschiedene vertikale Linien gezählt werden.Auch was ist, wenn ich horizontal, vertikal, 45 und -45 alle Linien erhalten möchte, wie kann ich alle 4 Masken verwenden, um eine einzige Ausgabe zu erhalten?

+0

können Sie eine Online-Verbindung zu diesem Bild geben? Ich kann es nicht im Netz finden – roni

+0

Ich habe meine Frage bearbeitet. Ich habe meinen Fehler verstanden, aber jetzt bekomme ich wieder unerwartete Ergebnisse. – Noober

+0

@roni Sie können dieses Bild von hier selbst speichern, da ich jetzt keinen Link zum Bild habe. – Noober

Antwort

11

Ein einfacher Vorschlag, den ich habe, ist, den Gradienten zu erkennen und die Orientierung eines Kantenpunktes zu bestimmen. Beachten Sie, dass die Ausrichtung in der Richtung senkrecht an der Kante ist. Wenn Sie also vertikale Linien finden möchten, ist die Richtung, die senkrecht zu einer vertikalen Linie steht, horizontal, dh entweder 180 Grad oder -180 Grad in Bezug auf die kartesische Ebene. Daher muss für jede Ausrichtung der erkannten Kantenpunkte, wenn die Ausrichtung entweder -180 Grad oder 180 Grad ist, die Ausgabe dieser Position auf true, sonst false, festgelegt werden. Um die Gradientenorientierungen zu erkennen, verwenden Sie dazu die Bildverarbeitungs-Toolbox imgradient. Ich gehe davon aus dieser verfügbar ist, wie Sie beide imread und im2bw verwendet haben, und sie sind beide Teil dieser Toolbox:

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

Der Code eine Variable tol genannt verwendet eine Toleranz in den Winkel zu definieren, die Sie ermitteln möchten berücksichtigen Sie Rauschen oder Kanten, die vertikal aussehen, aber wenn der Winkel berechnet wird, scheint es nicht zu sein. Grundsätzlich suchen wir nach Punkten, deren Winkel innerhalb von 180 Grad oder -180 Grad liegen. Diese

ist das, was wir bekommen:

enter image description here

Als Mittel zur Nachbearbeitung Sie bwareaopen zum Ausfiltern von Pixelbereiche, deren Bereiche fallen unter einen bestimmten Betrag nutzen könnten.Unter Ausnutzung der Tatsache, dass die vertikalen Linien haben eine größere Fläche als die anderen Pixel, können Sie etwas tun könnte:

out_filter = bwareaopen(out, 50); 

Wir erhalten:

enter image description here


Nun, wenn Sie Wenn Sie horizontale Linien erkennen möchten, sollten Sie Gradientenorientierungen finden, die entweder -90 oder 90 Grad sind. Dies ist sinnvoll, weil die horizontalen Linien, die zu einer horizontalen Linie senkrecht stehen, tatsächlich vertikal sind und das heißt entweder -90 oder 90 Grad. Wenn Sie schräge Linien haben möchten, wenn Sie eine nach links geneigte Linie haben möchten, suchen Sie nach Winkeln von entweder 45 Grad oder -135 Grad und einer nach rechts geneigten Linie, entweder -45 Grad oder 135 Grad. Ich lasse Sie herausfinden, warum diese Winkel tatsächlich für diese Art von Linien repräsentativ sind.

Sie haben keine horizontalen Linien in dem Bild, das Sie zur Verfügung gestellt, also werde ich schauen nur für schräge Linien:

Linke lehnt Linien

Hinweis: Ich hatte die Toleranz aufgrund zu erhöhen zu Quantisierungsfehlern.

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

rechts gelehnt Linien:

hatte auch die Toleranz auch hier zu erhöhen:

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

Folgen Sie dies mit 'out = bwareaopen (out, 50); '(eventuell muss der Schwellenwert etwas angepasst werden), um die mit Buchstaben verbundenen Zeilen zu entfernen. – Jonas

+1

@Jonas - Du hast meine Gedanken gelesen ... Ich habe es einfach gemacht, lol. Es ist auch sehr lustig, dass Sie und ich genau die gleichen Schwellenwerte gewählt haben. – rayryeng

+1

große Antwort konnte es mir nicht selbst herausfinden! – roni

2

Ich bin noch dabei, es zu tun. Aber bis jetzt habe ich das. Ich habe deinen Filter nicht benutzt, sondern einen anderen.

Ich habe das erste Bild verwendet, das Sie geliefert haben. Die Filter sind hier beschrieben: 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); 

Die Ausgabe, die ich habe, ist dies: Wie Sie das Ergebnis ist noch nicht vollständig sehen können. Ich kann Ihnen vorschlagen, zwei Dinge zu versuchen: Verwenden Sie den morphologischen Erosionsoperator, um die kleinen Elemente zu entfernen. Sie können dazu auch verbundene Komponenten verwenden.

output

In der Zwischenzeit versuchen zu tun, was ich vorgeschlagen. Wenn ich die Antwort bekomme, werde ich es aktualisieren.

+2

Anstelle von morphologischen Operationen gibt es eine einfachere Art zu erkennen diese geraden Linien (nach dem Filtern). Nimm sie einfach nacheinander (zum Beispiel durch 'imlabel') und berechne die Breite auf jeder Höhe. Wenn es konstant ist, dann ist es eine gerade Linie, sonst ist es etwas Rauschen, das Sie vermeiden wollen/ –

+0

Ich dachte mehr in den Zeilen der Hough-Transformation. Aber ich könnte es nicht anwenden – roni

+0

@AnderBiguri können Sie mir zeigen, wie man imlabel verwendet? konnte es in Matlab nicht finden ... – roni

7

Ein anderer Ansatz ist die Tatsache nutzen dass alle Linien, die Anleihen darstellen, haben das gleiche Seitenverhältnis und die gleiche Fläche. Nach dem Filtern des Bildes mit nur den Bindungen können wir die Orientierung oder die Liste der Indizes betrachten, die sie bilden, um zu erkennen, ob sie vertikal sind oder nicht. All dies kann mit regionprops durchgeführt werden.

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

das Histogramm Inspizieren zeigt, wo für die Linien zu schneiden, die Linien haben kleinere Bereiche als die Buchstaben, und sie sollten etwa die gleiche Fläche haben. Also schnitt ich für Flächen unter 1000 Punkte:

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

jetzt können Sie die angs und idx bekommen verwenden, die jemals Art der Linie, die Sie wollen. Zum Beispiel lässt nur die 30-Grad-Linien zeichnen:

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

enter image description here

Beachten Sie, dass ich zu der Zeit begonnen, diese Frage zu beantworten, das Bild habe ich die benzene.png Datei war. Jetzt erkenne ich, dass Sie ein anderes Bild als das ursprüngliche zur Verfügung gestellt haben, so dass die Linien, die Bindungen darstellen, nicht getrennt sind, sondern Sie haben "Ringe". Ich werde später sehen, ob ich das auch ansprechen kann, wenn du willst.

EDIT:

Um die entsprechende Zeile für das neue Bild, wo Sie Ringe haben, der einzige Unterschied die Linien ist, dass, na ja, sie gerade „Linien“ und nicht gekrümmt sind. So greifen ich an die Geliebte Hough transform, um sie abzuholen:

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); 

Lassen Sie uns die Winkel der gefundenen Linien erhalten:

angs=round([lines.theta]); 

Sie werden sehen, dass hier angs Werte von 0 erzeugen, -60 oder 60 Grad.

sagen Sie nur diejenigen darstellen möchten, die 0 Grad sind:

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

Vielen Dank. Aber wie haben Sie sich entschieden, nur für weniger als 1000 zu schneiden? – Noober

+0

Auch wie kann ich 'angle' und' idx' verwenden? Können Sie bitte ein Beispiel geben. – Noober

+1

Ich habe ein Beispiel hinzugefügt – bla