2011-09-28 7 views
5

Ho una matrice (immagine) e informazioni sulla parte interessante all'interno dei cerchi (centro corredato e raggi dati). Voglio tagliare per tutti i cerchi le parti della matrice per fare altri calcoli per ogni cerchio. O almeno voglio avere una maschera di bit con tutto il cerchio.MATLAB/Ottava: taglia un sacco di cerchi da un'immagine

Io uso Octave (ma potrebbe anche usare MATLAB ma sarebbe difficile a causa della licenza iusses) e ho il seguente script con alcuni suggerimenti da StackOverflow. Ho informazioni di 20 circoli e ci vogliono circa 0,7 s sul mio Core i5 con 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; 

Sai una soluzione più performante in quanto voglio avere circa 600 circoli.

Grazie in anticipo

+0

Si consiglia di considerare le maschere di pre-elaborazione o almeno l'archiviazione in cache fino a una determinata dimensione. Sembra che ci siano molti valori 'r' ripetuti. Quindi ogni volta che calcoli una maschera, calcola la parte circolare e poi la memorizzi in un array di celle o qualcosa del genere, quindi spostala per l'offset centrale per applicarla effettivamente. Quando incontri di nuovo lo stesso r, tira semplicemente la maschera dall'array di celle. – dantswain

+0

correlati: [MATLAB: come ritagliare un cerchio da un'immagine] (http://stackoverflow.com/q/4651778/97160) – Amro

risposta

3

Prova

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

Secondo il mio profiler MATLAB, questo è circa 4 volte più veloce rispetto la vostra versione. Inoltre, la linea B = A.*mask impiega all'incirca lo stesso tempo della linea originale mask = .... Non sono sicuro che ci sia molto che puoi fare al riguardo.

0

Si consiglia di esaminare Matlab strel (non sono sicuro della disponibilità di Octave, in Matlab è parte della toolbox di elaborazione delle immagini).

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

Il nn parametro di performance effetti. Rendendolo 4, 6 o 8 migliorerai le prestazioni a costo della tua maschera non essendo esattamente un cerchio.

È anche possibile comprimere alcune prestazioni da esso riscrivendo il repmat bit utilizzando un bsxfun.

+0

'Strel' non sembra essere in ottava. –

+0

Peccato: -/Penso che questo sia probabilmente un metodo molto veloce. Dico solo questo perché si basa su 'strel', che è già fortemente ottimizzato da Matlab, per il sollevamento pesante. – dantswain

2

Ci sono molte cose che puoi fare per rendere il tuo codice più efficiente, anche se alcune dipendono esattamente da quello che vuoi alla fine e su quali presupposti puoi fare riguardo ai cerchi (ad esempio possono sovrapporsi? Ci sono molti raggi simili?).

Di seguito è una soluzione che presuppone che ci sia pochissima ripetizione tra i raggi, e le coordinate del centro sono sempre valori di pixel interi.

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

A proposito: Se si dispone di ambienti non si sovrappongono, è possibile utilizzare bwlabel dopo il ciclo (o usare trovare e sub2ind di scrivere i nei singoli circoli), in modo che è possibile elaborare tutti i cerchi in una andare usando accumarray.

1

Ho intenzione di suggerire di utilizzare la funzione POLY2MASK da MATLAB Image Processing Toolbox (disponibile anche nel pacchetto Image per Octave). Controlla la sezione "Algoritmo" per vedere come gestisce i pixel discreti.

Ecco un esempio per testare le prestazioni:

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

Sul mio computer portatile, questo finisce in:

tempo trascorso è 4.864494 secondi.