使用MATLAB从图像中识别不同的硬币面值

4
我正在尝试使用MATLAB识别图片中每个价值的火柴和硬币数量。这是原始图片,包含5个小银币、2个小金币、2个大银币和4个大金币。 输出结果如下: 以下是代码:
close all;
img = (imread('C:\Users\Torstein\Jottacloud\Skole\Visu\Prosjekt\sample_images\sample2.jpg'));
img_gray = rgb2gray(img);

% Filter image for easier edge detection
m = 12;
n = 12;
img_filter = imfilter(img_gray, fspecial('average', [m n]));
%figure, imshow(f), title('f')

% Edge detection
[~, threshold] = edge(img_filter, 'canny');
fudgeFactor = 1.5;
img_edge = edge(img_filter, 'canny', threshold * fudgeFactor);
figure, imshow(img_edge), title('edge detection')

% Dilate image to make the coin edges complete without holes
se_disk = strel('disk',4);
se_line1 = strel('line',3,100);
se_line2 = strel('line',3,100);
img_dilated = imdilate(img_edge, se_disk);
img_dilated = imdilate(img_dilated, [se_line1 se_line2]);
figure, imshow(img_dilated), title('dilate')

% Remove small objects (noise) and fill complete objects
img_clearborder = imclearborder(img_dilated, 4);
%figure, imshow(BWclear), title('cleared border image');
img_fill = imfill(img_clearborder, 'holes');
figure, imshow(img_fill), title('fill holes')

% Erode image to make a clear cut between objects
se_diamond = strel('diamond',2);
img_erode = imerode(img_fill,se_diamond);
for k=1:3
    img_erode = imerode(img_erode,se_diamond);
end
img_nosmall = bwareaopen(img_erode,300);
figure, imshow(img_nosmall), title('erode')

[B, L] = bwboundaries(img_nosmall);
figure, imshow(label2rgb(L, @jet, [.5 .5 .5])), title('boundaries')
hold on
for k = 1:length(B)
  boundary = B{k};
  plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
end

stats = regionprops(L,img(:,:,1),...
    'Area','Centroid','Orientation','EquivDiameter','MeanIntensity');
threshold = 0.80; % For differentiating coins from matches based on an objects circularity

coinCentroids = [];
coinIntensities = [];
matchCentroids = [];
matchAngles = [];
coinRatios = [];

for k = 1:length(B)
    boundary = B{k};
    delta_sq = diff(boundary).^2;
    perimeter = sum(sqrt(sum(delta_sq,2)));
    area = stats(k).Area;
    metric = 4*pi*area/perimeter^2;
    metric_string = sprintf('%2.2f',metric);
    angle_string = sprintf('%2.2f',stats(k).Orientation);
    centroid = stats(k).Centroid;
    if metric > threshold
        % Object is round, therefore a coin
        coinCentroids = [coinCentroids; centroid];
        coinIntensities = [coinIntensities; stats(k).MeanIntensity];
        coinRatios = [coinRatios; stats(k).EquivDiameter/area];
    else
        % Object is a match
        angle = stats(k).Orientation;
        matchCentroids = [matchCentroids; centroid];
        matchAngles = [matchAngles; angle];
    end

    plot(centroid(1),centroid(2),'ko');
%     text(boundary(1,2)-35,boundary(1,1)+13,angle_string,'Color','y',...
%       'FontSize',14,'FontWeight','bold');

end

如您所见,我已经确定了哪些物品是硬币,哪些是火柴。

但是,我很难确定硬币的价值。

例如,硬币的面积/直径给出以下结果。仅根据这些数据,我无法清晰地区分不同类型的硬币; 数字太接近了。

0.0041
0.0042
0.0043
0.0043
0.0044
0.0045
0.0048
0.0048
0.0053
0.0054
0.0055
0.0055
0.0056

我试着从每个硬币的起始图片中获取平均颜色强度,但这并没有帮助我区分银色硬币和金色硬币。

从红色通道得到的平均强度并不能告诉我们有6个金色硬币和6个银色硬币。

  105.0104
  105.4408
  107.9070
  112.4762
  116.3412
  127.3481
  132.1418
  137.9697
  149.6601
  159.2506
  167.6910
  181.1673
  215.0395

问题:我如何确定不同的硬币价值?

(在这里询问如何分离两个重叠的对象:使用MATLAB分离图像中的两个重叠圆形)

谢谢


2
我无法看到图片。错误403。 - Autonomous
1
尝试使用属性“'Image'”的regionprops函数,应该会给您一个很好的分离效果。 - Shai
2
@tos 另一个可能有帮助的数量是每个对象直径和面积之间的比率。 - Shai
2
你已经非常接近答案了,所以我不会提供答案。继续Shai说的话题,查看这篇文章:http://www.mathworks.com/matlabcentral/answers/85363#answer_94853 。有一个很好的公式可以计算物体的圆度。如果该值接近1,则更接近于圆形,而小于1则更不像圆形。使用公式中的参数与regionprops一起计算出圆度,然后使用类似于0.5的阈值提取出圆形对象。该帖子还提示要谨慎使用离心率,如果您决定使用它。 - rayryeng
1
使用硬币上的孔作为参数来确定价值是否可接受?我的意思是,假设您知道哪些硬币包含孔,因此您首先通过存在孔来对硬币进行分类,并进一步通过面积\直径进行细化 - 这可能足够了。要查找内部孔,可以使用Hough变换查找特定半径(我相信孔的半径约为5px)... - Dev-iL
显示剩余13条评论
1个回答

