2011-09-28 1 views
5

J'ai une matrice (image) et des informations sur une partie intéressante dans les cercles (centre corrins et rayons donnés). Je veux couper pour tous les cercles les parties de la matrice afin de faire plus de calculs pour chaque cercle. Ou au moins je veux avoir un bitmask avec tout le cercle. J'utilise Octave (mais je pourrais aussi utiliser MATLAB mais ce serait difficile à cause des iusses de licence) et j'ai le script suivant avec quelques indications de stackoverflow. J'ai des informations de 20 cercles et il faut compter environ 0,7 s sur mon Core i5 utilisant Octave:MATLAB/Octave: couper beaucoup de cercles à partir d'une image

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

Connaissez-vous une solution plus performante car je veux avoir environ 600 cercles.

Merci à l'avance

+0

Vous pouvez envisager de pré-calculer ou au moins de masquer les masques jusqu'à une certaine taille. Il semble qu'il y ait beaucoup de valeurs 'r' répétées. Donc, chaque fois que vous calculez un masque, calculez la pièce circulaire et ensuite stockez-la dans un tableau de cellules ou quelque chose, puis déplacez-la par le décalage du centre pour l'appliquer réellement. Lorsque vous rencontrez à nouveau le même r, tirez simplement le masque de la matrice de cellules. – dantswain

+0

related: [MATLAB: comment faire un crop circle d'une image] (http://stackoverflow.com/q/4651778/97160) – Amro

Répondre

3

Essayez

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

Selon mon Matlab profileur, cela est environ 4 fois plus vite que votre version. En outre, la ligne B = A.*mask prend environ le même laps de temps que la ligne originale mask = .... Je ne suis pas sûr que vous pouvez faire beaucoup à ce sujet.

0

Vous pouvez regarder dans strel de Matlab (pas sûr de la disponibilité d'Octave, dans Matlab il fait partie de la boîte à outils de traitement d'image).

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

Le paramètre nn affecte les performances du paramètre. Le faire 4, 6 ou 8 améliorera les performances au prix que votre masque ne soit pas un cercle. Vous pouvez également en extraire des performances en réécrivant le bit repmat en utilisant un bsxfun.

+0

'Strel' ne semble pas être en octave. –

+0

C'est dommage: -/Je pense que c'est probablement une méthode très rapide. Je dis seulement cela parce qu'il s'appuie sur «strel», qui est déjà fortement optimisé par Matlab, pour le levage de charges lourdes. – dantswain

2

Il y a plusieurs choses que vous pouvez faire pour rendre votre code plus efficace, même si certains d'entre eux dépendent exactement de ce que vous voulez à la fin, et sur quelles hypothèses vous pouvez faire sur les cercles (par exemple, peuvent-ils se chevaucher? rayons similaires?). Ci-dessous est une solution qui suppose qu'il y a très peu de répétition parmi les rayons, et les coordonnées du centre sont toujours des valeurs de pixels entiers.

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

Soit dit en passant: Si vous avez des cercles qui ne se chevauchent, vous pouvez utiliser bwlabel après la boucle (ou utilisez trouver et sub2ind pour écrire i dans les cercles individuels), de sorte que vous pouvez traiter tous les cercles dans un allez en utilisant accumarray.

1

Je vais vous suggérons d'utiliser la fonction POLY2MASK de l'image Matlab Processing Toolbox (également disponible dans le paquet Image pour Octave). Vérifiez la section "algorithme" pour voir comment il gère les pixels discrets.

Voici un exemple pour tester les performances:

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

Sur mon ordinateur portable, ce termine dans:

temps est écoulé 4.864494 secondes.

Questions connexes