我输入到我的程序中的任何脸部图像,它需要找到眼睛,使用阈值将其转换为二进制,然后用颜色圈出眼睛。
例如:
如果要绘制圆圈,我想迭代每个阈值级别并绘制圆圈。我希望我的程序能够显示添加了阈值的图像,其中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
答案 0 :(得分:1)
首先,要解决我认为可能对OP的一些误解:
[center, radius] = imfindcircles(...);
时,您都会覆盖center
和radius
的值。imfindcircles
返回其所有输出的向量。 center
应该被称为centers
。它是Nx2
数组,N
是找到的圈数。 radius
应该是radii
。它的尺寸为Nx1
。imfindcircles
(在这种情况下为[j 31]
)的范围参数,使函数循环超出可能的半径。没有必要for j=10:30
,因为传入[10 31]
已经返回所有可能的半径为31的圆圈。您只需要找到两个最大的圆圈。 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
的全部功效。获取第一个输出参数的最后几行(此处作为~
丢弃)并将它们拆分为radii
和centers
一样容易。
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
的方式。