Steve on Image Processing

April 2nd, 2009

MATLAB R2009a - imread and multipage TIFFs

One of the changes we made to MATLAB in R2009a was to improve the way imread handles multipage TIFF files. (A multipage TIFF file is one that contains multiple images. I'm not sure, but I think this terminology stems from the use of TIFF to store FAX data.) As I've written about before, in the last few years some of our users have adopted a workflow that involves storing a large number of individual images in a single TIFF file. It turns out that the following loop had a bad performance characteristics:

fname = 'my_file_with_lots_of_images.tif';
info = imfinfo(fname);
num_images = numel(info);
for k = 1:num_images
    A = imread(fname, k);
    % ... Do something with image A ...
end

One problem was that imfinfo took a long time when the file contained many images. A second problem was that the for-loop execution time scaled with num_images^2 instead of num_images. Neither problem was severe unless num_images was in the thousands, but then the bad scaling took over and made it unusable.

The reason for the bad scaling has to do with the image location is stored in the file as a kind of linked list. I've given more detail on this previously.

Step 1 in addressing the performance problem was to make imfinfo run a lot faster. This enhancement was made in one of the 2008 releases, either R2008a or R2008b. I forget which one.

Step 2, in R2009a, was to add new information to the output of imfinfo and a new syntax to imread to make the read step scale better. The output of imfinfo now includes the locations of every image in the file, and you can now pass that information to imread to help it locate a specific image more quickly.

Here's how the processing loop might look using R2009a:

fname = 'my_file_with_lots_of_images.tif';
info = imfinfo(fname);
num_images = numel(info);
for k = 1:num_images
    A = imread(fname, k, 'Info', info);
    % ... Do something with image A ...
end

I compared R2008b and R2009a for reading 65,000 images from a TIFF file. It took just under an hour in R2008b, for an average of about 21 seconds per image. It took about 90 seconds in R2009a, for an average of about 1.5 milliseconds per image.

We're not done yet with TIFF enhancements. TIFF is a very flexible format that is used in many different applications and industries. We have more enhancement requests logged related to TIFF than for all the other image formats combined. So we are continuing to devote resources to expanding what MATLAB users can do with TIFF files. If you have any particular requests related to TIFF, please comment on this post.

21 Responses to “MATLAB R2009a - imread and multipage TIFFs”

  1. Ivan E. Cao-Berg replied on :

    Steve
    I agree. I wrote a simple function tif2img (http://www.mathworks.com/matlabcentral/fileexchange/21002) which reads multi-tiff images and also img2tif (http://www.mathworks.com/matlabcentral/fileexchange/23188) that reads and loads multi-tiffs to workspace. Nevertheless

    I do have one complain about how Matlab handles tiffs. If you save an array to image using the imwrite and save it as a tiff for some Matlab 2008a doesn’t add the SubFile Type tag to the tif. This tag is optional -to my knowledge- yet most image editors, e.g. Gimp and Photoshop will add the tag and Matlab doesn’t. You may think it is not important, but applications like Virtual Cell (VCell) require this tag in the file in order to recognize. The non-Matlab solution is quite simple, use the tiffset from libtiff.

  2. Steve replied on :

    Ivan—As far as I know, we’ve never heard this complaint before. We’ll look into it.

  3. Steve replied on :

    Ivan—The SubFile Type tag is optional. According to the TIFF spec, if the tag is not present, it’s value should be assumed to be 0, meaning that the image is a “primary” image. An application that requires this tag to be set in order to read a primary image correctly has not implemented the spec correctly. However, I’ll make a note in our enhancements database to see what we can do in a future release.

  4. Vijay Iyer replied on :

    Thanks for this tip. I’ve confirmed an ~3x improvement on our images (~256×64 frames of uint16), for movies/stacks ~10,000 frames in length.

    You know this feature is undocumented still, right?

    The performance gap with ImageJ is still quite significant (~10x for our 10000 frame data). If you don’t close this soon (and I mean soon!), I’ll have little choice but to become an ImageJ expert, and leave Matlab in the dust.

  5. Steve replied on :

    Vijay—The new syntax is mentioned in the M-file help but was accidentally omitted from the reference page. I believe that’s been fixed for the next release.

  6. Derrick replied on :

    I have been looking online and have not found a solution. I get how to read multipage tiffs but how do I create them using MATLAB and/or the IP toolbox?

  7. Derrick replied on :

    Never mind I see how to do it.

    for i = 1:10
    imwrite(myImage(:,:,i), ‘10-pk_img.tif’,'tif’, ‘Compression’, ‘none’, ‘WriteMode’, ‘append’);
    end

  8. Steve replied on :

    PZ posted a comment here to agree with Vijay Iyer’s critical comments above. That’s fine - I have no problem with criticism here, as long as it is relevant to the topic of the post. But PZ, I don’t let comments go through with author names and author URLs that appear to be advertisements.

  9. Peter replied on :

    Sorry about this irrelevant topic.

    I really want to write a 1024 x 1024 matrix with floating values to a tiff. Is it doable in Matlab? I know Matlab can read a tiff with floating values without any problem, but I was never able to write a tiff with floating values.

  10. Steve replied on :

    Peter—Your question is more relevant to the topic of this post than most of the comments that come in. ;-)

    No, there’s no way to do this in MATLAB right now. It’s on our list of things to work on for a future release.

  11. joshuav replied on :

    this speedup is great, thanks so much for implementing it. i’m curious about a similar speedup in imwrite. for large stacks (eg, >1000), i find that imwrite is unacceptably slow. i use the following code now:

    data=uint8(floor(255*(data-min(data)/(max(data)-min(data)))); %convert to 8-bit image
    for t=1:T
    if t==1, mod=’overwrite’; else mod=’append’; end
    imwrite(reshape(FF(:,t),height,width),fname,’tif’,'Compression’,'none’,'WriteMode’,mod)
    end

    would the basic idea of this speedup work for imwrite as well?

  12. Steve replied on :

    Joshuav—Thanks for the comment. We are working on ways to speed up writing stacks to TIFF files. It probably won’t look exactly the same as what we’ve already done with imread.

  13. Mike replied on :

    Steve,

    Will Matlab2009b have the function of saving floating-point TIFF? How about GEOTIFF?

    Mike

  14. Steve replied on :

    Mike—I generally avoid commenting on specific schedules for software changes.

  15. Grant replied on :

    It would be great if there was an option to load up a variable and write it at once instead of iteratively… at the moment imwrite will not handle this, for example, this imwrite statement will fail when it is a perfectly legitimate request:

    
    for k = 1:num_images
        A(:,:,k) = imread(fname, k, 'Info', info);
    end
    
    imwrite (A(:,:,k),outfile.tif)
    

    On that note, it would be great imread could read all frames at once. If I want to do a simple operation on all frames, I have to run it through a loop and iteratively operate. But it would be great if imread assumed ALL frames, rather than the first, where this code would read, flip, and write all frames:

    
    A=imread('tifname');
    A=flipupd(A);
    imwrite(A,outfile);
    

    or at least make a way to address all frames e.g.

    
    A(:,:,:)=imread('tifname',:)
    
  16. Grant replied on :

    sorry, that first imwrite statement should look like

    
    imwrite (A(:,:,:),outfile.tif)
    
  17. Steve replied on :

    Grant—Your suggestions are reasonable and other people have made them as well. I see at least two interface design problems, though. First, what would you like imwrite to do in the case where num_images equals 3? If you pass an M-by-N-by-3 array to imwrite today, it writes a single-frame RGB image. How can imwrite distinguish between between a single-frame RGB image and 3 image frames?

    Second, what should imread do for TIFF files that contain images of different size, bit depths, color formats, etc.? You can’t stack such images into a single multidimensional MATLAB array. You could return a cell array, but that would lose the convenience you’re looking for, and it would introduce an awkward syntactic discontinuity for the case where num_images equals 1.

    I’m sure that all of these functional behavior issues could be solved. However, because the for-loop is very straightfoward to write, and because of the many other TIFF-related enhancement requests, we are unlikely to implement something like you suggest in the near future.

  18. Gerard replied on :
    pointlist1=linspace(0, 16383, 480);  %% make float data for one line
    pointlist2=linspace(16383, 0, 480);  %% make float data for one line
    A=repmat(pointlist1,640,1);    %% construct float 640x480 array
    B=repmat(pointlist2,640,1);    %% construct float 640x480 array
    a=uint16(A);
    b=uint16(B);
    imwrite(a,'16bit.tif','WriteMode','Append');
    imwrite(b,'16bit.tif','WriteMode','Append');
    

    Hi Steve, my question is on making multipage tif files, can this be done in matlab? I have csv files that I want to wrap together into a multipage tif. My first test was using imwrite and trying to append 2 different matrices, I seem to only get the first one, it is at least 16 bit but only one file. Anyone have any suggestions?

  19. Vijay Iyer replied on :

    Can you give us an overview of what the LibTIFF library wrapper that’s included in 2009b will get us? This seems like it could be the most powerful way to work with large multi-page TIFF files, streamed reads/writes, etc.

  20. Steve replied on :

    Gerard—I get a two-image TIFF file when I run your code. How do you know your file contains only one image? What’s the output of this code:

    num_images = numel(imfinfo('16bit.tif'))
    
  21. Steve replied on :

    Vijay—Patience. R2009b is scheduled to ship next month. After it is released I will be happy to discuss what’s in it.

Leave a Reply

Wrap code fragments inside <pre> tags, like this:

<pre class="code">
a = magic(3);
sum(a)
</pre>

If you have a "<" character in your code, either follow it with a space or replace it with "&lt;" (including the semicolon).


Steve Eddins manages the Image & Geospatial development team at The MathWorks and coauthored Digital Image Processing Using MATLAB. He writes here about image processing concepts, algorithm implementations, and MATLAB.

  • Steve: Kezia—Try imrotate.
  • kezia: steve, how to perform rotation of structuring element by 15 degrees. kindly answer my question. thank u kezia...
  • Steve: Tasha—I only accept comments that are relevant to the particular blog post or are questions or comments...
  • Tasha: Steve,I send you a comment here but still didn’t get any reply yet.I did not see my comment posted here...
  • Steve: Carsten—Thanks for your input.
  • Carsten: Another vote for either imtranslate.m, or at least a blurb in the imtransform help why pure translation...
  • Loren Shure: If you look towards the end of the fftfilt program, you will see that there’s a check to see if...
  • Steve: Sonja—My imwritesize submission on the MATLAB Central File Exchange might be helpful. It was posted...
  • Steve: Grant—Sorry, but it won’t be for R2010a. That development deadline has already passed.
  • Sonja: My publisher is wanting images for a new book to be 300 dpi. Only 5 of the 19 images are 300, the rest are...

These postings are the author's and don't necessarily represent the opinions of The MathWorks.