2

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

非常感谢你的帮助!

编辑:感谢大家的投入 - 我将在接下来的一天左右尝试不同的解决方案,我会尝试在我完成后回复每个人。非常感谢你们富有洞察力的投入 - 非常感谢。

4

4 回答 4

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)

结果如下所示:

结果

在我看来,这就是你要找的东西!

于 2012-08-01T14:51:49.770 回答
2

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

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

  1. 计算点之间的成对距离。对于 N 个点,这会产生一个 NxN 矩阵
  2. 阈值矩阵
  3. 遍历矩阵的行

每次迭代将如下所示:

  • 如果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,'.');

在此处输入图像描述

于 2012-08-01T15:03:59.570 回答
0

在这种情况下,您可以首先使用区域增长方法来连接聚集的像素,然后使用侵蚀。如果您知道集群之间的距离大于集群本身,那将是可行的。也许在区域增长后使用重心来确定每个斑点的中间。

于 2012-08-01T14:03:39.957 回答
0

正如 slayton 所指出的,这是一个聚类问题。

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

  1. 用边权重作为距离构建一个完整的点图。
  2. 计算最小生成树,例如使用Prims 算法
  3. 从树中消除超过长度阈值的边
  4. 找出剩余的连通分量
于 2012-08-02T07:14:48.283 回答