减少像素的局部邻域

时间:2012-08-01 13:30:55

标签: matlab image-processing computer-vision

我最近遇到了一个我似乎无法解决的问题。我有一个处理过的图像,其中包含在小“本地”组中遍布整个图像的多个像素。我想找到每个组的“中心”,并在输出图像中放置一个像素作为每个组的代表。分组可以是紧密编织的组,它们之间没有像素零间距,也可以是较小的展开组,它们之间只有少数(小于4~5像素)。我的第一个想法是沿着形态侵蚀的方向使用某些东西,但这并没有考虑到像素组稍微分散的情况。我想知道是否有人可以指出我正确的方向。以下是我想做的一个例子: Local Group 左侧图像显示输入(大黑点表示它们之间没有零的一组像素),右侧图像是我想要的输出或处理图像类型的示例。最后我使用MATLAB,可以假设输入图像是二进制图像(黑色为1或0,逻辑应该相同)。

非常感谢你的帮助!

编辑:感谢大家的意见 - 我将在第二天左右尝试不同的解决方案,我将尽力回复所有人。非常感谢您的深刻见解 - 非常感谢。

4 个答案:

答案 0 :(得分:2)

我建议采用一种方法,包括形态学关闭,然后进行连通成分分析。请注意,我已经颠倒了问题所以“好点”是高价值而“坏背景”是黑色的。这与形态学操作的预期定义更为吻合。

path = 'yourimage.png'
space = 5; % you can change this to make it accept bigger spacings

input = imcomplement(rgb2gray(imread(path))) > 0;
input = imclose(input, strel('disk', space));
[labels, num] = bwlabel(input, 8);
output = logical(zeros(size(input)));
for i = 1:num
   [r, c] = find(labels==i); 
   x = round(mean(c))
   y = round(mean(r))
   output(y,x) = 1;
end

imshow(output)

结果如下:

Results

对我来说似乎是你想要的!

答案 1 :(得分:2)

您所描述的问题通常称为clustering or cluster analysis。根据您的数据集和分析约束,它可能非常困难。但是,在您的情况下,它很简单,因为您有一个硬阈值(5像素)可供使用。

Aardvarkk已经提出了一个很好的解决方案,但它并没有真正展示集群的过程。这是一种非常简单的方法,您可以对数据进行聚类并获得或多或少相同的结果。

  1. 计算点之间的成对距离。对于N个点,这导致NxN矩阵
  2. 矩阵
  3. 的阈值
  4. 遍历矩阵的行
  5. 每次迭代都如下所示:

    • 如果i已经群集,请继续
    • 如果i不在群集中,请创建新群集并为其指定i
    • 找到接近i的所有其他点(行i中的列等于1)
    • 检查这些点是否已存在于群集中
    • 如果设置为i且所有点都接近i至最低群集ID
    • 如果没有设置i且所有点都接近ii's群集

    这是我掀起的一个简单例子:

    %Generate random points
    nPts = 300;
    clustId = zeros(nPts,1);
    clusterCount = 0;
    x = randi(3, [1, nPts])*10+ randn(1, nPts);
    y = randi(3, [1, nPts])*10 + randn(1, nPts);
    
    %Compute the distance matrix  from http://goo.gl/8mAoC
    dist = distance([x;y], [x;y]);
    
    maxDist = 5;
    binDist = dist <= maxDist;
    
    
    for i = 1:nPts
        % if this point is already clustered skip it
        if clustId(i) ~= 0
            continue;
        end
    
        %if the current point isn't in a cluster, create a new cluster and add
        %the point to that cluster
        if clustId(i) == 0
            clusterCount = clusterCount+1;
            clustId(i) = clusterCount;
            fprintf('New point, creating cluster:%d\n', clusterCount);
        end
    
        % get the indices of the points that collide with the i
        idx = binDist(:,i);
    
        % check to see if idx contains points that already belong to another clustered
        % if it doesn't collisionIdx will be equal to i
        collisionIdx = idx & clustId>0;
    
        %get the smallest cluster from collisionIdx
        mergeClustId = min(clustId(collisionIdx));
    
        %assing all the original points to that cluster
        clustId(idx) = mergeClustId;
    end
    

    只需遍历群集ID即可计算质心:

    cx = [];
    cy = [];
    for i = 1:clusterCount
        idx = clustId == i;
        cx(i) = mean(x(idx));
        cy(i) = mean(y(idx));
    end
    

    然后用以下结果绘制结果:

    figure; 
    plot(cx,cy,'c.', 'markersize', 50); hold on;
    plot(x,y,'.');
    

    enter image description here

答案 2 :(得分:0)

在这种情况下,您可以首先使用区域生长方法来连接像素,然后使用侵蚀。如果你知道,那么集群之间的距离大于集群本身就可以了。可能会使用重心来确定区域生长后每个斑点的中间位置。

答案 3 :(得分:0)

正如slayton所指出的,这是一个集群问题。

由于您的群集分离非常清晰,您可以使用简单的基于图形的方法。如果您可以访问图形算法库(例如boost::graph,其中存在许多绑定),则以下方法应该非常简单:

  1. 使用边缘权重作为距离构建完整的点图。
  2. 计算最小生成树,例如使用Prims algorithm
  3. 从树中消除超过长度阈值的边
  4. 查找剩余的连接组件