2009-12-06 7 views
20

Ho un'immagine in MATLAB:Come posso trovare i massimi locali in un'immagine in MATLAB?

y = rgb2gray(imread('some_image_file.jpg')); 

e voglio fare un po 'di elaborazione su di esso:

pic = some_processing(y); 

e trovare la massimi locali dell'uscita. Cioè, tutti i punti in che sono maggiori di tutti i loro vicini.

Non riesco a trovare una funzione MATLAB per farlo bene. Il meglio che posso venire in mente è:

[dim_y,dim_x]=size(pic); 
enlarged_pic=[zeros(1,dim_x+2); 
       zeros(dim_y,1),pic,zeros(dim_y,1); 
       zeros(1,dim_x+2)]; 

% now build a 3D array 
% each plane will be the enlarged picture 
% moved up,down,left or right, 
% to all the diagonals, or not at all 

[en_dim_y,en_dim_x]=size(enlarged_pic); 

three_d(:,:,1)=enlarged_pic; 
three_d(:,:,2)=[enlarged_pic(2:end,:);zeros(1,en_dim_x)]; 
three_d(:,:,3)=[zeros(1,en_dim_x);enlarged_pic(1:end-1,:)]; 
three_d(:,:,4)=[zeros(en_dim_y,1),enlarged_pic(:,1:end-1)]; 
three_d(:,:,5)=[enlarged_pic(:,2:end),zeros(en_dim_y,1)]; 
three_d(:,:,6)=[pic,zeros(dim_y,2);zeros(2,en_dim_x)]; 
three_d(:,:,7)=[zeros(2,en_dim_x);pic,zeros(dim_y,2)]; 
three_d(:,:,8)=[zeros(dim_y,2),pic;zeros(2,en_dim_x)]; 
three_d(:,:,9)=[zeros(2,en_dim_x);zeros(dim_y,2),pic]; 

E poi vedere se compare la massima lungo la terza dimensione nel 1 ° strato (vale a dire: three_d(:,:,1)):

(max_val, max_i) = max(three_d, 3); 
result = find(max_i == 1); 

c'è più elegante modo di fare questo? Questo mi sembra un po 'scomodo.

+0

questione connessa: [Come posso trovare molti massimi locali in un'immagine disturbata?] (http://stackoverflow.com/questions/2706528/finding-many-local-max-in-an-image-using-matlab) –

risposta

37
bw = pic > imdilate(pic, [1 1 1; 1 0 1; 1 1 1]); 
+0

sì, questo è ancora più veloce :) – Amro

+0

+1 Avevo dimenticato come IMDILATE avrebbe funzionato con le immagini in scala di grigi (di solito lo uso solo con maschere logiche). – gnovice

+0

Puoi spiegare come funziona? –

18

Se avete il Image Processing Toolbox, si potrebbe utilizzare la funzione IMREGIONALMAX:

BW = imregionalmax(y); 

La variabile BW sarà una matrice binaria delle stesse dimensioni y con quelli che indicano il massimi locali e zeri altrimenti.

NOTA: Come fai notare, IMREGIONALMAX troverà massimi che sono superiori o uguali a loro vicini. Se si desidera escludere i massimi adiacenti con lo stesso valore (cioè trovare i massimi che sono pixel singoli), è possibile utilizzare la funzione BWCONNCOMP. Il seguente dovrebbe rimuovere i punti in BW che ha vicini di casa, lasciando solo i pixel singoli:

CC = bwconncomp(BW); 
for i = 1:CC.NumObjects, 
    index = CC.PixelIdxList{i}; 
    if (numel(index) > 1), 
    BW(index) = false; 
    end 
end 
+0

Grazie! Vedo che imregionalmax trova massimi che sono maggiori o uguali ai loro vicini. Sai come posso trovare solo quelli che sono più grandi e non uguali ai loro vicini? –

+0

@Nathan: Quindi, se dovessi trovare un insieme di massimi vicini uguali, vorresti semplicemente sceglierne uno o escluderli tutti? – gnovice

+1

Voglio escluderli. –

11

In alternativa, è possibile utilizzare nlfilter e fornire la propria funzione da applicare a ogni quartiere.

Questa "trovare rigorosa max" funzione sarebbe semplicemente controllare se il centro del quartiere è strettamente maggiore di tutti gli altri elementi in quel quartiere, che è sempre 3x3 per questo scopo. Pertanto:

I = imread('tire.tif'); 
BW = nlfilter(I, [3 3], @(x) all(x(5) > x([1:4 6:9]))); 
imshow(BW) 
+0

Grazie amico .. :) – G453

2

Oltre a imdilate, che è in Image Processing Toolbox, è anche possibile utilizzare ordfilt2.

ordfilt2 ordina i valori nei quartieri locali e seleziona il valore n-esimo. (The MathWorks example dimostra come implementato un filtro max.) È inoltre possibile implementare un cercatore 3x3 picco con ordfilt2 con la seguente logica:

  1. Definire un dominio 3x3 che non include il pixel centrale (8 pixel) .

    >> mask = ones(3); mask(5) = 0 % 3x3 max 
    mask = 
        1  1  1 
        1  0  1 
        1  1  1 
    
  2. Selezionare il valore più grande (8 °) con ordfilt2.

    >> B = ordfilt2(A,8,mask) 
    B = 
        3  3  3  3  3  4  4  4 
        3  5  5  5  4  4  4  4 
        3  5  3  5  4  4  4  4 
        3  5  5  5  4  6  6  6 
        3  3  3  3  4  6  4  6 
        1  1  1  1  4  6  6  6 
    
  3. Confronta questa uscita al valore centrale di ogni quartiere (appena A):

    >> peaks = A > B 
    peaks = 
        0  0  0  0  0  0  0  0 
        0  0  0  0  0  0  0  0 
        0  0  1  0  0  0  0  0 
        0  0  0  0  0  0  0  0 
        0  0  0  0  0  0  1  0 
        0  0  0  0  0  0  0  0 
    
+1

Questa è la soluzione più corretta qui. È nativamente in Matlab e richiede molto meno tempo per l'elaborazione rispetto a nfilter. – iamseiko

+0

@ Franzd'Anconia Ma ho risposto con 5 anni di ritardo, quindi eccolo in fondo. :) – chappjc

+0

Ottima risposta. È possibile includere la matrice originale 'A'? Sembra che manchi dalla tua catena di elaborazione. Posso facilmente decodificarlo ma sarebbe bello includere ciò che era per l'autocontenimento :). Grazie! – rayryeng