如何在MATLAB中找到图像局部极大值?

21

我在MATLAB中有一张图片:

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

我想对它进行一些处理:

pic = some_processing(y);

找到输出的局部极大值。也就是说,所有在y中比它们的邻居都要大的点。

我似乎找不到一个很好的MATLAB函数来完成这个任务。我能想到的最好的方法是:

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

然后查看第三维度中的最大值是否出现在第一层(即:three_d(:,:,1)):

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

有没有更优雅的方式来做这件事?这似乎有点笨拙。


这个回答解决了你的问题吗?如何在图像中找到局部极大值 - Trilarion
5个回答

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

4
@Nathan: IMDILATE 作用于灰度图像中的每个像素。3x3 矩阵的中心位于每个像素处,该像素的值将被周围像素中具有矩阵中数值为1的值的像素的最大值所替代。因此,IMDILATE 的调用返回一个新的矩阵,其中每个点都被其8个邻居中的最大值所代替(根据需要在边缘进行零填充),并且原始矩阵中较大的点表示局部极大值。 - gnovice
2
imdilate 遍历每个像素,并计算给定掩模中以其为中心的相邻像素的最大值(请注意中间的零以排除像素本身)。然后,我们将结果图像与原始图像进行比较,以检查每个像素是否严格大于其邻域的最大值。请务必阅读形态学操作的文档页面:http://www.mathworks.com/access/helpdesk/help/toolbox/images/f18-12508.html - Amro
3
似乎imdilate在图像处理工具箱中。是否有Matlab本身的解决方案? - shabbychef
有没有类似的方法来找到局部最小值? - Dynamite
这种方法唯一的问题是它可能在域的边界(图像的周长)上添加了一些“人为”的局部极大值,这些局部极大值并不一定是真正的局部极大值,因为它们自然上没有一个邻居,并且我们没有关于这个缺失的邻居像素值的数据。 - undefined
显示剩余3条评论

18

如果您拥有图像处理工具箱,您可以使用IMREGIONALMAX函数:

BW = imregionalmax(y);
变量BW将是一个逻辑矩阵,其大小与y相同,其中一表示局部最大值,零表示其他情况。
注意:正如您指出的那样,IMREGIONALMAX将找到大于等于其邻居的最大值。如果您想排除具有相同值的相邻最大值(即仅查找单像素的最大值),则可以使用BWCONNCOMP函数。以下应该会移除BW中具有任何邻居的点,只留下单像素:
CC = bwconncomp(BW);
for i = 1:CC.NumObjects,
  index = CC.PixelIdxList{i};
  if (numel(index) > 1),
    BW(index) = false;
  end
end

哦...我修改了问题以显示我正在使用灰度。 - Nathan Fellman
1
Steve的答案确实更优雅。 - Nathan Fellman
有没有类似的方法来寻找局部最小值? - Dynamite
1
@Dynamite:你可以先反转图像,使最小值变成最大值,然后使用与上述相同的方法。例如,如果您有一个无符号8位整数图像,可以使用“255-y”来反转它。 - gnovice
如果速度很重要,您可能想尝试这个2D峰值查找器。它比IMREGIONALMAX快6倍... http://www.mathworks.com/matlabcentral/fileexchange/37388-fast-2d-peak-finder - bla
显示剩余3条评论

11

或者,您可以使用nlfilter并提供自己的函数来应用于每个邻域。

这个“查找严格最大值”的函数只需检查邻域中心是否严格大于该邻域中的所有其他元素,该邻域始终为3x3以实现此目的。因此:

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

3
除了图像处理工具箱中的imdilate之外,您还可以使用ordfilt2ordfilt2对局部邻域中的值进行排序并选择第n个值。(The MathWorks example演示了如何实现最大值滤波器。) 您也可以使用以下逻辑用ordfilt2实现一个3x3峰值查找器:
  1. Define a 3x3 domain that does not include the center pixel (8 pixels).

    >> mask = ones(3); mask(5) = 0 % 3x3 max
    mask =
         1     1     1
         1     0     1
         1     1     1
    
  2. Select the largest (8th) value with 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. Compare this output to the center value of each neighborhood (just 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
    

3
这是此处最正确的解决方案。它是用Matlab原生编写的,计算时间比nfilter要短得多。 - sparkonhdfs
@Franzd'Anconia 但是我回答晚了5年,所以现在在底部。 :) - chappjc
很棒的答案。是否可以包含原始矩阵A?它似乎在您的处理链中丢失了。我可以轻松地进行逆向工程,但是包含它以实现自我封闭会更好 :)。谢谢! - rayryeng

2

或者,您可以使用优秀的:extrema2.m


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接