Reading animated gif with imread() produces unexpected results
11 Ansichten (letzte 30 Tage)
Ältere Kommentare anzeigen
My attempt at using imread() to read an animated gif (itself created with imwrite()) produces incorrect output:
function outpict=gifreadbad(filepath)
% GIFREADBAD(FILEPATH)
% reads all frames of an animated gif into a 4-D RGB image array
[images map]=imread(filepath, 'gif','Frames','all');
s=size(images);
numframes=s(4);
outpict=zeros([s(1:2) 3 numframes],'uint8');
for n=1:1:numframes;
outpict(:,:,:,n)=ind2rgb8(images(:,:,:,n),map);
end
return
This results in the following image:
being read as this:
I don't know if I'm not correctly specifying how the colormap(s) should be handled or what. I have a feeling that the root of the problem may have something to do with the way imread() handles the tables for multiple image blocks. It seems to fetch the map corresponding to frame 1 only. Using imread() to read individual frames produces the same results.
For sake of full disclosure, the function which created the image uses:
for n=1:1:numframes;
[imind,cm]=rgb2ind(inarray(:,:,:,n),256);
if n==1;
imwrite(imind,cm,outname,'gif','DelayTime',delay,'Loopcount',inf);
else
imwrite(imind,cm,outname,'gif','DelayTime',delay,'WriteMode','append');
end
end
I've looked around here and and elsewhere and I haven't come across an explanation or a solution other than my workaround:
function outpict=gifread(filepath)
% GIFREAD(FILEPATH)
% reads all frames of an animated gif into a 4-D RGB image array
% method requires imagemagick for splitting the gif
% imread() cannot correctly read animated gifs
% it seems that imread() won't correctly read animated gifs
% dramatic errors occur in the indexed image
% map data may be truncated or malinterpreted?
% split the gif using imagemagick instead
system(sprintf('convert %s %%03d_gifreadtemp.gif',filepath));
[~,numframes]=system('ls -1 *gifreadtemp.gif | wc -l');
numframes=str2num(numframes);
[image map]=imread('000_gifreadtemp.gif', 'gif');
s=size(image);
outpict=zeros([s(1:2) 3 numframes],'uint8');
for n=1:1:numframes;
[image map]=imread(sprintf('%03d_gifreadtemp.gif',n-1), 'gif');
outpict(:,:,:,n)=ind2rgb8(image,map);
end
system('rm *gifreadtemp.gif');
return
Using external resources to split the file works. Imread() is able to read the individual files without issue. Since the indexed-rgb conversion works fine, this leads me to suspect that the only place my error could lie is in the call to imread() in the case of the animated file.
While the above workaround is okay to demonstrate the concept, I'd like to avoid using imagemagick as it makes the function non-portable and none of the students will be able to use it.
This is 2009b on my lab computer (linux). I have not been able to get a chance to try it on a newer version or a different environment.
UPDATE: I double-checked and verified my assumption that the image data is identical between the two methods. The problem lies in the color tables.
It seems that imread(...'frames','all') returns only the GCT from the target file. After figuring out that imfinfo() exists, I attempted to use it to read in all the color tables from the target file, only to discover that all of the returned tables were incorrect (except for the first one, of course).
Upon closer inspection, the color tables returned by imfinfo() are shifted by one complete byte. This is strange, since as far as I can tell, imfinfo() is reading every other portion of the file correctly.
There does not appear to be any extraneous data in the file, and the structure is as would be expected from both the file format documentation and the image information available from imfinfo() and giftrans.
For example:
*USING HEXEDIT:*
logical screen descriptor and first/last triplets from GCT:
20 01 : width=288
00 02 : height=512
F7 : 1111 0111 : GCT=true, 8-bit, sort=false, size(GCT)=256
00 00 : BG=0, aspect=0
17 0F 10
96 3F 4D
...
2A 28 25
21 FF 0B : application extension, 11 bytes (netscape 2.0)
terminates in a zero byte (correct)
image descriptor and first/last triplets from LCT1:
2C 00 00 00 00 20 01 00 02 : same stuff as before
87 : 1000 0111 : LCT=true, interlace,sort=false,
reserved:00, size(LCT)=256
16 12 13
8B 48 4F
...
A7 A4 9C
08 FE 00 B9 : image data ...
*USING IMFINFO:*
triplets from map(:,:,[1:3 end]):
17 0F 10
96 3F 4D
...
2A 28 25
12 13 8B
48 4F 8E
...
A4 9C 08
Given that imfinfo() can read everything else correctly, even the bytes immediately adjacent to the LCT block, I'm wondering if this is a bug.
I haven't been able to find a gif file which does not produce this behavior, and I'm going to see if I can't try this on a newer version. If there is something obvious I'm missing or a bug report I haven't found, any help would be appreciated.
UPDATE AGAIN: As soon as I had written that, I found this bug report. Seems it was a bug. That pretty much wraps everything up nicely.
2 Kommentare
Weitere Antworten (0)
Siehe auch
Kategorien
Mehr zu Printing and Saving finden Sie in Help Center und File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!