如何将矩阵中强元素附近的弱元素归零?

Posted

技术标签:

【中文标题】如何将矩阵中强元素附近的弱元素归零?【英文标题】:How can I zero out weak elements near stronger ones in a matrix? 【发布时间】:2015-02-09 10:49:00 【问题描述】:

我有一个包含一些点和许多零元素的像素矩阵。从那些非零点中,我想丢弃那些在矩阵 N 范围内具有更强点的点。范围是像素之间的欧几里得距离。

input  = [0.0 0.0 0.0 0.9 0.0 0.0 
          0.0 0.0 0.2 0.0 0.0 0.5 
          0.0 0.0 0.7 0.0 0.0 0.0 
          0.0 0.4 0.1 0.0 0.0 0.0];

output = [0.0 0.0 0.0 0.9 0.0 0.0   % 0.7 is the largest number in range
          0.0 0.0 0.0 0.0 0.0 0.5   % 0.2 got removed; was next to 0.9 and 0.7
          0.0 0.0 0.7 0.0 0.0 0.0   % 0.7 is the largest number in range
          0.0 0.0 0.0 0.0 0.0 0.0]; % 0.1 and 0.4 both got removed; were next to 0.7

更新:这是我目前为止的想法。它遍历所有非零像素并将当前像素与邻域中的最大像素进行比较。但是,该邻域包含许多像素。我需要以某种方式选择圆形区域,而不是通过索引偏移选择区域。此外,如果有更短的方法,我将不胜感激,也许用内置的 Matlab 函数替换循环,如 conv2imfilter

% Discard points near stronger points
points = find(Image > 0);
radius = args.Results.min_dist;
for i = 1:size(points)
    [index_y, index_x] = ind2sub(size(Image), points(i));
    %  Find neighborhood
    from_x = max(index_x-radius, 1);
    from_y = max(index_y-radius, 1);
    to_x = min(index_x+radius, size(Image, 2));
    to_y = min(index_y+radius, size(Image, 1));
    neighbors = Image(from_y:to_y, from_x:to_x);
    % Discard if there is a stronger neighbor
    largest = max(max(neighbors));
    if Image(index_y, index_x) < largest
        Image(index_y, index_x) = 0;
    end
end

【问题讨论】:

你如何定义“强点”? @Divakar 更重要的是,我只是指像素矩阵中较大的值。 嗯,这就是我在这里定义“强”和“弱”的意思。我想这里必须有一些加权标准。 你有图片处理工具箱吗? @mehmet 如果在 N 的欧几里德距离内只有较小的像素(或根本没有像素),我想将像素保持在 0.3 以下。 【参考方案1】:

如果您安装了图像处理工具箱(或Try Hard's answer 中提到的免费替代工具之一),您可以很容易地做到这一点:

函数imdilate 基本上是一个滑动最大过滤器。所以我们所做的是,对于每个像素,我们在半径R 指定的邻域中寻找最大值。然后我们将实际值与找到的最大值进行比较,如果较小,我们将值设置为零。

function A = zeroOutWeakElements(A, R)
[X,Y] = ndgrid(-ceil(R):ceil(R));
neighborhood = (X.^2 + Y.^2)<=R^2;
A(imdilate(A,neighborhood)>A) = 0;

对于大的完整矩阵和小距离,这也将比当前接受的解决方案快得多。这种好处会随着稀疏矩阵和大半径而消失,但我想你应该用实际数据进行测试以确定什么是最好的。

【讨论】:

非常优雅的使用形态学的解决方案! +1【参考方案2】:

解决这个问题的basic workflow可以描述如下-

    对所有非零点进行排序。 从最高值点开始,将其 N 邻域内的所有非零点设置为零。 对第二高的点执行相同操作,并将其 N 邻域内的所有非零点设置为零不包括比当前值更高的非零点。这个排除部分可以在代码中使用一个非常有用的 MATLAB 工具triu 来实现。 继续直到覆盖每个非零点。当然,随着我们沿着这个阶梯往下走,要搜索的点会越来越少,因为前面讨论了排除子句

这些步骤可以通过矢量化方法来实现,不使用特殊工具箱并假设A作为输入 -

%// Distance parameter
N = 2; 

%// Find all non-zero points and then sort them in descending manner
[x,y] = find(A~=0)
pts = [x y]
[val,sorted_idx] = sort(A(A~=0),'descend')
pts = pts(sorted_idx,:)

%// Find euclidean distances
distmat = sqrt(squared_dist(pts,pts))

%// Find points to be removed (set to zero); then calculate their linear indices
rm_pts = pts(any(triu(distmat<N,1),1),:)
rm_lin_idx = sub2ind(size(A),rm_pts(:,1),rm_pts(:,2))

%// Use those linear indices to set those in the input as zeros
out = A;
out(rm_lin_idx) = 0;

相关函数代码(求平方欧几里得距离)-

function sq_distmat = squared_dist(A,B)

[nA,dim] = size(A);
nB = size(B,1);

A_ext = ones(nA,dim*3);
A_ext(:,2:3:end) = -2*A;
A_ext(:,3:3:end) = A.^2;

B_ext = ones(nB,dim*3);
B_ext(:,1:3:end) = B.^2;
B_ext(:,2:3:end) = B;

sq_distmat = A_ext * B_ext.';

return;

代码运行-

A =
         0         0         0    0.9000         0         0
         0         0    0.2000         0         0    0.5000
         0         0    0.7000         0         0         0
         0    0.4000    0.1000         0         0         0
out =
         0         0         0    0.9000         0         0
         0         0         0         0         0    0.5000
         0         0    0.7000         0         0         0
         0         0         0         0         0         0

【讨论】:

花了一段时间寻找max 的用法...我花了一点时间来了解sorttriuany 的替代组合...真的很优雅! @TryHard 谢谢!这确实是我认为的解决方案中最棘手的事情之一! :)【参考方案3】:

MATLAB 图像处理工具箱功能有多种免费替代品;例如,您可以查看octave,或者如果这不适合您,请查看例如this source 虽然它需要 mex 编译。

您正在寻找具有突然截止的过滤器。过滤器是工具箱中的标准工具。首先查看imfilter 以及imdilateimopen 等工具的文档。

【讨论】:

@danijar 你可以用fspecial指定你自己的内核

以上是关于如何将矩阵中强元素附近的弱元素归零?的主要内容,如果未能解决你的问题,请参考以下文章

162. 矩阵归零

162. 矩阵归零

PyTorch:除前k之外的向量的所有元素都归零?

如何在 python 中使用掩码将特定元素归零?

如何在 HTML textarea 元素中强制单行?

如何有效地改变矩阵的连续部分?