Обнаружение линий в изображении


Я новичок в обработке изображений и пытался обнаружить вертикальные линии, используя этот код -

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

Это был мой образ -

Введите описание изображения здесь

И это то, что я получил после выполнения операций- Введите описание изображения здесь

Итак, мой вопрос в том, почему я получаю этот вывод?Существует 10 вертикальных линий, если вертикальные двойные связи считаются 2 отдельными вертикальными линиями.Кроме того, если я хочу получить горизонтальные, вертикальные, 45 и -45 все линии,как я могу использовать все 4 маски, чтобы получить одну единственную выход?

3 8

3 ответа:

У меня есть одно простое предложение-обнаружить градиент и определить ориентацию точки ребра. Имейте в виду, что ориентация находится в направлении, которое перпендикулярно краю. Поэтому, если вы хотите найти вертикальные линии, направление, перпендикулярное вертикальной линии, является горизонтальным, которое составляет либо 180 градусов, либо -180 градусов по отношению к декартовой плоскости. Таким образом, для каждой обнаруженной ориентации краевых точек, если ориентация равна либо -180 градусов, либо 180 градусов, затем установите выходное значение этого положения равным true, иначе false. Для обнаружения градиентных ориентаций используйте imgradient из набора инструментов обработки изображений для этого. Я предполагаю, что это доступно, поскольку вы использовали оба imread и im2bw, и они оба являются частью этого набора инструментов:

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

Код использует переменную под названием tol для определения допуска в углах, которые вы хотите обнаружить, чтобы учесть шум или ребра, которые выглядят вертикальными, но когда угол вычисляется, может показаться, что его нет. В принципе, мы ищем любые точки, углы которых находятся в пределах 180 градусов или -180 градусов.

Вот что мы получаем:

Введите описание изображения здесь

В качестве средства постобработки можно использовать bwareaopen чтобы отфильтровать пиксельные области, площади которых падают ниже определенной величины. Воспользовавшись тем, что вертикальные линии имеют большую площадь, чем другие пиксели, вы можете сделать что-то вроде этого:

out_filter = bwareaopen(out, 50);

Мы получить:

Введите описание изображения здесь


Теперь, если вы хотите обнаружить горизонтальные линии, вы должны найти градиентные ориентации, которые составляют либо -90, либо 90 градусов. Это имеет смысл, потому что те линии, которые являются горизонтальными, направление, перпендикулярное горизонтальной линии, действительно вертикальное, и это либо -90, либо 90 градусов. Если вам нужны наклонные линии, если вам нужна левая наклонная линия, ищите углы 45 градусов или -135 градусов и правую наклонную линию, либо -45 градусов или 135 степени. Я позволю вам понять, почему эти углы действительно являются репрезентативными для таких линий. У вас нет горизонтальных линий на изображении, которое вы предоставили, поэтому я просто буду искать наклонные линии:

Левые наклонные линии

Примечание: мне пришлось увеличить допуск из-за ошибок квантования.

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

Введите описание изображения здесь

Правые наклонные линии:

Также пришлось увеличить допуск и здесь:

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

Введите описание изображения здесь

Другой подход заключается в использовании того факта, что все линии, изображающие связи, имеют одинаковое соотношение сторон и площадь. после фильтрации изображения, оставляя его только с привязками, мы можем посмотреть на ориентацию или на список индексов, которые составляют их, чтобы определить, являются ли они вертикальными или что-то еще. Все это можно сделать с помощью 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)

Введите описание изображения здесь

Проверка гистограммы показывает, где нужно вырезать линии, линии имеют меньшие площади, чем буквы, и они должны имеют примерно такую же площадь. Поэтому я вырезал для областей ниже 1000 пикселей:

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

Теперь вы можете использовать angs и idx, чтобы получить, какой тип строки вы хотите. Например, давайте просто построим 30-градусные линии:

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

Введите описание изображения здесь

Обратите внимание, что в то время, когда я начал отвечать на этот вопрос, образ, который я взял, был бензолом.PNG-файл. Теперь я понимаю, что вы предоставили другой образ, чем первоначальный, так что линии, которые изображают связи, не разделены, а вы есть "кольца". Я посмотрю позже, смогу ли я обратиться и к этому, если вы этого хотите.

Редактировать:

Чтобы найти соответствующую линию для нового изображения, где у вас есть кольца, единственное отличие линий состоит в том, что они являются прямыми "линиями", а не изогнутыми. Поэтому я прибегаю к возлюбленному Hough transform , чтобы забрать их:
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);

Получим углы обнаруженных линий:

angs=round([lines.theta]);

Вы увидите, что здесь angs будет генерировать значения 0, -60 или 60 градусов.

Предположим, что вы хотите построить только те, которые равны 0 градусам:

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

Введите описание изображения здесь

Я все еще в процессе выполнения этого. Но до сих пор у меня есть это. Я использовал не ваш фильтр, а скорее другой.

Я использовал первое изображение, которое вы предоставили. Фильтры описаны здесь: image_filters .

Введите описание изображения здесь

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);
Вывод, который я получил, таков: как вы можете видеть, результат еще не завершен. Я могу предложить вам попробовать две вещи: использовать морфологический оператор эрозии для удаления мелких элементов. Вы также можете использовать connected компоненты, чтобы сделать это.

выход

А пока постарайтесь сделать то, что я предложил. Если я получу ответ, я обновлю его.