MATLAB: Pixel to Area conversion accruacy issue with Matlab and im2bw function

digital image processingimage analysisimage processingImage Processing ToolboxMATLABpixel area

I am reformatting and reposting this question to hopefully make it easier for more people to help.
I am writing a short Matlab script to use im2bw to calculate the area of objects in the image. I am trying to validate that the areas are being calculated correctly, but on the reference image I am using the last square's area is 2% off and I cannot figure out why.
myFolder = 'Your Directory';
% Get a list of all files in the folder with the desired file name pattern.
filePattern = fullfile(myFolder, '*.png'); % Change to whatever pattern you need.
theFiles = dir(filePattern);
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(theFiles(k).folder, baseFileName);
J = imread(fullFileName);
%J = imcrop(I,[500,200,4400,3500]);
BW = im2bw(J,0.3);
BW2 = imcomplement(BW);
BW3 = imfill(BW2,4,'holes');
%figure(1)
%imshowpair(I,BW3,'montage')
stats = regionprops(BW3,'area','PixelList','majoraxislength','minoraxislength');
area = zeros(size(stats));
for i = 1:size(stats,1)
area(i) = stats(i).Area;
end
scale = 1e-6;
%scale = 3.134755344e-8;
cutoff = 0;
area = area*scale;
stats(area<cutoff)=[];
area(area<cutoff)=[];
writematrix(area,'Your Directory','WriteMode','append')
end
figure(1)
imshowpair(J,BW3,'montage')
The image is 1000×1000 with 20×20, 100×100, 100×200, and 200×200 squares that I use as a reference.
I assumed the reference image in reality was 1mx1m and scaled accordingly, but the 200×200 square seems to not come out exactly right. The result is 0.0392 when it should be 0.04.
Additionally I have some issues overall with the accuracy of the im2bw function when trying to calculate area using other images, where I get 10-20% error. Any insights into this issue would be awesome as well.

Best Answer

As you can see from this corrected code:
clc; % Clear the command window.
fprintf('Beginning to run %s.m ...\n', mfilename);
close all; % Close all figures (except those of imtool.)
imtool close all; % Close all imtool figures.
clear; % Erase all existing variables.
workspace; % Make sure the workspace panel is showing.
fontSize = 22;
myFolder = pwd; % 'Your Directory';
% Get a list of all files in the folder with the desired file name pattern.
filePattern = fullfile(myFolder, 'ar*.png'); % Change to whatever pattern you need.
theFiles = dir(filePattern)
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(theFiles(k).folder, baseFileName);
rgbImage = imread(fullFileName);
%J = imcrop(I,[500,200,4400,3500]);
BW = im2bw(rgbImage,0.3);
BW2 = imcomplement(BW);
BW3 = imfill(BW2,4,'holes');
stats = regionprops(BW3,'area','PixelList','BoundingBox');
areaInPixels = [stats.Area]
bb = vertcat(stats.BoundingBox);
allWidthsInPixels = bb(:, 3)
allHeightInPixels = bb(:, 4)
scale = 1e-6;
areaInMm = areaInPixels * scale
% %scale = 3.134755344e-8;
% cutoff = 0;
% stats(areaInMm<cutoff)=[];
% areaInMm(areaInMm<cutoff)=[];
%
% writematrix(areaInMm,'Your Directory','WriteMode','append')
end
% figure(1)
% imshowpair(rgbImage,BW3,'montage')
fprintf('Done running %s.m ...\n', mfilename);
The areas, widths, and heights are
areaInPixels =
400 10000 20000 39204
allWidthsInPixels =
20
100
200
198
allHeightInPixels =
20
100
100
198
areaInMm =
0.0004 0.01 0.02 0.039204
so your last rectangle is not 200x200, it's 198x198.
It is probably because your large rectangle is ringed with a value of 127, unlike the other rectangles, and that 127 is below the threshold so it's not considered part of the blob. Why does only that one blob have a one pixel wide layer of 127 surrounding it?
Try a manual threshold instead.
BW = rgbImage(:, :, 1) < 255;
imshow(BW);
% BW2 = imcomplement(BW);
% BW3 = imfill(BW2,4,'holes');
BW3 = imfill(BW,4,'holes');
That will work.