问题
I'm trying to identify the number of matches and coins of each value in a picture using MATLAB. Here is the starting picture, with matches and 4 different coin values. (5 small silver, 2 small gold, 2 big silver, 4 big gold coins)
The output: Here's the code:
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
As you can see, I have identified which objects are coins and which objects are matches. But, I have big trouble identifying what value the coins have.
For example, Area/diameter of the coins gives the following results. I can't see any clear way to distinguish the different types of coins based solely on this data; the numbers are just too close.
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
I tried getting the average color intensity from the starting picture of each coin too, but this did not help me separate the silver colored coins from the gold colored coins.
Mean intensity from the Red channel gives no information that there are 6 gold colored coins and 6 silver colored coins.
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
Question: How can I identify the different coin values?
(Asked how to separate two joined objects here: Separate two overlapping circles in an image using MATLAB )
Thanks
回答1:
First, regionprops 'BoundingBox'
, I cut out a picture of the coin from the starting picture using imcrop
and the BoundingBox for the identified coin.
Then, using imfindcircles
I can detect the holes in the silver-colored coins. At last, I identify the coin value using the area of the coin.
Final code:
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
Thanks
来源:https://stackoverflow.com/questions/26855264/identifying-different-coin-values-from-an-image-using-matlab