MATLAB: Estimate the total area of black pixels from a construction in a figure.

area figure axis

Hello everyone,
I need to know the total area covered by black pixels in a matlab figure. I do not know the polygons and can't use polyarea() or polybool(). So, as an example, I wrote a little code for estimating the total area of three squares (with two of them interlaced, and one "distant"). Here is the code:
%Plot 3 squares (two of them are melted):
%So exact surface is known (11).
x = [0,2; 0,0; 2,0 ;2,2; 0,2];
y = x + 1;
z = x + 5;
h = figure('Color',[1 1 1]);
plot(x(:,1),x(:,2),'b-'); hold on;
plot(y(:,1),y(:,2),'r-');
plot(z(:,1),z(:,2),'r-');
axis equal;
%axis square;
%patch:
patch(x(:,1),x(:,2),'k')
patch(y(:,1),y(:,2),'k')
patch(z(:,1),z(:,2),'k')
axis off;
%get actual frame:
f = getframe;
%Binarization:
ZZ = rgb2gray(f.cdata) > 255/2;
STATS = regionprops(double(~ZZ),'Area');
%same as: sum(sum(~ZZ))
aire = STATS.Area;
inter = axis;
dx = (inter(2)-inter(1))/size(ZZ,1);
dy = (inter(4)-inter(3))/size(ZZ,2);
totalarea = aire*(dx*dy)
My question is that 'totalarea' returns approximatively 11.xxx (arround 10% of error, depending of the screen resolution). So the estimation is very bad for such a simple example with squares. The shapes I intend to estimate are way more curvy and complicated… It seems to me that the estimation is resolution dependant, and I'm wondering how to improve the code further so that the error fall beyond 0.1% (or best)? Is it possible?
Thank you in advance dear matlab users.
Bests

Best Answer

It's all due to quantization error because you're taking an analytical function and digitizing it. Look in the code below where I blow up the image to full screen before getting the axes limits. More pixels give a lower relative quantization error. Then you'll see the area is now 11.06 instead of 11.14 (0.55% instead of 1.27%). I never do get a 10% error like you do.
clc;
close all;
workspace;
clear;
%Plot 3 squares (two of them are melted):
%So exact surface is known (11).
x = [0,2; 0,0; 2,0 ;2,2; 0,2];
y = x + 1;
z = x + 5;
h = figure('Color',[1 1 1]);
plot(x(:,1),x(:,2),'b-'); hold on;
plot(y(:,1),y(:,2),'r-');
plot(z(:,1),z(:,2),'r-');
axis equal;
%axis square;
%patch:
patch(x(:,1),x(:,2),'k')
patch(y(:,1),y(:,2),'k')
patch(z(:,1),z(:,2),'k')
% Enlarge figure to full screen.

set(gcf, 'Position', get(0,'Screensize'));
inter = axis
%get actual frame:
axis off; % We don't want to capture any tick marks or borders.
f = getframe;
%Binarization:
ZZ = rgb2gray(f.cdata) < 255/2;
figure;
imshow(ZZ);
% Enlarge figure to full screen.
set(gcf, 'Position', get(0,'Screensize'));
axis on;
title('The Binary Image', 'fontsize', 20);
dx = (inter(2)-inter(1))/size(ZZ,1);
dy = (inter(4)-inter(3))/size(ZZ,2);
totalWhiteArea = sum(sum(ZZ));
message = sprintf('The area of white is %d pixels\n=%.1f%%of %d total pixels.',...
totalWhiteArea, 100*totalWhiteArea/numel(ZZ), numel(ZZ));
uiwait(msgbox(message));
labeledImage = bwlabel(ZZ);
STATS = regionprops(labeledImage,'Area');
%same as: sum(sum(~ZZ))
allAreas = [STATS.Area];
aire = sum(allAreas);
message = sprintf('The area of white pixels from regionprops() is %d.', aire);
uiwait(msgbox(message));
totalArea = aire*(dx*dy);
message = sprintf('The area in calibrated units is %.2f.', totalArea);
uiwait(msgbox(message));