Did you know that MathWorks publishes information about product bugs on its web site? And that you can be automatically notified with updates regarding specific bugs, or regarding specific products?
A few weeks ago, Joan posted a blog comment about strange behavior in the deconvwnr function. I investigated and determined that there was a bug in some code that was intended to avoid divide-by-zero warnings. I fixed the problem and then published a bug report, including a work-around, to our support site. (The fix was too late to be included in the upcoming R2008b release, so it will be in R2009a.)
The bug report includes a summary of the problem, which product releases have the problem, whether the problem has been fixed in a shipped release, and whether there is a work-around. In the case of the deconvwnr problem, there is a work-around, and the report includes instructions for downloading new versions of two M-files.
To search the online bug reports, start at the MathWorks home page, then click on Support, and then click on View and Report Bugs. From this page you can search the bug reports, look at bug reports for specific products, set up a watch list, and more. You can sign up to receive e-mail whenever a specific bug report is updated, or you can subscribe to RSS feed, customized to the list of products you are interested in.
There is also a "Frequently Asked Questions" page about bug reports that explains, for example, what an "OPEN" status means, or why some bugs aren't shown in the bug reports.
We are continually trying to improve the quality of our products and therefore reduce the need for published bug reports. In my area, there are fewer unfixed bugs in the development builds of the Image Processing Toolbox and the Mapping Toolbox than at any previous time in the history of these products. But any number of unfixed bugs is too many, and we're trying to do better for you.
Note: Most of the time, you should report product bugs directly to MathWorks technical support rather trying to post them as comments on this or other MATLAB Central blogs. My usual practice is to delete any comments that aren't directly relevant to the topic of the blog post. Joan's comment was relevant to the topic, so I let it through.
In my previous post on dilation algorithms I discussed structuring element decomposition. We looked at the decomposition of structuring elements with rectangular domains.
Today I want to follow up on the idea by looking at decompositions of other structuring element shapes.
The strel function offers a variety of flat structuring element shapes:
diamond
disk
line
octagon
pair
periodicline
rectangle
square
(The strel function also offers nonflat shapes, and shapes with arbitrary domains.)
Let's look at the 'diamond' shape. The doc says SE = strel('diamond', R) creates a flat, diamond-shaped structuring element, where R specifies the distance from the structuring element origin to the points of the diamond." For example:
The display says the structuring element has 61 neighbors in its domain, but the four decomposed structuring elements have
a total of only 17 neighbors.
What shapes makes up the decomposition? We can use getsequence and getnhood to find out.
se1_seq = getsequence(se1);
for k = 1:numel(se1_seq)
This decomposition comes from Rein van den Boomgard and Richard van Balen, "Methods for Fast Morphological Image Transforms
Using Bitmapped Binary Images," Computer Vision, Graphics, and Image Processing: Models and Image Processing, vol. 54, no. 3, May 1992, pp. 252-254. (That journal name sure is a mouthful!)
Now let's look at the 'disk' structuring element. By default, strel('disk',R) actually gives you an approximation to a disk shape, where the approximation is based on a technique called radial decomposition using periodic lines. The reference sources are:
Rolf Adams, "Radial Decomposition of Discs and Spheres," Computer Vision, Graphics, and Image Processing: Graphical Models and Image Processing, vol. 55, no. 5, September 1993, pp. 325-332.
Ronald Jones and Pierre Soille, "Periodic lines: Definition, cascades, and application to granulometries," Pattern Recognition Letters, vol. 17, 1996, 1057-1063.
Well, that's definitely an approximation. It looks a lot more like an octagon than a circle. The syntax strel('disk',R,N) gives you more control over the approximation. N can be 0, 4, 6, or 8. The values 4, 6, and 8 indicate different levels of approximation. The default value is 4. With
N equal to 8, the result looks closer to a circle, but dilation is a little slower because the decomposition isn't as efficient.
Do you read any of the other MATLAB Central blogs? There's a lot of good information on them.
For several years, the "Pick of the Week" blog has regularly highlighted the best contributions on the MATLAB Central File Exchange. Until recently, it was "Doug's Pick of the Week." As regular "pick" readers know, Doug shifted his emphasis some time ago to making tutorial videos about MATLAB, while guest bloggers Bob, Brett, and Jiro continued giving you the best of the File Exchange.
These four MathWorkers have now split their blogging into two blogs. The "File Exchange Pick of the Week" is still at the same location and is jointly run by Bob, Brett, and Jiro. And Doug is now publishing his tutorial videos on the new "Doug's MATLAB Video Tutorials" blog.
When the "Inside the MATLAB Desktop" blog was originally started, we thought it would written by entire Desktop team. That never really happened, though. The blog was always run by one or two people, with occasional guest contributions. Most recently, Ken and Mike have been running things, so the Desktop blog has been retitled "Ken & Mike on the MATLAB Desktop." Other MathWorks developers will still occasionally contribute.
"Loren on the Art of MATLAB" has long been our most popular blog and is chock full of valuable tips on programming in MATLAB. And if you're into the Simulink side of our product family, be sure to check out "Seth on Simulink."
Each of our blogs have links on the sidebar for subscribing, either by e-mail or by RSS feed. You might also want to check out the "Blog Archives" links, since most of the technical topics don't get dated and are just as informative now as when they were first written.
What suggestions do you have for our blogs? Do you have any ideas for what new blogs you'd like to see? Let us know by commenting on this post.
Dilation algorithms—structuring element decomposition
This is the second post in my series on algorithm concepts behind the implementation of dilation and erosion in the Image Processing Toolbox. Today I want to
talk about structuring element decomposition.
Some useful structuring elements can be represented as the dilation of two or more smaller structuring elements. Dilation
implementations can exploit this decomposition of structuring elements into smaller structuring elements by taking advantage
of the associativity property of dilation.
That is, suppose image g is the dilation of image f with structuring element b:
where the star operator means dilation. And further suppose that b is the dilation of two other structuring elements:
Then the original image dilation equation can be rewritten as:
In English, the equation above says we can dilate f with structuring element b by:
1. Dilating f first with structuring element b1.
2. Dilating the result of step 1 with structuring element b2.
Let's see how this might help make dilation faster. One of the most commonly-used structuring element shapes is the square.
For example, here's a simple 5-by-5 array of 1s that can define a structuring element domain (or neighborhood):
It turns out that a square (or rectangular) structuring element can be decomposed into two structuring elements: a horizontal
line, and a vertical line.
b1 = ones(1, 5)
b1 =
1 1 1 1 1
b2 = ones(5, 1)
b2 =
1
1
1
1
1
You can check that the dilation of b1 and b2 equals b by using the 'full' option of imdilate:
How does this help us? Well, as I discussed last time, computing dilation directly from its defining equation requires Q comparisons per pixel, where Q is the number of elements in the structuring element domain. The 5-by-5 square structuring element has 25 elements in its
domain. But structuring elements b1 and b2 have only five elements each. So you could dilate by one and then again by the other and require only 40% of the comparisons.
Let's look at how structuring element decompositions are computed and represented in the Image Processing Toolbox. The function
strel makes a structuring element object. You give strel the name of a shape, such as 'rectangle', plus any parameters required for the shape. When you use strel to make a rectangular structuring element, the resulting object displays information about itself, including the decomposition:
Today's post is brought to you directly from the software developer half of my brain.
MATLAB 6 was the first version to use the FFTW library for fast Fourier transform computations, and I was one of the developers who worked on that change.
Making changes to fft and related functions made me a bit nervous. What if we made a mistake and broke it somehow? That would be 15 minutes of fame I would definitely not enjoy.
The best way to proceed when changing existing, working code is to make sure first that you have thorough, effective tests. (See, for example, "The First Step in Refactoring" in Martin Fowler's book, Refactoring: Improving the Design of Existing Code.) And for numerical computation, nothing gives you more confidence in your tests than using independent computation methods to validate your code.
Besides using fft, I can think of at least two other reasonably easy ways to compute the discrete Fourier transform in MATLAB. One is to write an M-file that directly implements the discrete Fourier transform equation. Another is to use a matrix-vector multiply with the Fourier matrix (see the doc for the dftmtx function in the Signal Processing Toolbox.) Normally, you would never want to use either of these methods when you can instead use a much faster fast Fourier transform algorithm.
However, pure speed is not so critical for testing purposes. Many of our automated tests for fft and related functions test their output against the result found using the matrix-vector multiplication. That turned out to be very helpful for making sure that our changes to fft did not result in incorrect output. (If you'd like to know more about MATLAB and FFTW, read this Cleve's Corner.)
Here's another testing example illustrating the need for independent computation. The Mapping Toolbox has functions for computing minimum distance curves on an ellipsoid. No closed-form solutions exist, so series or iterative approximations are commonly used. The Mapping Toolbox test suite checks the numerical accuracy of these approximations by comparing them to the results obtained using MATLAB ODE solvers. (This testing technique was published in a paper. See R. Comer and N. Ramarathnam, "Numerical Validation of Curves on the Ellipsoid," Proceedings of the ASPRS 2005 Annual Conference.)
Often you can independently compute small positive test cases by hand. Many image morphology test cases in the Image Processing Toolbox test suite were computed by hand directly from the relevant formulas and definitions.
It's tempting sometimes, especially for operations that are especially tedious to compute by hand or by another method, to construct test case validation data by saving the output data from the code you are trying to test. Such a test is only useful for making the sure that today's output from the code is the same as yesterday's; it doesn't tell you anything about whether the answers are correct. That's better than no test at all, but not nearly as good as independent validation of correctness.
My blog has a rule, which I just now made up, that my second post during the month of September has to be totally off topic.
So you've been warned!
OK, you're still reading, so I want to ask you: Do you like to play chess?
A few years ago I was sitting in another developer's office here, staring idly at the Escher print on her wall. This print was a long, thin strip that went almost all the way around the top of the office walls. It showed many different geometric motifs merging from one form to another, in typical Escher fashion. It suddenly dawned on me that the chess pieces in one section of the print were arranged in a real chess position.
Here it is:
So how about it, image processing / chess fans? What's going on in this position? Who is winning, and what are the next moves going to be?
Next time I'll return to discussing image processing, I promise.
Post updated on September 4 based on feedback from Cris Luengo's comment.
Today I'm starting a new series covering some of the concepts underlying algorithms for performing morphological dilation
(and erosion, which is very similar). Most of the time, when people talk about image dilation, they mean the form of dilation
that is a local maximum operation on the neighbors of each pixel. For example, here's how to compute the local maximum, for
each image pixel, with that pixel and its eight neighbors:
The set of neighborhood pixels involved in the max operator forms a shape called the structuring element. The structuring element doesn't have to be square, as above. Here is dilation with a short, 3-pixel line:
Let's consider how long it should take to compute dilation. Suppose an image has P pixels, and the structuring element contains
Q neighbors. Computing the output for a particular pixel involves both Q memory reads and Q comparisons. Therefore we might
expect the computation time to be proportional to Q.
We can try to verify that behavior using square structuring elements of varying sizes. (I'll be using my timeit function, which you can download from the MATLAB Central File Exchange.)
% Read in a small sample image and replicate it to make a 1k-by-1k% test image.
I = repmat(imread('rice.png'), 4, 4);
% Measure dilation times using a set of square structuring elements% ranging in size from 5-by-5 to 97-by-97.
w = 5:4:97;
% The number of neighbors, Q, in each structuring element will be% w^2. We are guessing that the running time will be proportional% to Q.
Q = w.^2;
% Initialize vector containing recorded times.
times = [];
for wk = w
% Not that many MATLAB users are familiar with the for-loop% construct above. I'll send a MATLAB t-shirt to the first% person who adds a comment to this post with a brief, clear,% and correct explanation.
se = strel(ones(wk, wk));
f = @() imdilate(I, se);
times(end+1) = timeit(f);
end
plot(Q, times)
ylim([0 1.5*max(times)])
That plot looks almost constant, with maybe just a hint of an increase with Q.
So is imdilate somehow computing dilation faster than expected?
That's the subject of this series. We'll start digging in deeper next time.
Transparent graphics objects can be used effectively to visualize image processing concepts. Two particularly useful techniques
are:
Highlighting image regions with transparent patches
Displaying one image transparently over another
Today I'll show how to highlight image regions with patches. For this example I'll use the 'Extrema' measurement returned by regionprops. The extrema for a given object are eight points: the left-most pixel on the bottom, the right-most pixel on the bottom,
the top-most pixel on the right, the bottom-most pixel on the right, and so on.
I'll start with the rice image, segmenting it using techniques I've shown before.
I = imread('rice.png');
imshow(I)
Even out the illumination with the tophat operator, threshold, and then clean up the thresholded image a bit.
A MATLAB user recently asked in the MATLAB newsgroup how to fill "small" holes in a binary image. The function imfill can be used to fill all holes, but this user only wanted to fill holes having an area smaller than some threshold.
That's an interesting question. It can be done using a combination of imfill, bwareaopen, and MATLAB logical operators. Here's how.
Last fall I wrote about a complaint some MATLAB users had about reading certain kinds of TIFF files. Specifically, some users have TIFF files that each contain tens of thousands of images—or more! One user sent us a single TIFF file containing almost 130,000 individual images. My tongue-in-cheek name for these files is "Massively Multipage TIFF" (MMT).
The problem is that the syntax for reading the k-th image from a TIFF file:
>> I = imread(filename, k);
takes significantly longer for images at the end of the file. As a result, reading all of the images in such a file takes way too long. I discussed the technical issues in the post "How many images can fit in a TIFF file" last September.
We now have updated files you can use to improve import performance on these TIFF files. The necessary files and instructions can be downloaded here. The patch is only for the most recent MATLAB release, R2008a. Please do not try to apply the patch to earlier releases.
[Update - August 11, 2008 - The download link above now points to an official MathWorks technical support solution page.
With the updated files, images at the end of a TIFF file can be read in the same amount of time as images at the beginning of the file. Note that a different syntax is necessary, so please read the instructions in the download carefully.
You should be aware that these updates will NOT be included in the upcoming R2008b release. These changes were implemented very recently, and the relevant development deadline for R2008b changes was a couple of months ago.
Also, we don't have any updates available yet for improving the performance of creating such TIFF files using imwrite.
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