2011-09-28 13 views
5

Tengo una matriz (imagen) e información sobre la parte interesante dentro de los círculos (corrdinates del centro y radios dados). Quiero cortar para todos los círculos las partes de la matriz con el fin de hacer algunos cálculos más para cada círculo. O al menos quiero tener una máscara de bits con todo el círculo.MATLAB/Octave: corta muchos círculos de una imagen

Uso Octave (pero también podría usar MATLAB pero sería difícil debido a licencia iusses) y tengo el siguiente script con algunos consejos de stackoverflow. Tengo información de 20 círculos y se tarda unos 0,7 s en mi Core i5 utilizando 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; 

¿Conoce a una solución con más prestaciones ya que yo quiero tener unos 600 círculos.

Gracias de antemano

+0

Es posible que desee considerar la precomputación o al menos las máscaras de caché hasta un determinado tamaño. Parece que hay muchos valores 'r' repetidos. Por lo tanto, cada vez que calcule una máscara, calcule la parte circular y luego guárdela en una matriz de celdas o algo así, luego cámbiela por la compensación central para aplicarla realmente. Cuando te encuentres con la misma r otra vez, simplemente saca la máscara de la matriz de celdas. – dantswain

+0

relacionado: [MATLAB: cómo recorto un círculo de una imagen] (http://stackoverflow.com/q/4651778/97160) – Amro

Respuesta

3

Trate

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

Según mi perfilador MATLAB, esto es aproximadamente 4 veces más rápido que su versión. Además, la línea B = A.*mask tarda aproximadamente el mismo tiempo que la línea original mask = .... No estoy seguro de que haya mucho que puedas hacer al respecto.

0

Es posible que desee consultar el strel de Matlab (no estoy seguro acerca de la disponibilidad de octava, en Matlab es parte de la caja de herramientas de procesamiento de imágenes).

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

El nn parámetro effects performance. Hacerlo 4, 6 u 8 mejorará el rendimiento a costa de que su máscara no sea precisamente un círculo.

También puede exprimir algo de rendimiento reescribiendo el bit repmat usando bsxfun.

+0

'Strel' no parece estar en octava. –

+0

Eso está muy mal: -/Creo que este es probablemente un método muy rápido. Solo digo eso porque se basa en 'strel', que ya está muy optimizado por Matlab, para el trabajo pesado. – dantswain

2

Hay varias cosas que puede hacer para que su código sea más eficiente, aunque algunas de ellas dependen de lo que desea al final, y de qué suposiciones puede hacer sobre los círculos (por ejemplo, ¿pueden superponerse? radios similares?).

A continuación se muestra una solución que supone que hay muy poca repetición entre radios, y las coordenadas centrales son siempre valores de píxeles enteros.

%# 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 

Por cierto: Si usted tiene círculos que no se solapan, se puede utilizar bwlabel después del bucle (o utilizar encontrar y sub2ind escribir i en los círculos individuales), por lo que se puede procesar todos los círculos en una ir usando accumarray.

1

Voy a sugerir el uso de la función POLY2MASK de MATLAB Image Processing Toolbox (también disponible en el paquete Image para Octave). Compruebe la sección "algoritmo" para ver cómo maneja los píxeles discretos.

Aquí se muestra un ejemplo para probar el rendimiento:

%# 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 

En mi portátil, esto termina en:

tiempo transcurrido es 4.864494 segundos.

Cuestiones relacionadas