1

首先,使用regionprops 'BoundingBox',我使用imcrop和识别到的硬币的BoundingBox从起始图片中切出了硬币的图像。

然后,使用imfindcircles,我可以检测出银色硬币上的孔洞。最后,我使用硬币的面积来确定硬币的价值。

最终代码:

close all;
img = (imread('C:\Users\Torstein\Jottacloud\Skole\Visu\Prosjekt\sample_images\sample1.jpg'));
%figure, imshow(img);
img_gray = rgb2gray(img);

% img_hsv = rgb2hsv(img); 
% imgv = img_hsv(:,:,3);
% [Gx, Gy] = imgradientxy(imgv);
% [Gmag, Gdir] = imgradient(Gx, Gy);
% Gmag could be useful

% Filter image for easier edge detection
m = 12;
n = 12;
img_filter = imfilter(img_gray, fspecial('average', [m n]));
%figure, imshow(f), title('f')

% Edge detection
[~, threshold] = edge(img_filter, 'canny');
fudgeFactor = 1.5;
img_edge = edge(img_filter, 'canny', threshold * fudgeFactor);
%figure, imshow(img_edge), title('edge detection')

% Dilate image to make the coin edges complete without holes
se_disk = strel('disk',4);
se_line1 = strel('line',3,100);
se_line2 = strel('line',3,100);
img_dilated = imdilate(img_edge, se_disk);
img_dilated = imdilate(img_dilated, [se_line1 se_line2]);
%figure, imshow(img_dilated), title('dilate')

% Remove stuff touching the image border and fill complete objects
img_clearborder = imclearborder(img_dilated, 4);
%figure, imshow(BWclear), title('cleared border image');
img_fill = imfill(img_clearborder, 'holes');
%figure, imshow(img_fill), title('fill holes')

% Erode image to make a clear cut between objects
se_diamond = strel('diamond',2);
img_erode = imerode(img_fill,se_diamond);
for k=1:3
    img_erode = imerode(img_erode,se_diamond);
end
img_nosmall = bwareaopen(img_erode,300); % Remove small objects (noise)
%figure, imshow(img_nosmall), title('erode')

[B, L] = bwboundaries(img_nosmall);
%figure, imshow(label2rgb(L, @jet, [.5 .5 .5])), title('boundaries')
% hold on
% for k = 1:length(B)
%   boundary = B{k};
%   plot(boundary(:,2), boundary(:,1), 'w', 'LineWidth', 2)
% end

stats = regionprops(L,img(:,:,1),...
    'Area','Centroid','Orientation','EquivDiameter','Image','BoundingBox');
threshold = 0.80; % For differentiating coins from matches based on an objects circularity

coinCentroids = [];
coinTypes = []; % 0 for Silver, 1 for Gold
coinValues = []; % 1, 5, 10 eller 20 kroning
coinAreas = [];
silverCoinAreas = [];
goldCoinAreas = [];
matchCentroids = [];
matchAngles = [];
radiusRange = [8,40];

for k = 1:length(B)
    boundary = B{k};
    delta_sq = diff(boundary).^2;
    perimeter = sum(sqrt(sum(delta_sq,2)));
    area = stats(k).Area;
    metric = 4*pi*area/perimeter^2;
    metric_string = sprintf('%2.2f',metric);
    angle_string = sprintf('%2.2f',stats(k).Orientation);
    centroid = stats(k).Centroid;
    if metric > threshold
        % Object is round, therefore a coin
        coinValues = [coinValues; 0];
        coinAreas = [coinAreas; area];
        coinCentroids = [coinCentroids; centroid];
        bbox = stats(k).BoundingBox;
        im = imcrop(img,bbox);
        %figure, imshow(im);
        [centers,radii] = imfindcircles(im,radiusRange,'ObjectPolarity','bright');
        %viscircles(centers,radii);
        if length(centers) > 0
            % Coin has a hole, therefore either 1-kroning or 5-kroning
            coinTypes = [coinTypes; 0];
            silverCoinAreas = [silverCoinAreas; area];

        else
            % Coin does not have hole, therefore either 10-kroning or
            % 20-kroning
            coinTypes = [coinTypes; 1];
            goldCoinAreas = [goldCoinAreas; area];
        end

    else
        % Object is a match
        angle = stats(k).Orientation;
        matchCentroids = [matchCentroids; centroid];
        matchAngles = [matchAngles; angle];
    end

    %plot(centroid(1),centroid(2),'ko');
%     text(boundary(1,2)-35,boundary(1,1)+13,angle_string,'Color','y',...
%       'FontSize',14,'FontWeight','bold');

end

goldThreshold = 0.1;
silverThreshold = 0.1;
maxSilver = max(silverCoinAreas);
maxGold = max(goldCoinAreas);
for k=1:length(coinTypes)
    area = coinAreas(k);
    if coinTypes(k) == 0
        if  area >= maxSilver-maxSilver*silverThreshold
            % 5-kroning
            coinValues(k) = 5;
        else
            % 1-kroning
            coinValues(k) = 1;
        end
    else
        if area >= maxGold-maxGold*goldThreshold
            % 20-kroning
            coinValues(k) = 20;
        else
            % 10-kroning
            coinValues(k) = 10;
        end
    end
end

% OUTPUT:
coinCentroids
coinValues
matchCentroids
matchAngles

谢谢


干得好!这个线程是一个很好的提问示例,也展示了学习过程的结果。 - Shai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接