The given code more or less does what's requested, though it's not generalized.
I'm just going to throw this out there.
I'm claiming liberty to ignore the filename-as-input requirement, as I feel that it is poorly-generalized and promotes disk thrashing and unnecessary requantization as part of an acceptable workflow.
I'm ignoring the uint8-only and grayscale-only requirements, as they're presumptuous artifacts of prevailing IPT conventions and general naivete.
% a test image (probably uint8)
inpict = imread('peppers.png');
% for the sake of testing
% spread the data away from the original uint8 quant levels
inpict = im2double(inpict);
inpict = imgaussfilt(inpict,0.5);
% recast as any particular test class
% MIMT imcast() supports float classes and 8,16,32b signed/unsigned integer classes
inpict = imcast(inpict,'int32'); % MIMT-only
% get this bitplane image
outpict = getbitplane(inpict,5); % logical-class
% display the result
% IPT imshow() does not support valid RGB logical or signed integer images
% MIMT imshow2() does
imshow2(outpict)
function outpict = getbitplane(inpict,thisbit)
% OUTPICT = GETBITPLANE(INPICT,BIT)
% Get a logical image representing the specified bitplane from a logical image.
%
% INPICT is a logical or integer-class image of any number of channels.
% BIT specifies the bitplane (integer scalar between 1 and the width of the integer class)
%
% OUTPICT is a logical image of the same size as INPICT.
% Be aware that imshow() will not display correct logical images unless
% they are strictly 2D.
thisclass = class(inpict);
switch thisclass
case 'logical'
nbits = 1;
case {'single','double'}
error('Image must be logical or integer numeric class')
otherwise
nbits = str2double(regexp(thisclass,'\d*','match'));
end
if thisbit < 1 || thisbit > nbits
error('Specified bitplane must be between 1 and %d',nbits)
end
outpict = bitget(inpict,thisbit);
outpict = logical(outpict);
end

As noted, this uses MIMT tools for sake of demonstration, though they're not necessary for the conversion itself.
