MATLAB / Octave: вырезать много кругов из изображения - PullRequest
5 голосов
/ 28 сентября 2011

У меня есть матрица (изображение) и информация об интересной части внутри кругов (указаны центральные координаты и радиусы).Я хочу вырезать для всех кругов части матрицы, чтобы сделать еще несколько вычислений для каждого круга.Или, по крайней мере, я хочу иметь битовую маску со всем кругом.

Я использую Octave (но мог бы также использовать MATLAB, но это было бы сложно из-за использования лицензий) и получил следующий скрипт с некоторыми подсказками от stackoverflow.У меня есть информация о 20 кругах, и это занимает около 0,7 с на моем Core i5 с использованием Octave:

% image
dim_x = 1000;
dim_y = 1000;
A=rand(dim_x,dim_y);

% center positions and ...
c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
%...  radii of the circles
r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];

tic;
for i=1:size(c,1)
    % create a bitmask ...
    mask = bsxfun(@plus, ((1:dim_y) - c(i,1)).^2, (transpose(1:dim_x) - c(i,2)).^2) < r(i)^2;
    % ... cut the circles out of the image
    B=A.*mask;
end;
toc;

Знаете ли вы более эффективное решение, так как я хочу иметь около 600 кругов.

Заранее спасибо

Ответы [ 4 ]

2 голосов
/ 28 сентября 2011

Попробуйте

mask = bsxfun(@lt, ((1:dim_y) - c(i,1)).^2,  r(i)^2 - ((1:dim_x).' - c(i,2)).^2);

Согласно моему профайлеру MATLAB, это примерно в 4 раза быстрее, чем ваша версия. Кроме того, строка B = A.*mask занимает примерно столько же времени, что и исходная строка mask = .... Не уверен, что с этим можно многое сделать.

1 голос
/ 28 сентября 2011

Есть несколько вещей, которые вы можете сделать, чтобы сделать ваш код более эффективным, хотя некоторые из них зависят от того, что именно вы хотите в итоге, и от того, какие предположения вы можете сделать относительно кругов (например, могут ли они перекрываться? Много ли подобных радиусы?).

Ниже приведено решение, которое предполагает, что между радиусами очень мало повторений, а координаты центра всегда являются целочисленными значениями пикселей.

%# image
dim_x = 1000;
dim_y = 1000;
A=rand(dim_x,dim_y);

%# center positions and ...
c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
%#...  radii of the circles
r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];

%# find the largest circle...
rMax = max(r);
%#... and create a distance array
distFromCenterSquared = bsxfun(@plus,(-rMax:rMax).^2,transpose(-rMax:rMax).^2);

%# now we can loop over the radii to create the logical mask for all circles
mask = false(dim_x,dim_y); %# initialize inside the loop if you want one circle at a time
for i=1:length(r)

    %# create logical mini-circle mask
    miniMask = distFromCenterSquared(rMax-r(i)+1:end-(rMax-r(i)),rMax-r(i)+1:end-(rMax-r(i)))...
       < r(i)^2;

    %# add to the mask. The ranges need to be fixed, obviously, if 
    %# circles can be only partially inside the image
    %# also, the "or" is only necessary if you're adding to
    %# a mask, instead of recreating it each iteration
    mask(c(i,1)-r(i):c(i,1)+r(i),c(i,2)-r(i):c(i,2)+r(i)) = ...
       mask(c(i,1)-r(i):c(i,1)+r(i),c(i,2)-r(i):c(i,2)+r(i)) | ...
       miniMask;

end

Кстати: если у вас есть непересекающиеся круги, вы можете использовать bwlabel после цикла (или использовать find и sub2ind для записи i в отдельные круги), так что вы можете обрабатывать все круги в одном перейти с использованием accumarray.

0 голосов
/ 29 сентября 2011

Я собираюсь предложить использовать функцию POLY2MASK из набора инструментов обработки изображений MATLAB (также доступна в пакете Image для Octave). Проверьте раздел «алгоритм», чтобы увидеть, как он обрабатывает отдельные пиксели.

Вот пример для тестирования производительности:

%# image
dim_x = 1000;
dim_y = 1000;
A = rand(dim_x,dim_y);

%# center positions and radii of the circles
c = [222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112; 222 111; 878 112; 81 718; 89 112];
r = [10 33 55 2 22 10 33 55 2 22 10 33 55 2 22 10 33 55 2 22];

%# lets make them 600 circles
c = repmat(c,30,1);
r = repmat(r,1,30);

%# zero-centered unit circle
t = linspace(0,2*pi,50);
ct = cos(t);
st = sin(t);

%# compute binary mask for each circle
tic
for i=1:numel(r)
    %# scale and shift scale circle, and use to get mask
    BW = poly2mask(r(i).*ct + c(i,1), r(i).*st + c(i,2), dim_x, dim_y);

    %# use the mask ...
end
toc

На моем ноутбуке это заканчивается:

Прошедшее время составляет 4,864494 секунды.

0 голосов
/ 28 сентября 2011

Возможно, вы захотите заглянуть в Matlab strel (не уверен в доступности Octave, в Matlab он является частью набора инструментов для обработки изображений).

radius = 10;
center = [320 240];
nn = 0; 
se = strel('disk', radius, nn);
px = se.getneighbors;
px = px + repmat(center, [length(px) 1]);

Параметр nn влияет на производительность.Если вы установите значение 4, 6 или 8, вы улучшите производительность за счет того, что ваша маска не будет точно кругом.

Вы также можете выжать из нее некоторую производительность, переписав бит repmat, используя bsxfun.

...