15

While doing some tests with .gif animations in MATLAB I realised that somehow I can't read the transparency of the gif.

Example:

enter image description here

(Original source of the gif)

If I do

[img,cmap]=imread('Finnandjake.gif');

img is 4D with a redundant 3rd dimension (weird). After squeezing it (img=squeeze(img);), if I show it (imshow(img(:,:,30),cmap)):

enter image description here

The transparency is gone, using another color from the image as background, thus deleting features. However

[img,cmap,alpha]=imread('Finnandjake.gif');

returns an empty alpha. Obviously the information of the alpha is in the image somewhere, how can I read it in MATLAB?

Ander Biguri
  • 35,140
  • 11
  • 74
  • 120
  • 1
    I think that matlab can't manage the transparency for a .gif image. From mathworks.com : `imread(___) additionally returns the image transparency. This syntax applies only to PNG, CUR, and ICO files.` – obchardon Jan 24 '16 at 00:26
  • @obchardon I noticed, but then, is there any way of loading a gif file to MATLAB with the alpha info? Its just a gif file, it can't be that hard – Ander Biguri Jan 24 '16 at 01:02
  • 2
    I wanted to suggest converting the GIF to PNG using Imagemagick and reading the PNGs in a loop. But I can't even get MATLAB to recognize the Alpha layer in the PNG, though it *is* present in the file. :-( – hbaderts Jan 24 '16 at 11:23
  • Open the `toolbox\private\readgive.m` and set a breakpoint next to `% Determine appearance of all frames using disposal method and transparency`. To my understanding `imshow(data{1}==53)` returns the transparency information. – Daniel Jan 24 '16 at 15:03
  • 2
    @Daniel, but that's weird because the first frame of the .gif give 53 for transparent areas and the last one give 0... There is no consistency. So for the first frame you can modify the cmap. `cmap(53:end,:) == 1;` but for the last frame it won't work. – obchardon Jan 24 '16 at 15:37
  • @obchardon: I noticed that behavior of the `handle_positive_base_frame` function, but I did not understand it. That's why I stopped previous to that function call, there I understood the data still present. – Daniel Jan 24 '16 at 16:11
  • @Daniel: `toolbox\private\readgive.m`? That's not a valid path on R2015b. Are you referring to something else or a deleted comment? – horchler Feb 13 '16 at 01:05
  • @obchardon: Where do you get 53 from? Is that counting from 0? I get 54 for every frame. – horchler Feb 13 '16 at 01:06
  • @horchler: I really screwed up that path, not sure what I did. `toolbox\matlab\imagesci\private\readgif.m` Using Matlab 2013a – Daniel Feb 13 '16 at 01:10
  • 1
    Testing with images [here](http://www.imagemagick.org/Usage/anim_basics/#background) seems to show that Matlab either has a bug, doesn't support features, or does things differently from most common GIF parsers. – horchler Feb 13 '16 at 02:19

1 Answers1

9

/Update: I made the code available at MATLAB file exchange. The published version is compatible to OCTAVE and comes with some documentation.


I came up with this solution. Return arguments are the stacked images, the colormap and the index corresponding to transparency.

%do not use, instead use: http://www.mathworks.com/matlabcentral/fileexchange/55693-transparentgifread-filename-
function [stack,map,transparent]=transparentGifRead(filename)
if ~exist(filename,'file')
    error('file %s does not exist',filename);
end
info=imfinfo(filename);
%Check if color map for all frames is the same
if any(any(any(diff(cat(3,info.ColorTable),[],3))))
    error('inconsistent color map')
else
    map=info(1).ColorTable;
end
%Check if transparent color for all frames is the same
if any(diff([info.TransparentColor]))
    error('inconsistent transparency information')
else
    transparent=info(1).TransparentColor-1;
end
import java.io.*
str = javax.imageio.ImageIO.createImageInputStream(java.io.File(filename));
t = javax.imageio.ImageIO.getImageReaders(str);
reader = t.next();
reader.setInput(str);
numframes = reader.getNumImages(true);
for imageix = 1:numframes
    data = reader.read(imageix-1).getData();
    height = data.getHeight();
    width = data.getWidth();
    data2 = reader.read(imageix-1).getData().getPixels(0,0,width,height,[]);
    if imageix == 1
        stack=zeros(height,width,1,numframes,'uint8');
    end
    %row major vs column major fix
    stack(:,:,1,imageix) = reshape(data2,[width height]).';%'
end
str.close();
end

Some demonstration code to colour the transparent pixels green:

[stack,map,transparent]=transparentGifRead('tr.gif');
map(transparent+1,:)=[0,1,0] %offset 1 because uint8 starts at 0 but indices at 1
for frame=1:size(stack,ndims(stack))
    imshow(stack(:,:,frame),map);
    pause(1/25);
end
Daniel
  • 36,610
  • 3
  • 36
  • 69
  • 1
    Two issues: `x=fullfile(matlabroot,'toolbox\matlab\imagesci','private','imgifinfo.m');` should be `x=fullfile(matlabroot,'toolbox','matlab','imagesci','private','imgifinfo.m');` to work cross-platform. Also, you seem to have an off-by-one error with the image data indexed into the colormap. – horchler Feb 13 '16 at 02:33
  • @horchler: Thanks for the feedback, just compared values and did not realise my function returned doubles instead of uint8. Now it returns uint8, there a offset of 1 between colormap and integer value is intended. – Daniel Feb 13 '16 at 02:43
  • 1
    You should be able to use `info = iminfo(filename);` to get details like the `TransparentColor` property for each frame, rather than needing to call a private function. – horchler Feb 13 '16 at 02:49
  • Changed it to use [`imfinfo`](http://www.mathworks.com/help/matlab/ref/imfinfo.html) – Daniel Feb 13 '16 at 03:18
  • Let me try this, but looks great!! – Ander Biguri Feb 13 '16 at 15:16
  • Note that the index is not unique. The transparent colors are from the index to the end, as e.g. in the image I posted its `53:64`. – Ander Biguri Feb 13 '16 at 15:31
  • @AnderBiguri I don't understand your comment. `max(stack(:))` is 53, which is transparent. I don't see other values in that range. – Daniel Feb 13 '16 at 15:41
  • @AnderBiguri: There's only one transparent color per frame. The colormap has 64 rows just so that it can be a power of two. – horchler Feb 13 '16 at 17:01
  • @Daniel for some reason `map(53,:)=1` did not change my transparency to white but `map(53:end,:)=1` did. I migth have made some mistake – Ander Biguri Feb 13 '16 at 18:53
  • 1
    @AnderBiguri: When using uint8 the map starts with index 1 but the images start with index 0, there is an offset of 1. Correct code is `map(transparent+1,:)=1`, see the example at the end of my answer. – Daniel Feb 13 '16 at 18:58
  • 1
    @Daniel yeah that was definetly it! Thanks for the effort! – Ander Biguri Feb 13 '16 at 19:00