我最近遇到了一个我似乎无法解决的问题。我有一个处理过的图像,其中包含在小“本地”组中遍布整个图像的多个像素。我想找到每个组的“中心”,并在输出图像中放置一个像素作为每个组的代表。分组可以是紧密编织的组,它们之间没有像素零间距,也可以是较小的展开组,它们之间只有少数(小于4~5像素)。我的第一个想法是沿着形态侵蚀的方向使用某些东西,但这并没有考虑到像素组稍微分散的情况。我想知道是否有人可以指出我正确的方向。以下是我想做的一个例子: 左侧图像显示输入(大黑点表示它们之间没有零的一组像素),右侧图像是我想要的输出或处理图像类型的示例。最后我使用MATLAB,可以假设输入图像是二进制图像(黑色为1或0,逻辑应该相同)。
非常感谢你的帮助!
编辑:感谢大家的意见 - 我将在第二天左右尝试不同的解决方案,我将尽力回复所有人。非常感谢您的深刻见解 - 非常感谢。答案 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)
结果如下:
对我来说似乎是你想要的!
答案 1 :(得分:2)
您所描述的问题通常称为clustering or cluster analysis。根据您的数据集和分析约束,它可能非常困难。但是,在您的情况下,它很简单,因为您有一个硬阈值(5像素)可供使用。
Aardvarkk已经提出了一个很好的解决方案,但它并没有真正展示集群的过程。这是一种非常简单的方法,您可以对数据进行聚类并获得或多或少相同的结果。
每次迭代都如下所示:
i
已经群集,请继续i
不在群集中,请创建新群集并为其指定i
i
的所有其他点(行i
中的列等于1)i
且所有点都接近i
至最低群集ID i
且所有点都接近i
到i'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,'.');
答案 2 :(得分:0)
在这种情况下,您可以首先使用区域生长方法来连接像素,然后使用侵蚀。如果你知道,那么集群之间的距离大于集群本身就可以了。可能会使用重心来确定区域生长后每个斑点的中间位置。
答案 3 :(得分:0)
正如slayton所指出的,这是一个集群问题。
由于您的群集分离非常清晰,您可以使用简单的基于图形的方法。如果您可以访问图形算法库(例如boost::graph,其中存在许多绑定),则以下方法应该非常简单: