Digital Image Processing Using MATLAB has three coauthors, and we are each responsible for different aspects of writing and other book-related activities. One of my responsibilities is to keep track of changes in MATLAB and Image Processing Toolbox that might affect the book. I look for new features that we might want to mention, as well as behavior changes that might affect existing text in the book.
I was looking at my lists recently and thought they might be interesting to publish here. I normally write about new features in the blog, but I do it one release at a time. We published the first edition of the book in late 2003, so looking at all of my lists gives you a birds-eye view of what's been happening in the products over a five-year period.
Today I'll post my MATLAB lists, and later in the week I'll post my Image Processing Toolbox lists. Note that these lists are not comprehensive; they contain only the items that I thought might be relevant to some topic in the book.
Here's my challenge to readers: Scan these lists and find the oldest "new" feature that you didn't already know about, preferably something that might be useful to you. Let us know about your find by commenting on this post.
Version 7.0
Single precision support
uipanels
dockable figures
array editor for viewing structures (useful in compression chapter?)
Cell mode and publishing tool
Conditional breakpoints
Directory reports (code quality issues; todo list; etc.)
M-Lint code-checker tool
Nondouble arithmetic
Single precision linear algebra
Single precision FFTs
class input for eps function
class inputs for realmax, realmin
new functions intmax, intmin
class inputs for ones, zeros, eye
class and size inputs for Inf, NaN
isfloat
isinteger
accumarray
mode argument for sort
new trig functions for inputs in degrees
new calling syntax for function handles
anonymous function handles
nested functions
isscalar
isvector
strtrim
textscan
expanded regular expression functions
bit functions on unsigned integers
compressed MAT-files
ftp functions
interactive plotting tools
data cursors
plot annotation (with MATLAB code generation)
hggroup
hgtransform
linkprop
axes OuterPosition and TightInset properties (may be useful for fine-tuning plot positioning in our book)
GUIDE changes: panels, button groups, ActiveX support, toolbar component, menu editor, key-press detection, edit-text, scroll bar, focus setting
uiwait - timeout argument
Version 7.1
new function hypot - square root of sum of squares
new function mode - most frequent values in sample
new function arrayfun - applies a given function to each element of an array. Especially useful for arrays of structures. (possibly useful with regionprops)
new function exifread - reads EXIF information from JPEG and TIFF image files
new function structfun - applies a given function to each field of a structure
new function swapbytes - swaps byte ordering
new function typecast - converts data types without changing underlying data
cellfun - modified to be able to apply a user-specified function to each element of a cell array
Plot Tools enabled on Macintosh
Time-series analysis tools
Version 7.2
New function idivide provides division similar to A./B on integers except that fractional quotients are rounded to integers according to a specified rounding mode
New features for regular expressions:
dynamic regular expressions (insertion of MATLAB expressions into regular expressions or replacement strings)
New function for generating literals
New parsing modes (case-sensitive, single-line, multiline, freespacing)
Version 7.3
New MAT-file format capable of storing data larger than 2 GB. Not on by default; must be selected
Data cursor text can be programmatically modified
Creating GUIs - details and documentation significantly updated
mwSize and mwIndex types for use in MEX-file programming
Version 7.4
Get online URL of displayed page in help browser
Create searchable database for your own toolbox's HTML help files.
bsxfun (definitely useful - may want to replace all uses of repmat in DIPUM with calls to bsxfun)
divide-by-zero and log-of-zero warnings now off by default
new function assert
new function verLessThan
new inputParser class
More GUIDE changes
Version 7.5
Help on selection (editor)
Code folding in editor - worth recapturing editor screenshots if we have any
new function maxNumCompThreads (may want to mention multithreaded computation in MATLAB intro chapter)
new 'split' option for regexp
new error handling ability - MException - plus related changes to catch
new multimedia file reader - mmreader
imread has several TIFF-related enhancements:
LZW, Deflate, and JPEG compression support
Arbitrary combinations of samples-per-pixel and bits-per-sample
Increased performance when using 'PixelRegion' parameter. (Might want to have a DIPUM example showing how to read a subset of a TIFF image.)
GUIDE changes - custom toolbar editor, icon editor, coordinate readout in layout editor, documentation on how to make GUIDE GUIs interact
Version 7.6 (R2008a)
Camera EXIF information incorporated into output from imfinfo
FFT functions no longer warn on uint8 input
Support for JPEG-2000 import
Version 7.7 (R2008b)
Find function names and get help using new function browser
View syntax hints while entering statements
New formats supported for imread:
JPEG 2000
netCDF
Version 7.8 (R2009a)
Performance improvements for low-level HDF 5 interface
Support for HDF 1.8.1
Performance improvement for JPEG 2000 import
New syntax for faster reading of TIFF files containing many images
New computational geometry classes TriRep, DelaunayTri, TriScatteredInterp
New functions now multithreaded: fft, fft2, fftn, ifft, ifft2, ifftn, prod, sum max, min
Some Image Processing Toolbox functions moved into MATLAB: rgb2ind, dither, cmunique, cmpermute, imapprox
I want to point you to Damian's second guest blog post on Loren's Art of MATLAB. Scattered data interpolation and data gridding definitely have application to multiple areas in image processing, and the related MATLAB capabilities have significantly improved in R2009a, the latest MATLAB release.
I wrote last week about new features in R2009a related to connected component labeling. There are two new functions, bwconncomp and labelmatrix, as well as additional syntaxes for an existing function, regionprops. The features were designed to reduce the amount of memory required to measure geometric properties of connected components
(objects) in binary images. In many cases the computational speed is improved as well.
We were concerned that existing users would not discover and use the new features. If users did not change their code, then
they would not benefit from the memory and speed improvements.
So we asked the MATLAB M-Lint team for help. M-Lint is the MATLAB code analysis tool that is behind those helpful suggestions
that the MATLAB Editor makes about your code. We asked the team to detect the code pattern where the output of bwlabel is passed as the first input argument to regionprops. I showed this coding pattern in Part 1. Here's what the MATLAB Editor now shows for the script is used to create Part 1:
If you hover over the underlined "L" with your mouse, a short message pops up:
And if you click on the short message, you get a full explanation of how to change your code:
As I mentioned in Part 1, the feedback of blog readers was influential in increasing the priority of this issue. I thank
you for your many comments on my previous blogs about bwlabel and regionprops.
If you get a chance to use the new features, let us know what you think by commenting on this post.
This is a "small world" story for a mid-summer Friday.
Outside work, family, and book writing, I like to play a little tournament chess. I'm just your middle-of-the-pack club player trying to get a bit better, and occasionally I work with a chess coach who goes over my games and tells me about the silly moves I make.
Well, earlier this year my wife called to tell me that my chess coach called the house and was hoping to talk to me that day. That was a bit of a puzzle, since we had no lessons scheduled. What could this be about?
When I called him back, my coach explained that he was working on an advertisement of services to be placed in the program materials for an upcoming national tournament. The printer had notified him that the graphics file he provided wasn't suitable; he needed to send a file that was "300 dpi."
My coach didn't know what that meant, so naturally he did an internet search for terms like "300 dpi." That brought him to my blog post, "Help! My publisher wants a 300 dpi TIFF." After a while, it dawned on him that this "Steve" fellow was actually his student, and he called me to see if I could help.
It made my day to be the "expert" (for a change) in one of our conversations.
I've always had a kind of amateur's fascination with computational geometry, and computational geometry problems do arise in image processing from time to time. I've had just enough experience to know how devilishly difficult it can be to robustly compute things that seem intuitively easy.
For the past couple of years I've had the pleasure of talking every so often with Damian Sheehy, a computational geometry expert and software developer on the MATLAB team. I always learn something interesting from him, so I particularly enjoyed seeing his guest blog post today on Loren's Art of MATLAB. He provides an interesting perspective on when you might and might not want to compute certain quantities using exact arithmetic, and he shows off some of the new computational geometry features in R2009a. I encourage you to take a look. And check back again next week; he's got another post planned.
Last week I wrote about our desire to reduce the memory used by bwlabel. I also wrote about other issues we hoped to address:
The label matrix uses memory proportional to the total number of image pixels. This seems unreasonable when you're working
with an image containing only a few object pixels.
When bwlabel was used with regionprops (a frequent combination), some computational work was duplicated in both functions.
Many users never use the label matrix directly. They only compute it in order to pass it to regionprops. That implies there may be a simpler, more usable interface design.
With so much code out there using bwlabel and regionprops, though, we did not want to introduce any compatibility problems.
Our solution was to introduce two new functions in R2009a, bwconncomp and labelmatrix, as well as a couple of new syntaxes for the existing function regionprops.
The new function bwconncomp finds the connected components of a binary image, just as bwlabel does. But it does not return the result as a label matrix.
As you can see, bwconncomp produces a structure. The critical information for subsequent processing is the PixelIdxList field, which contains the linear indices of the pixels belonging to each object. For example, the 2nd object found comprises
four pixels with the following linear indices:
s.PixelIdxList{2}
ans =
15
16
23
24
A key aspect of this design is that the amount of memory required is proportional to the number of object pixels, not the
number of image pixels. For a 1000-by-1000 image containing a single foreground pixel, the output data structure is nicely
compact:
Name Size Bytes Class Attributes
s2 1x1 596 struct
You can compute the label matrix, if you really need it, using the new function labelmatrix.
L2 = labelmatrix(s2);
whos L2
Name Size Bytes Class Attributes
L2 1000x1000 1000000 uint8
Notice that L2 is a uint8 matrix. Unlike bwlabel, labelmatrixdoes adjust the output data type based on the number of objects.
The last related change was to regionprops. As I mentioned before, we've noticed that this is a very common coding pattern:
L = bwlabel(bw);
s = regionprops(L, ...);
We've modified the syntax for regionprops so that you can now do this in a one step:
s = regionprops(bw, ...);
For example:
bw = imread('text.png');
s = regionprops(bw, 'Centroid');
These several new and modified functions, working together, nicely solve several design problems:
Reducing memory use
Increasing speed (in many cases) by eliminating duplicate computation
Converting a two-step workflow to a one-step workflow
We had one last concern, though. It takes code changes to benefit from these enhancements. Users who aren't aware of the
new features and don't change their code will never benefit. So what could we do to help users discover the new features?
One of the changes we made to the Image Processing Toolbox for R2009a was partially inspired by comments received on this
blog. Specifically, several blog readers complained about the memory required by the function bwlabel.
The function bwlabel labels connected components (or objects, or blobs) in a binary image. (I wrote a series of posts a couple of years ago about connected component labeling algorithms.)
I'll illustrate what bwlabel does using a very small binary image.
The output, L, of bwlabel is called a label matrix. A label matrix contains nonnegative integer values. 0s correspond to background pixels in the binary image, and positive
values identify each labeled object. For example, the elements of L that equal 2 correspond to the second object found by bwlabel.
Very often, the output of bwlabel is used as the input to regionprops, a function that measures geometric properties of regions. For example, we can compute the area of each labeled object:
s = regionprops(L, 'Area')
s =
3x1 struct array with fields:
Area
[s.Area] % comma-separated list syntax for structures
ans =
9 4 9
As I mentioned in the first paragraph above, we occasionally hear complaints about the amount of memory required by bwlabel. Because bwlabel always returns L as a double-precision matrix, the memory required is 8 bytes per image pixel.
Why is L double-precision? Because bwlabel was introduced to the Image Processing Toolbox at a time when support for integer matrices was just getting off the ground.
In 1998 or so, the only non-double data type supported by the Image Processing Toolbox was uint8. It did not seem reasonable to limit label matrices to 255 objects, and we were uncomfortable with a design that called
for the data type of L to vary according to the number of objects detected.
If there had been more than minimal support at the time for uint32 or single matrices, we might have chosen one of those types. But there wasn't, so we went with double, and that's what it's been ever since.
The memory complaints have persisted, though, particularly with users who are doing multidimensional image processing. 8 bytes
per image pixel seemed to be a high price to pay, especially when there were relatively few foreground pixels.
The usual request was to change the data type L to be uint8 when there were only a few objects. We thought about doing that, but there were other issues we wanted to fix:
1. The memory requirement was proportional to the total number of image pixels instead of the number of object pixels. This
would still be the case even we used uint8 in some cases.
2. We knew that an early step inside the implementation of regionprops was to compute a list of all the pixel indices corresponding to each object. This information is known inside the bwlabel computation, but it gets lost the label matrix doesn't represent it directly. Recomputing the pixel indices causes a speed
penalty.
3. We knew that most users didn't use the label matrix directly. Often, the only reason for computing it was to hand it off
to regionprops.
So we looked for a new design that would address all these issues and that would not cause compatibility problems.
Sometimes readers will tell me they had a hard time reproducing results from one of my blog posts, so let me tell you the easiest way to do it. Almost all of my posts that show MATLAB examples have a link at the bottom that says "Get the MATLAB code."
To see how this works, go to my recent "Learning lessons from a one-liner" post, scroll down to the bottom, and click on the "Get the MATLAB code" link just before the comments section.
I would like to remind readers about how I handle comments on this blog. (Please note that each MATLAB Central blog author handles comments somewhat differently.)
I moderate all comments, meaning that new comments will not appear until I have had a chance to review them. I welcome comments that are at least somewhat relevant to the topic of the post. I also welcome general comments about this blog—especially suggestions for new topics!
I generally do not permit comments that are irrelevant to the topic of the post, or that appear to be requests for homework help, or are requests for MATLAB code.
When you post a comment, an e-mail message is immediately sent to me, and I usually make the moderation decision as soon as I see the e-mail.
The conversations that have happened through relevant blog comments and responses have been very valuable, and I encourage you to continue sharing your thoughts here.
Matt Whitaker asked me in a blog comment recently about the references I keep on my own shelf.
Well, first of all I seem to keep fewer things on my bookshelves as the years go by. When I first started at MathWorks I had two tall bookcases in my office, filled with about 25 linear feet of books and journals. I guess I still had the academic's pack-rat habit. Now I'm down to about 5 feet of books in my office, plus about another 5 feet of journals on the team bookcase nearby.
I don't actually keep any image processing books in my office (except for my own, of course). When we're studying algorithms for possible use in our products, mostly we are looking at journal papers, and most of those are available online. The 5 feet of journal space on the team bookcase is for IEEE Transactions on Pattern Analysis and Machine Intelligence, which for some mysterious reason is still not available in electronic form. [Update: it's available now.] The image processing book that's been the most useful for toolbox development is Soille's Morphological Image Analysis: Principles and Applications. We learned a lot from that book when we were working on morphology functions in Image Processing Toolbox version 3, and I still refer to it regularly.
For the occasional digital signal processing theory question, I have two books from my grad school days: Oppenheim and Schafer's Discrete-Time Signal Processing (signed by Schafer!) and Dudgeon and Mersereau's Multidimensional Digital Signal Processing.
Most of my bookshelves these days are taken up with software development books:
General software development books like Code Complete by McConnell, The Pragmatic Programmer by Hunt and Thomas, and Refactoring by Fowler
Algorithms in C (in multiple volumes) by Sedgewick
Design Patterns by the "gang of four"
A pile of C++ books by authors such as Josuttis, Alexandrescu, Meyers, Sutter, and Vandevoorde
But perhaps the most important thing on my shelf is my personal gargoyle, who has been watching over me protectively for many years.
What's your favorite thing (book or otherwise) on your bookshelves? Post a comment.
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.
Recent Comments