Como posso encontrar máximos locais em uma imagem em MATLAB?
-
13-09-2019 - |
Pergunta
Eu tenho uma imagem em MATLAB:
y = rgb2gray(imread('some_image_file.jpg'));
e eu quero fazer algum processamento sobre ele:
pic = some_processing(y);
e encontrar a máximos locais da saída. Ou seja, todos os pontos em y
que são maiores do que todos os seus vizinhos.
Eu não consigo encontrar uma função MATLAB para fazer isso bem. O melhor que posso dar é:
[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, em seguida, ver se o máximo ao longo da 3ª dimensão aparece na 1ª camada (isto é: three_d(:,:,1)
):
(max_val, max_i) = max(three_d, 3);
result = find(max_i == 1);
Existe alguma maneira mais elegante de fazer isso? Este parece ser um pouco de um truque.
Solução
bw = pic > imdilate(pic, [1 1 1; 1 0 1; 1 1 1]);
Outras dicas
Se você tem o Imagem Processing Toolbox , você poderia usar IMREGIONALMAX função:
BW = imregionalmax(y);
O BW
variável será uma matriz lógica do mesmo tamanho que y
com aqueles que indicam a maxima e zeros locais de outra forma.
NOTA: Como salienta, IMREGIONALMAX vai encontrar maxima que são maiores do que ou igual a seus vizinhos. Se você quiser excluir vizinha maxima com o mesmo valor (ou seja, encontrar maxima que são pixels individuais), você poderia usar o função BWCONNCOMP . O seguinte deve remover pontos em BW
que temos vizinhos, deixando apenas pixels individuais:
CC = bwconncomp(BW);
for i = 1:CC.NumObjects,
index = CC.PixelIdxList{i};
if (numel(index) > 1),
BW(index) = false;
end
end
Como alternativa, você pode usar nlfilter e fornecer sua própria função a ser aplicado a cada bairro.
Este "encontrar max rigorosa" função seria simplesmente verificar se o centro do bairro é estritamente maior do que todos os outros elementos naquele bairro, que é sempre 3x3 para esta finalidade. Portanto:
I = imread('tire.tif');
BW = nlfilter(I, [3 3], @(x) all(x(5) > x([1:4 6:9])) );
imshow(BW)
ou, basta usar o excelente: extrema2.m
Além de imdilate
, que está no Processamento de Imagem Caixa de ferramentas, você também pode usar ordfilt2
.
ordfilt2
classifica os valores em bairros locais e pega o n-th valor. ( O exemplo MathWorks demonstra como implementar um filtro max .) Você também pode implementar um localizador de 3x3 pico com ordfilt2
com a seguinte lógica:
-
Definir um domínio 3x3 que não inclui o pixel central (8 pixels).
>> mask = ones(3); mask(5) = 0 % 3x3 max mask = 1 1 1 1 0 1 1 1 1
-
Selecione o valor maior (8º) com
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
-
Comparar essa saída para o valor central de cada bairro (apenas
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