如何分割多个重叠硬币(椭圆)

信息处理 计算机视觉 opencv 图像分割 边缘检测 霍夫变换
2022-02-21 03:11:44

我正在做一个用 OpenCV (C++) 计算硬币(并通过它们的大小告诉它们的价值)的程序。

假设我们有一些硬币的图像。

如果同时有两个硬币重叠,则相对容易分割硬币进行距离变换,阈值化以分离硬币,做背景骨架,然后将该骨架绘制到原始图像中。

但是,如果有 3 个硬币重叠,如下图所示:

在此处输入图像描述

在这种情况下检测 3 个硬币的最佳方法是什么?霍夫圆?

1个回答

分割通常是一个非常容易受到噪声影响的过程。我最好使用检测器,特别是对于像硬币这样的几何形状。请记住,如果你有一个好的检测,你也可以极大地缓解分割问题。对于硬币的例子,一个好的模型是使用椭圆:每个圆/椭圆在透视投影下看起来都是一个椭圆,误差可以忽略不计。

幸运的是,有很多很好的方法可以在不分割的情况下检测椭圆。ELSD是一个,霍夫变换是另一个。在上一篇文章中,我已经解释了如何使用 ELSD 来发现球形粒子。现在我将采用 Hough 变换方法——这会产生一个有效的最小代码,我将在下面分享。这也可能更直观地理解。

我现在将解释一个假设合并算法。假设给定一张灰度图像I, 具有高斯平滑边缘E. 这个想法是应用霍夫椭圆检测器E得到一大组椭圆假设{Ψ1..n}然后将它们聚集到一个简化的子集{Ψ1..k}在哪里k<<n. 如果k是已知的(例如这张有六个硬币的图像有k=6) 我们可以利用这些知识。不过,我不会假设这一点。使用提到的椭圆检测器(见上文)和可用的均值偏移聚类,我设计了以下 MATLAB 脚本(所有这些都可以在 OpenCV 中以合理的很少的努力实现):

%% PARAMETERS
% blur the image to suppress some noise
gaussSigma = 1.0;

% parameters of the canny algorithm
edgeThMin = 0.03;
edgeThMax = 0.3; % usually set to 10*edgeThMin

% override some default parameters - tune them to the size of a coin
minEllipseMajorAxis = 45;
maxEllipseMajorAxis = 110;

% coins are circle like but in case of projectivity set to a lower value
minEllipseAspectRatio = 0.7;

% bandwidth of the meanshift filter. this is a quite critical parameter 
% that determines the number of detected ellipses and their grouping.
meanShiftBandwidth = 25;

%%
% some more parameters do exist within the code below, but
% they should be somewhat less important.
I=imread('XqEYO.jpg');

% smooth the image a bit - increases reliability
Ig = imgaussfilt(I, gaussSigma);
G = rgb2gray(Ig);
E = edge(G,'canny', [edgeThMin, edgeThMax]);

params.minMajorAxis = minEllipseMajorAxis;
params.maxMajorAxis = maxEllipseMajorAxis;

params.minAspectRatio = minEllipseAspectRatio;

% there can be multiple correct hypotheses (filter later)
params.numBest = 200;

% pair with k other points N^2 -> k*N
% less randomization means more speed
params.randomize = 5;

% note that the edge (or gradient) image is used
% code from: https://www.mathworks.com/matlabcentral/fileexchange/33970-ellipse-detection-using-1d-hough-transform
bestFitHyp = ellipseDetection(E, params);

% a fit looks like: (ra,rb,ang,x0,y0,C,Nb)
fprintf('Output %d best fits.\n', size(bestFitHyp,1));
%
figure; image(I);
%ellipse drawing implementation: http://www.mathworks.com/matlabcentral/fileexchange/289
ellipse(bestFitHyp(:,3),bestFitHyp(:,4),bestFitHyp(:,5)*pi/180,bestFitHyp(:,1),bestFitHyp(:,2),'g');
title('Hough Ellipse Hypotheses');

% now cluster the ellipses that belong together using x0,y0 only.
% we use mean-shift clustering : https://de.mathworks.com/matlabcentral/fileexchange/10161-mean-shift-clustering
[~,idx,~] = MeanShiftCluster(bestFitHyp(:,1:2)',meanShiftBandwidth, 0);
numClusters = max(idx);
bestFits = zeros(numClusters, 6);
for i=1:numClusters % for each class
    ind = find(idx==i);
    members = bestFitHyp(ind, :);
    for j=1:6 % for each component of an ellipse record the median
        bestFits (i, j) = median(members(:,j));
    end
end

figure; image(I);
%ellipse drawing implementation: http://www.mathworks.com/matlabcentral/fileexchange/289
ellipse(bestFits(:,3),bestFits(:,4),bestFits(:,5)*pi/180,bestFits(:,1),bestFits(:,2),'g');
title('Clustered Hypotheses');

为了确定聚类中心,我使用中位数,因为这可能比平均替代方案更稳健——不过你可以尝试不同的方法。让我们看看不同步骤的输出。

平滑图像的边缘:

            在此处输入图像描述

最初,我们允许大量假设存在(~120)。这个初始结果以及聚类假设(最终检测)如下所示:

在此处输入图像描述

当然这个结果是一个粗略的检测。换句话说,它是投票的结果,而不是非线性参数细化的结果。为了进一步改善这些结果,您可以编写一个优化器来捕捉图像边缘顶部的椭圆。有关如何执行此操作的说明,请参见此处。您还可以使用 ELSD 边缘而不是 Canny 来简化 Hough 变换的工作并使算法更加健壮。

它可能不是最好的,但我希望这能给你一个方向。以下是在从 Google 图片中获取的硬币照片上运行该方法的更多示例输出:

在此处输入图像描述