找到两个最大的圈子

时间:2016-11-15 20:05:31

标签: matlab image-processing

我输入到我的程序中的任何脸部图像,它需要找到眼睛,使用阈值将其转换为二进制,然后用颜色圈出眼睛。

例如:

those eyes!

如果要绘制圆圈,我想迭代每个阈值级别并绘制圆圈。我希望我的程序能够显示添加了阈值的图像,其中2个最大的圆圈是瞳孔。

这是我的代码:

radiusDark = 1;
for i=1:256
    threshold = double(i/256);
    NewImage = im2bw(Image, threshold); %0.4
    imshow(NewImage);
    hold on;
    for j=10:30
        [center, radius] = imfindcircles(NewImage,[j 31],'ObjectPolarity','dark');

        if double(radius) > double(radiusDark)

           radiusDark = radius;

           viscircles(center, radiusDark,'EdgeColor','r');

        else
           viscircles(center, radius,'EdgeColor','b');

        end
end 

1 个答案:

答案 0 :(得分:1)

首先,要解决我认为可能对OP的一些误解:

  • 每次拨打[center, radius] = imfindcircles(...);时,您都会覆盖centerradius的值。
  • imfindcircles返回其所有输出的向量。 center应该被称为centers。它是Nx2数组,N是找到的圈数。 radius应该是radii。它的尺寸为Nx1
  • imfindcircles(在这种情况下为[j 31])的范围参数,使函数循环超出可能的半径。没有必要for j=10:30,因为传入[10 31]已经返回所有可能的半径为31的圆圈。您只需要找到两个最大的圆圈。
  • 您无需在MATLAB中强制转换为double。它已经是默认类型。 threshold = 1/256;if radius > radiusDark可以正常使用。
  • 如果您确实定义了radiusDark = 1,那么测试if radius > radiusDark永远不会失败,因为返回的半径都至少为10.但是,如果找到多个圆圈,您将最终至少有一个警告,可能是错误,因为radius将是一个数组。

这应该解释一些有关正在发生的事情的事情,并希望指出解决方案的可能方向。这个问题有点含糊不清。您要么在每个给定的阈值处寻找两个最大的圆圈,要么就是在寻找所有可能阈值的两个最大圆圈。我将展示两者的解决方案,从前者开始,因为你已经拥有了90%的代码。

在每个阈值

独立查找圆圈

这基本上就是你的代码所做的事情。以下是一些修改,使其更正确,更有效地工作:

for i=1:254
    threshold = i / 255;
    NewImage = im2bw(Image, threshold);
    figure;
    imshow(NewImage);
    title(sprintf('Threshold=%0.3g (i=%d)', threshold, i));
    hold on;
    [centers, radii] = imfindcircles(NewImage, [10 31], 'ObjectPolarity','dark');
    if isempty(radii)
        % No circles found
        fprintf(1, 'No circles found for i=%d (threshold=%.3g)\n', i, threshold);
        continue
    end

    if length(radii) > 2
        % More than two circles found: find the two largest ones
        [~, ind] = sortrows([radii centers]);
        ind = ind(end-1:end);
        radii = radii(ind);
        centers = centers(ind, :);
    elseif length(radii) == 1
        % Only one circle found. This is the reason we check length(radii)
        % instead of length(centers). For this case, length(centers) == 2,
        % but it is a row vector with a single xy pair.
        fprintf(1, 'Only one circle found for i=%d (threshold=%.3g)\n', i, threshold);
    end
    viscircles(centers, radii, 'EdgeColor', 'b');
end

此方法将为每个阈值级别打开一个新数字。它将打印一条关于没有圆圈或只有一个圆圈的阈值的消息。

sortrows用于按半径(第一列)对半径和中心进行排序,以便我们可以选择两个最大的半径。这些将是最后一个,因为排序是按升序排列的。我选择按索引进行选择以显示sortrows的全部功效。获取第一个输出参数的最后几行(此处作为~丢弃)并将它们拆分为radiicenters一样容易。

fprintf(1, ...)将格式化的消息打印到命令行。文件句柄1表示标准输出(2是标准错误)。此处需要换行符\n,因为较低级别的打印功能不会自动添加一行。

查找所有阈值的最大圆圈

这是一个稍微复杂的场景,但实际上更明智,因为我猜测OP想要在任何给定图像中为学生提供单个位置。这里的关键是消除误解#1中的问题,并在选择两个最大的半径和中心之前积累所有半径和中心:

allCenters = [];
allRadii = [];
for i=1:254
    threshold = i / 255;
    NewImage = im2bw(Image, threshold);
    [centers, radii] = imfindcircles(NewImage, [10 31], 'ObjectPolarity','dark');
    % This step involves a couple of reallocations that are normally considered
    % "expensive" and may give a lint warning. Just turn it off. This step is
    % negligible in every way compared to running a Hough transform on the image.
    allCenters = [allCenters; centers];
    allRadii = [allRadii; radii];
end

imshow(NewImage);
hold on;
if ~isempty(allRadii)
    if length(allRadii) > 2
        sorted = sortrows([allRadii allCenters]);
        allRadii = sorted(end-1:end, 1);
        allCenters = sorted(end-1:end, 2:end);
    elseif length(allRadii) == 1
        fprintf(1, 'Only one circle in the whole image. Strange.\n');
    end
    viscircles(allCenters, allRadii, 'EdgeColor', 'b');
else
    % No circles found
    fprintf(1, 'No circles found at all. What did you do!?\n');
end

此版本使用基本相同的逻辑,但它应用于组合数组。显示代码同样被考虑在内。我在本例中使用了另一种应用sortrows的方式。