2014-06-10 2 views
1

У меня есть следующий код matlab в моем проекте. image_working - это логическое изображение, результат обнаружения края. Ниже петля расширяется каждой белой точкой, чтобы быть по существу крестом с шириной width (это так позже вызов imfill() найти более закрытые регионы. Четыре если заявления проверить, что каждая точка находится в пределах первоначальных границ.Матрица расширения краев векторизации

[edge_row, edge_col] = find(image_working); 
for width = 1:width_edge_widen 
    for i = 1:length(edge_row) 
     if (edge_row(i) + width <= m) 
      image_working(edge_row(i) + width, edge_col(i)) = 1; 
     end 
     if (edge_row(i) - width >= 1) 
      image_working(edge_row(i) - width, edge_col(i)) = 1; 
     end 
     if (edge_col(i) + width <= n) 
      image_working(edge_row(i), edge_col(i) + width) = 1; 
     end 
     if (edge_col(i) - width >= 1) 
      image_working(edge_row(i), edge_col(i) - width) = 1; 
     end 
    end 
end 

Я подозреваю, что есть хороший способ его векторизации и избежать цикла верхнего уровня, но я не понимаю, как это сделать. Просто индексирование (например, image_working(edge_row, edge_col)) не работает, так как это даст прямоугольная область, а не отдельные точки. Линейное индексирование (вызов inds = find(image_working)) нежелательно, потому что трудно выполнять как вертикальные, так и горизонтальные сдвиги, хотя может быть и векторизованное преобразование по индексам, о которых я не думал. Любые советы?

+0

Вы просто хотите размножать двоичные пиксели? Как насчет размытия всего изображения, например: imout = image_working; для width = 1: width_edge_widen; imout = imout | image_working (:, [ones (1, width), 1: end-width]) | image_working (:, [width + 1: end, ones (1, width)]) | image_working ([ones (1, width), 1: end-width], :) | image_working ([width + 1: end, ones (1, width)], :); конец . В зависимости от разреженности изображения это много операций, но оно векторизовано. – dpwe

ответ

4

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

Сначала нужно создать случайный двоичный образ

im0=rand(2000)>0.999; % this means sparsity (density) ~ 1e-3 

Решение 1 - цикл (для креста шириной 1, но вы можете изменить его по мере необходимости):

im=im0; 
sd=size(im); 
width=1; 
[x y]=find(im((1+width):sd(1)-(width+1), (1+width):sd(2)-(width+1))); 
x=x+width; y=y+width; 
for n=1:numel(y) 
    im(x(n)-width:x(n)+width,y(n))=1; 
    im(x(n),y(n)-width:y(n)+width)=1; 
end 

Раствор 2 - Векторизованных и одна линия (для креста шириной 1):

im=conv2(single(im0),[0 1 0; 1 1 1; 0 1 0],'same')>0; 

Решение 3 - векторное логическая индексацию (для креста шириной 1)

im =(im0(2:end-1,2:end-1) | im0(1:end-2,2:end-1) |... 
     im0(2:end-1,1:end-2) | im0(3:end ,2:end-1) |... 
     im0(2:end-1,3:end)); 

im =[zeros(1,size(im,2)); im; zeros(1,size(im,2))]; 
im= [zeros(size(im0,1),1) im zeros(size(im,1),1)]; 

Вы увидите, что для разреженных изображений для цикла будет быстрее, чем другие методы.

Solution 1: Elapsed time is 0.028668 seconds. 
Solution 2: Elapsed time is 0.041758 seconds. 
Solution 3: Elapsed time is 0.120594 seconds. 

Для менее редких изображений говорят (~ 1%) вы можете использовать векторизованный раствор (раствор 2), так как цикл будет очень быстро становится менее эффективным, но я хотел бы проверить производительность ваших данных, прежде чем принять решение.


Bonus редактировать, для удовольствия я векторизован перекрестный фильтр в растворе 2, чтобы иметь произвольную ширину следующим образом:

[email protected](width) circshift(vander([1 zeros(1,2*width)]),[width -width]); 

так im=conv2(single(im0),f(1),'same')>0; эквивалентен тому, что написано в решении 2, но теперь вы можете использовать любые f(width_size), которые вы хотите.

+3

Хороший ответ и приятное сравнение. – Trilarion

+3

Спасибо!Мои изображения находятся где-то между 5 и 20% белого (результат обнаружения края на том, что по существу является изображением с кучей кругов), поэтому ваше векторное решение выглядит так, как будто оно лучше. Результаты тестирования их всех (на изображении 528 x 710) ** Мой старый метод: 3,766 секунды, решение 1 (лучший цикл): 0,607 секунды, решение 2 (векторизованное): 0,014 секунды. ** Это довольно резкое различие ! –

+0

Еще одна вещь, которая предлагает этот метод, теперь я могу использовать произвольные формы для расширения изображения - а не только крест. Это может быть полезно для того, что я делаю –

Смежные вопросы