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.
16:45 UTC |
Posted in Uncategorized |
Permalink |
You can follow any responses to this entry through the RSS 2.0 feed.
You can skip to the end and leave a response. Pinging is currently not allowed.
Leave a Reply
|
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.
Ivan—As far as I know, we’ve never heard this complaint before. We’ll look into it.
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.
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.
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.
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?
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
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.
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.
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.
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?
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.
Steve,
Will Matlab2009b have the function of saving floating-point TIFF? How about GEOTIFF?
Mike
Mike—I generally avoid commenting on specific schedules for software changes.
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',:)sorry, that first imwrite statement should look like
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.
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?
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.
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'))Vijay—Patience. R2009b is scheduled to ship next month. After it is released I will be happy to discuss what’s in it.