2009-12-06 20 views
20

Tengo una imagen en MATLAB:¿Cómo puedo encontrar máximos locales en una imagen en MATLAB?

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

y quiero hacer algo de procesamiento en él:

pic = some_processing(y); 

y encontrar los máximos locales de la salida. Es decir, todos los puntos en y que son mayores que todos sus vecinos.

Parece que no puedo encontrar una función MATLAB para hacerlo bien. Lo mejor que puedo llegar a decir:

[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]; 

y luego ver si el máximo a lo largo de la tercera dimensión aparece en la primera capa (es decir: three_d(:,:,1)):

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

¿Hay alguna más elegante forma de hacer esto? Esto parece un poco complicado.

+0

pregunta relacionada: [¿Cómo puedo encontrar muchos máximos locales en una imagen con ruido?] (http://stackoverflow.com/questions/2706528/finding-many-local-max-in-an-image-using-matlab) –

Respuesta

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

sí, este es aún más rápido :) – Amro

+0

+1 Había olvidado cómo funcionaría IMDILATE con imágenes en escala de grises (normalmente solo lo uso con máscaras lógicas). – gnovice

+0

¿Puedes explicar cómo funciona esto? –

18

Si usted tiene la Image Processing Toolbox, se puede utilizar la función IMREGIONALMAX:

BW = imregionalmax(y); 

La variable BW será una matriz lógica del mismo tamaño que y con los que indican los máximos locales y ceros de otra manera.

NOTA: Como usted señala, IMREGIONALMAX encontrará máximos que son mayores que o igual a sus vecinos. Si desea excluir los máximos vecinos con el mismo valor (es decir, encontrar máximos que son píxeles individuales), puede usar la función BWCONNCOMP. Lo siguiente debe quitar puntos en BW que tiene ningún vecinos, dejando sólo los píxeles individuales:

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

¡Gracias! Veo que imregionalmax encuentra máximos que son mayores o iguales que sus vecinos. ¿Sabes cómo puedo encontrar solo aquellos que son más grandes y no iguales a sus vecinos? –

+0

@ Nathan: Entonces, si buscara un conjunto de máximos vecinos que sean iguales, ¿le gustaría elegir uno de ellos o excluirlos a todos? – gnovice

+1

Quiero excluirlos. –

11

Alternativamente, se puede utilizar nlfilter y proporcionar su propia función que debe aplicarse a cada barrio.

Esta función "find strict max" simplemente verificará si el centro del barrio es estrictamente mayor que todos los demás elementos en ese vecindario, que siempre es 3x3 para este fin. Por lo tanto:

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

Gracias amigo ... :) – G453

2

o, sólo tiene que utilizar la excelente: extrema2.m

2

Además de imdilate, que está en el procesamiento de imágenes caja de herramientas, también se puede utilizar ordfilt2.

ordfilt2 ordena los valores en los vecindarios locales y elige el valor n-ésimo. (The MathWorks example muestra cómo implementar un filtro máx.) También puede implementar un buscador de pico de 3x3 con ordfilt2 con la siguiente lógica:

  1. definir un dominio de 3x3 que no incluye el píxel central (8 píxeles) .

    >> mask = ones(3); mask(5) = 0 % 3x3 max 
    mask = 
        1  1  1 
        1  0  1 
        1  1  1 
    
  2. Seleccione el valor más 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. comparar esta salida al valor central de cada barrio (justo 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

Esta es la solución más correcta aquí. Es nativamente en Matlab y toma mucho menos tiempo para computar que nfilter. – iamseiko

+0

@ Franzd'Anconia Pero respondí 5 años tarde, así que aquí está en la parte inferior. :) – chappjc

+0

Gran respuesta. ¿Es posible incluir la matriz original 'A'? Parece que falta en tu cadena de procesamiento. Puedo hacer ingeniería inversa de forma sencilla, pero sería bueno incluir lo que era para la autocontención :). ¡Gracias! – rayryeng

Cuestiones relacionadas