how to convert color image to gray in app designer in different windows without using imread and rgb2gray?
5 views (last 30 days)
Show older comments
i made a app to load a image using fopen and fread commands and set the app data to open it in another app, i did get the original image but am not able to convert it in gray. how to convert an image to gray if we are reading an image by fread?
2 Comments
DGM
on 2 Dec 2023
Edited: DGM
on 2 Dec 2023
You have not explained what sort of image you're reading, or why it's necessary to avoid both imread() and rgb2gray(). If there is some technical reason that the obvious tools cannot be used, then nobody can be sure what a bespoke solution could be until you explain the problem.
If this is all because "the instructor said I had to do everything the hard way", well:
That answer covers multiple ways of doing RGB-gray conversion. You'd obviously need to test that the images are RGB before doing the conversions, and for most, the image will need to be converted to float via im2double() as the example shows.
Answers (3)
Image Analyst
on 2 Dec 2023
3 Comments
Image Analyst
on 3 Dec 2023
I hadn't been using it because I tought it would rescale the values to 0-1 like im2double does, and I don't like that. I like to keep everything in the original range. But I tested it and im2gray leaves the images in their original range, which is good (in my opinion).
rgbImage = imread('peppers.png');
grayImage = im2gray(rgbImage);
max(grayImage(:))
dblImage = im2double(grayImage);
max(dblImage(:))
So thanks for telling me that. Now I don't have to check if the rgb image is a 3-D array (rgb2gray will throw an error if it's not). Makes the code simpler.
DGM
on 4 Dec 2023
I really don't know why they didn't just add the obvious necessary input handling to rgb2gray() instead of creating another tool and leaving rgb2gray() half-baked. The input checking is the only added feature. It's not like it even does anything else.
Would've been a great opportunity to have it optionally provide alternative grayscale metrics (e.g. BT709 luma), but I guess we'd need another confusingly-named mostly redundant function for that.
Image Analyst
on 3 Dec 2023
What can be used if your instructor doesn't want you to use any built-in functions?
0 Comments
DGM
on 4 Dec 2023
Edited: DGM
on 5 Dec 2023
EDIT AGAIN: better generalization and broader support for all the oddball things
I've included a number of different BMP images to demonstrate the operation of this code.
- a_indexed_1.bmp: 1-bit indexed color
- a_indexed_4.bmp: 4-bit indexed color
- a_indexed_8.bmp: 8-bit indexed color
- a_bw.bmp: 1-bit grayscale (actually a 1b indexed-color image)
- a_i_8.bmp: 8-bit grayscale (actually an 8b indexed-color image)
- a_rgb_16.bmp: 16-bit RGB (packing is [5 6 5 0 0])
- a_rgbx_16.bmp: 16-bit RGB (packing is [5 5 5 0 1])
- a_rgba_16.bmp: 16-bit RGB (packing is [5 5 5 1 0])
- a_rgb_24.bmp: 24-bit RGB
- a_rgbx_32.bmp: 32-bit RGB (packing is [8 8 8 0 8])
- a_rgba_32.bmp: 32-bit RGB (packing is [8 8 8 8 0])
Packing descriptions are the number of bits alloted for [R G B A X] respectively, where A is alpha, and X are unused padding bits.
% need to do this for the forum
unzip('bmp_types.zip');
% read the file as a byte stream
fid = fopen('bmp_types/a_rgb_16.bmp');
stream = fread(fid,inf,'*uint8');
fclose(fid);
% get stuff from file header
isbmp = all(stream(1:2) == [66;77]); % is this a BMP file?
if ~isbmp
error('OS/2 BMP headers are not supported')
end
imoffset = typecast(stream(10 + (1:4)),'uint32'); % offset to data block
% get stuff from DIB header
% assume this is BITMAPINFOHEADER or newer
% MATLAB uses 40; GIMP uses 124 or 108
diblength = typecast(stream(14 + (1:4)),'uint32'); % assume this is [40 108 124]
if ~ismember(diblength,[40 108 124])
% i'm just going to let this continue with a warning
% it may be prudent to just error out here unless work is done
% to ensure other DIB lengths are accomodated
warning('Not prepared for this header type. Things might break')
end
% image geometry
imw = typecast(stream(18 + (1:4)),'uint32'); % width
imh = typecast(stream(22 + (1:4)),'int32'); % height
bottomup = imh > 0; % sign designates scan direction
imh = abs(imh);
% get additional size information
% i'm going to assume depths of:
% 1bpp (BW/indexed) (binary images are represented as indexed)
% 2bpp (indexed)
% 4bpp (indexed)
% 8bpp (I/indexed) (grayscale images are represented as indexed)
% 16bpp (RGB/RGBX/RGBA)
% 24bpp (RGB)
% 32bpp (RGBX/RGBA)
% the 'planes' field is always 1, even for RGB, so i will ignore it
bpp = typecast(stream(28 + (1:2)),'uint16'); % depth needs to be determined from bpp instead
imsz = typecast(stream(34 + (1:4)),'uint32'); % size of image data block, including padding
nchans = ceil(double(bpp)/8); % number of image channels (this probably isn't the right way)
if ~ismember(bpp,[1 2 4 8 16 24 32])
error('%d bpp images are not supported',bpp)
end
% check compression
% 0: none (RGB)
% 3: bitfields (packed format)
compression = typecast(stream(30 + (1:4)),'uint32'); % assume this is 0 or 3
if ~ismember(compression,[0 3])
error('Compressed images of this type are not supported')
end
hasbitfields = compression == 3;
% check for color table
ctlen = typecast(stream(46 + (1:4)),'uint32'); % color table length (number of rows)
hascolortable = ctlen ~= 0;
% get the image data
imdata = stream(imoffset + (1:imsz)); % extract
% unpack data
if hasbitfields
% this handles 16b/32b packed RGB/A/X
% each bpp-bit word is an arbitrarily packed field representing 1 pixel
% bitmask is a 4x32 logical array designating which bits belong to each channel
bitmask = dec2bin(typecast(stream(54 + (1:16)),'uint32'),32) == '1'; % [R;G;B;A]
if bpp == 16
% if there are any bogus mask bits above the 16 lowest bits, ignore them
bitmask(:,1:16) = 0;
end
nchans = nnz(any(bitmask,2)); % adjust the number of channels as needed
imdata = unpackbitfields(imdata,bitmask,nchans,bpp);
elseif ismember(bpp,[16 32])
% this handles RGBX cases where no bitfields are included
% default bitfields are needed for these cases
switch bpp
case 16 % for 16b, default is 55501 RGBAX
bitmask = dec2bin([31744; 992; 31; 0],32) == '1'; % [R;G;B;A]
case 32 % for 32b, default is 88808 RGBAX
bitmask = dec2bin([16711680; 65280; 255; 0],32) == '1'; % [R;G;B;A]
end
nchans = nnz(any(bitmask,2)); % adjust the number of channels as needed
imdata = unpackbitfields(imdata,bitmask,nchans,bpp);
elseif bpp < 8 && nchans == 1
% this handles low-bpp indexed images
% each bpp-bit word represents one pixel
imdata = tcast8(imdata,bpp);
end
% rearrange the image data
imdata = reshape(imdata,[],imh); % reshape into padded block
imdata = imdata(1:double(imw)*nchans,:); % trim off padding
imdata = reshape(imdata,nchans,imw,imh); % reshape
imdata = flip(permute(imdata,[3 2 1]),3); % reorient
if bottomup
imdata = flip(imdata,1); % flip as needed
end
% deal with color table if present
% if an RGB/A/X image has an extraneous CT, ignore it
if hascolortable && nchans == 1
ctoffset = diblength + 14; % assumes no masks are present
% [R G B] tuples are padded and sequenced [B G R 0]
CT = stream(double(ctoffset) + (1:double(ctlen)*nchans*4)); % extract
CT = reshape(CT,4,[]).'; % reshape
CT = im2double(fliplr(CT(:,1:3))); % trim padding, reorient, recast
imdata = ind2rgb(imdata,CT); % convert indexed image to RGB
end
% show the image as extracted from the file
imshow(imdata)
% if the image is RGB, reduce it to luma, display it
if size(imdata,3) == 3
inclass = class(imdata);
% Rec 470/601 (analog/digital SD video)
% these are the constants used by rgb2gray()/im2gray()
factors = permute([0.299 0.587 0.114],[1 3 2]);
% perform the conversion, recast to input class
imdata = sum(bsxfun(@times,double(imdata),factors),3);
imdata = cast(imdata,inclass);
end
imshow(imdata)
Obviously, that's not a complete or robust decoder implementation. It works for a small subset of common BMP types. It should work with the attached files, though it will probably fail on some images.
Trying to process a_rgba_16.bmp or a_rgba_32.bmp will result in an error, though that's not a problem with the decoder, but rather, it's simply a limitiation of imshow(). Likewise, the RGB-gray conversion routine does not accomodate an RGBA image.
Consider the set of test images included in BMP Suite. The demo above will fail or reject many of the images which a decent decoder should be expected to handle. In its simplicity, it also incidentally succeeds in returning images which a decent decoder probably shouldn't be expected to handle. To summarize, these are my notes. Decipher them if you can.
% handles:
% 1/2/4/8-bit indexed
% 16bpp (RGB/RGBX/RGBA with bitfields; RGBX with default)
% 24bpp (RGB)
% 32bpp (RGBX/RGBA with bitfields; RGBX with default)
% bottom-up (normal) and top-down scan order
% q/rgba16-1924.bmp, others (requires output class wider than uint8)
% q/rgb16-3103.bmp (has bits outside the expected range in bitmask, also wide)
% g/rgb24pal.bmp, g/rgb16-565pal.bmp (RGB with extraneous CT)
% q/rgb24largepal.bmp (RGB with extraneous CT of bogus length)
% g/rgb16.bmp (16b 5551 RGBX without explicitly specified bitfields)
% g/rgb32.bmp (32b 8888 RGBX without explicitly specified bitfields)
% q/pal8offs.bmp (junk bytes between CT and image block)
% q/pal8oversizepal.bmp (bogus CT length)
% q/pal8os2v2.bmp (DIB64 is not accomodated, but incidentally is okay)
% q/pal8os2v2-sz.bmp (similar DIB64 with odd size reporting)
% q/rgba32h56.bmp (DIB56 is not accomodated, but incidentally is okay)
% q/rgb32h52.bmp (DIB52 is not accomodated, but incidentally is okay)
% b/badheadersize.bmp (unintentionally works since bogus DIB length only prompts a warning)
% b/badplanes.bmp (unintentionally works since planes field is ignored)
% b/badfilesize.bmp (unintentionally works since fsize field is ignored)
%
% excludes:
% any other compression (RLE, embedded JPG/PNG, ALPHABITFIELD, etc)
% OS/2 magic numbers
% 64b RGBA images and other odd/bogus bpp images
%
% fails:
% nonsquare pixel aspect ratio (all physical resolution info is ignored)
% embedded color profiles and gamma info are ignored
% g/pal8-0.bmp (file falsely reports zero imsz, zero ctlen)
% warns, then fails for images with DIB12/16 headers
% may fail with some DIB64/52/56, as i've made no explicit effort to accomodate them
% q/rgb16faketrns.bmp, q/rgb32fakealpha.bmp (not a failure, but undeclared content is ignored)
% b/rgb16-880.bmp (doesn't preserve empty blue channel, so output is only 2-channel)
% the following result in unhandled errors for their own reasons:
% b/badwidth.bmp, b/badbitssize.bmp, b/badpalettesize.bmp, b/reallybig.bmp, b/shortfile.bmp
%
In reality, I doubt you really need the decoder to support everything that I've tried to make this support. I did it that way since I have no way of knowing what your test images actually are. You can always try to simplify it.
If the decoder doesn't work for your images, you'll have to share them.
0 Comments
See Also
Categories
Find more on Image Processing Toolbox in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!