Welcome to discuss more efficient algorithms.
For a mask image imMask below
,
the optimal displayable area (i.e., the largest inscribed rectangle) can be found by rect = getLargestRect(imMask, aspectRatio); where aspectRatio is the aspect ratio of the inscribed rectangle, and it should match your projector input images/frames aspect ratio.
- When aspect ratio = 1,
rect = getLargestRect(imMask, 1);

- When aspect ratio = 4/3,
rect = getLargestRect(imMask, 4/3);

Function getLargestRect is an iterative rectangle growing algorithm written in MATLAB 2021a, and is defined below:
%% find the largest inscribed rectangle of a binary image imBW.
function [rect] = getLargestRect(imBW, aspectRatio)
% aspectRatio is the aspect ratio of the inscribed rect (w/h)
h = size(imBW, 1);
w = size(imBW, 2);
% find candidate rect centers using distance transform
imDist = bwdist(~imBW);
[cy, cx] = find(imDist > prctile(imDist(imBW), 90)); % to speedup, only select the inner 90% points as candidate rect centers
% only use a subset for speedup (fix RNG seed to be deterministic)
seed = RandStream('mlfg6331_64');
idx = randsample(seed, length(cx), min(200, length(cx)));
cx = cx(idx);
cy = cy(idx);
% max size of the inscribed rect
maxH = 0;
% maxW = 0;
% for each candidate center
for i = 1: length(cy)
% left, right x and top and bottom y
lx = cx(i);
rx = cx(i);
ty = cy(i);
by = cy(i);
% iteratively grow the current inscribed renctangle toward top-left and bottom-right by 1 pix
while(1)
% move the top-left corner toward top-left by 1 pix
curH = by - ty + 1;
dx = round(curH * aspectRatio) - round((curH - 1) * aspectRatio);
if(ty - 1 >= 1 && lx - dx >= 1)
imRect = imBW(ty-1:by, lx-dx:rx);
if(nnz(~imRect(:)) == 0)
ty = ty - 1;
lx = lx - dx;
else
break;
end
else
break;
end
% move the bottom-right corner toward bottom-right by 1 pix
curH = by - ty + 1;
dx = round(curH * aspectRatio) - round((curH - 1) * aspectRatio);
if(by + 1 <= h && rx + dx <= w)
imRect = imBW(ty:by+1, lx:rx+dx);
if(nnz(~imRect(:)) == 0)
by = by + 1;
rx = rx + dx;
else
break;
end
else
break;
end
end
% record the centers with the largest inscribed rectangle
curH = by - ty + 1;
if(curH > maxH)
maxH = curH;
bestx = cx(i);
besty = cy(i);
bestRect = [lx, ty, rx-lx+1, by-ty+1];
elseif(curH == maxH)
bestx = [bestx, cx(i)];
besty = [besty, cy(i)];
bestRect = [bestRect; [lx, ty, rx-lx+1, by-ty+1]];
end
end
% finally, find the best rect whose center has the largest distance
[~, idx] = max(imDist(sub2ind(size(imDist), besty, bestx)));
rect = bestRect(idx, :);
figure; imshow(imBW); rectangle('Position', rect, 'EdgeColor','r', 'LineWidth', 3); drawnow
end
Welcome to discuss more efficient algorithms.
For a mask image
,
imMaskbelowthe optimal displayable area (i.e., the largest inscribed rectangle) can be found by
rect = getLargestRect(imMask, aspectRatio);whereaspectRatiois the aspect ratio of the inscribed rectangle, and it should match your projector input images/frames aspect ratio.rect = getLargestRect(imMask, 1);rect = getLargestRect(imMask, 4/3);Function
getLargestRectis an iterative rectangle growing algorithm written in MATLAB 2021a, and is defined below: