Sometimes I'd really like to be able to go back in time and fix a few of the functional designs in the Image Processing Toolbox. In a few cases the original design flaw is that we bundled up a little too much functionality in a single function. I'll give you two examples: graythresh and edge.
The function graythresh uses Otsu's method to automatically determine a "good" threshold for a gray-scale image. You use it like this:
I = imread('coins.png'); imshow(I)
T = graythresh(I); % T is a normalized threshold value between 0 and 1 bw = im2bw(I, T); imshow(bw)
The functional design flaw here is that Otsu's method doesn't really need the original image at all. It is defined solely in terms of the histogram of the image. The first thing graythresh does is compute the histogram.
But what if you had already computed the histogram for some other purpose? There's no way to use graythresh without computing it again.
My own functional design sensibility has evolved toward writing more functions that do smaller, simpler steps. So today I would design a function like graythresh so that it took a histogram as the input argument.
But isn't that less convenient? Yes. But I would move the "convenience" syntax elsewhere, probably to im2bw by giving it an "automatic threshold" syntax. If I could redesign im2bw together with graythresh, I would probably make the single-input syntax im2bw(I) use graythresh behind the scenes to compute the threshold automatically.
That design would be more convenient than it is today, because you could type im2bw(I) instead of im2bw(I, graythresh(I)), and it would also be more flexible because you would have access to smaller computational pieces.
The function edge has a similar problem. Several of the supported edge detection methods, such as Sobel and Roberts, use the gradient magnitude. The gradient magnitude is computed within edge, but there's no separate toolbox function for computing it. The toolbox and MATLAB have the low-level functions and operators that can be used to compute the gradient magnitude (fspecial, imfilter, ^2, sqrt), and the high-level function edge uses the gradient magnitude, but there's no function in the middle that conveniently computes the gradient magnitude for you.
I mention these examples to encourage you to think about your own approach to breaking down your computations into functions.
I would also be interested to hear your opinions about what other functional designs in MATLAB and the Image Processing Toolbox could be better. Please add your comments to this post.
Get the MATLAB code
Published with MATLAB® 7.8
5 CommentsOldest to Newest
If you already mention both graythresh and edge in one post I’ll use this opportunity to ponder about them: Why is it tied only to Otsu’s method? Otsu’s is one of many algorithm to determine the “best” value for thresholding. I found for my work that minimum error thresolding (Kittler 86) works better. Similar to edge, graythresh could implement several algorithms and get as input argument which one to use.
Just a thought…
Roy—The simple answer is that Otsu’s method appeared to us to be sufficient for a variety of use cases, and so we moved on to something else. There are dozens of techniques that have been published and we can’t evaluate them all. However, we are always interested to hear when someone has practical experience with multiple algorithms. Can you give an example where minimum error thresholding performs better for your purposes? Maybe we and our users can benefit from what you have learned.
I totally agree. I want to find a global average threshold from a large number of images so my initial approach was to sum all their histograms and find graythresh on that. This turned out to be impossible due to the above described problem.You could possible convert this combined histogram to some array where all individual values are represented and try on that but the large number of images => memory overflow.
I am having difficulty using graythresh() with a tiff file (which I have written to disk using imwrite(…,’TIFF’). The tiff file elements are ‘uint16’. graythresh() always returns a level of 0.0 so the result of
I = imread('mytiff.tiff'); level = graythresh(I); BW = im2bw(I,level); imview(BW)
is always an image of 1s. I can manually insert a “level” (say 0.0035) into the im2bw(I,level) to give a meaningful result from im2bw but I want to remove the manual threshholding step (obviously).
Dave—What is the maximum pixel value?
I’m guessing that the maximum value is very small, relative to the dynamic range of uint16 values. graythresh uses a 256-bin histogram in its calculation, so maybe your image values are all so small that they get counted in the lowest bin. I suggest rescaling your data before calling graythresh.