Here's a quick tip. A user question came in recently that
involved a step of finding the pixels adjacent to foreground pixels
in a binary image. Suppose you have a binary mask image, like this
one:
bw = imread('circles.png');
imshow(bw)
How can you find all the black pixels in ...
Here's a quick tip. A user question came in recently that
involved a step of finding the pixels adjacent to foreground pixels
in a binary image. Suppose you have a binary mask image, like this
one:
bw = imread('circles.png');
imshow(bw)
How can you find all the black pixels in bw that are
immediately adjacent to a white pixel? You can do this using
imdilate and a logical operation.
Use imdilate to "grow" the mask by one
pixel:
bw2 = imdilate(bw, ones(3,3));
Now use a logical operation to find which pixels are white in
bw2 but black in bw:
MathWorks developer Dave L. created an
Intruder Detection example to demonstrate how Image Acquisition
Toolbox and Data Acquisition
Toolbox can work together. The program displays live video and
audio data acquired from a web cam and sound card. Whenever certain
motion or sound thresholds are excee...
MathWorks developer Dave L. created an
Intruder Detection example to demonstrate how Image Acquisition
Toolbox and Data Acquisition
Toolbox can work together. The program displays live video and
audio data acquired from a web cam and sound card. Whenever certain
motion or sound thresholds are exceeded, an alarm will sound while
the video and audio data are recorded to disk for 10 seconds.
Technical Marketing Manager Bruce Tannenbaum and I will be
hosting a live webinar next Thursday, June 28, on color image
processing.
If you're interested, browse to the MathWorks home page, click on the
"Events" tab, then scroll down and click on "Color
Image Processing with MATL...
Technical Marketing Manager Bruce Tannenbaum and I will be
hosting a live webinar next Thursday, June 28, on color image
processing.
If you're interested, browse to the MathWorks home page, click on the
"Events" tab, then scroll down and click on "Color
Image Processing with MATLAB."
As I mentioned in an
earlier post, Adobe Photoshop CS3 Extended provides some MATLAB
integration features. If you're interested, here are a couple
of links I've seen that might be useful:
Blogger "Dr. Woohoo" has written up notes on his
experience using the two products togethe...
As I mentioned in an
earlier post, Adobe Photoshop CS3 Extended provides some MATLAB
integration features. If you're interested, here are a couple
of links I've seen that might be useful:
Blogger "Dr. Woohoo" has written up notes on his
experience using the two products together.
Adobe has a
help page showing how to verify that the MATLAB integration
feature is working properly.
Loren wrote about the
2007 MATLAB World Tour in her Art of MATLAB blog
recently. Several other MathWorks developers also attended some of
the events.
One message that they brought back to us is that many of the
good features we put into our products simply have not yet been
discovered by many of ...
Loren wrote about the
2007 MATLAB World Tour in her Art of MATLAB blog
recently. Several other MathWorks developers also attended some of
the events.
One message that they brought back to us is that many of the
good features we put into our products simply have not yet been
discovered by many of our users. That has inspired me to think
about a new kind of post on this blog - I think of it as the
"Didja Know?" post. (Many of the MATLAB Desktop blog
posts are Didja Know? posts.) In my Didja Know? posts, I'll try
to highlight useful functions or function options that you might
not have discovered yet.
First up: the border replication option of imfilter.
When you perform convolution on an image, one question to
consider is: How do you compute the convolution sum for pixels
along the image border? By default, imfilter assumes that
image pixels "outside" the image are zero. Mathematically
this is kind of reasonable, but it tends to produce a dark strip
along the edge of the output image. Here's an example to show
what I mean:
I = imread('cameraman.tif');
imshow(I)
imcredit('Image courtesy of MIT')
J = imfilter(I, ones(5,5)/25);
imshow(J)
But you can tell imfilter to handle image borders by
replicating the border pixel values. That often produces a more
desirable result:
K = imfilter(I, ones(5,5)/25, 'replicate');
imshow(K)
There are other border options as well. See the imfilter documentation for more information.
I've about run out of things to say for now about connected
component labeling algorithms. ("Hurray!" shouts the
audience.)
For reference, here's a summary of all the posts in the
series:
Part 1 - Introduction
Part 2 - Connectivity definitions
Part 3 - Adjacency matrices a...
I've about run out of things to say for now about connected
component labeling algorithms. ("Hurray!" shouts the
audience.)
For reference, here's a summary of all the posts in the
series:
I described in my
previous connected component labeling post the algorithm used
by bwlabeln. This time I'll talk about the variation
used by bwlabel. This variation uses run-length
encoding as the first step.
Here's what I mean by run-length encoding. Consider this
small binary image mat...
I described in my
previous connected component labeling post the algorithm used
by bwlabeln. This time I'll talk about the variation
used by bwlabel. This variation uses run-length
encoding as the first step.
Here's what I mean by run-length encoding. Consider this
small binary image matrix:
Such a binary image can be represented as a collection of
runs, or sequences of 1s. Working columnwise, this image
contains 9 runs:
Each run can be represented by its starting pixel and by the
number of pixels in the run, which is called the run length.
Hence the term run-length encoding.
For a larger binary image containing larger objects, the number
of runs can be much smaller than the number of foreground pixels.
But the connectivity analysis can be completely determined based on
the runs. In our small example:
Run #3 is connected to run #1
Run #4 is connected to run #2
Run #6 is connected to run #4
Run #7 is connected to run #5
Run #8 is connected to run #6
Run #9 is connected to run #7
Run #9 is connected to run #8
This set of connectivity pairs can be resolved into equivalence
classes using the
technique I described earlier based on dmperm. In this
example there are only two equivalence classes, corresponding to
the two connected components.
The function bwlabel calls computes a run-length
encoding first. As it finds each run, it also determines which runs
on the previous column are connected, if any. Then it constructs a
sparse adjacency matrix and calls dmperm to compute the
equivalence classes. Then it labels each run in the output label
matrix according to the equivalence class it belongs to.
This is a very efficient method because it scans each pixel in
the input image only once, and also because the adjacency matrix is
usually relatively small. It is R-by-R, where R is the number of
runs.
You can find this method described in Haralick and Shapiro,
Computer and Robot Vision Volume 1, Addison-Wesley, 1992,
pp. 40-48. (Note that the equivalence class resolution method used
by bwlabel is different than the one described in the
book.)
Today I'll continue thinking about plateaus in a DEM and
what they mean for calculating pixel flow. Here's a very tiny
portion of my DEM array, just northwest of
North Pond.
a = [120 118 123; 120 118 125; 119 119 126]
a =
120 118 123
120 118 125
119 119 126
...
Today I'll continue thinking about plateaus in a DEM and
what they mean for calculating pixel flow. Here's a very tiny
portion of my DEM array, just northwest of
North Pond.
a = [120 118 123; 120 118 125; 119 119 126]
a =
120 118 123
120 118 125
119 119 126
The center pixel doesn't have a downhill neighbor, so
I'm calling it a plateau pixel. No matter that it's
a very small plateau; we can't compute a pixel flow direction
for it, and that will cause problems when we get around to
computing upslope area.
One technique used in image processing to deal with plateaus is
called the lower complete transformation. A lower
complete image is one where the only pixels having no downhill
neighors are the pixels belonging to regional minima. Roughly
speaking, the lower complete transformation operates by elevating
plateau pixels. Pixels further from the plateau edge get elevated
more. Of course, pixels uphill from the plateau need to be elevated
as well so that they remain uphill. I have read about this
technique but have never implemented it myself. (For more
information, I recommend P. Soille, Morphological Image
Analysis: Principles and Applications, 2nd edition, Springer,
2003, pp. 222-226.)
I'm going to use a different technique, one that's based
on the algorithm in the Image Processing Toolbox function
roifill. This function fills in pixels in a particular
region by smoothly interpolating from the pixels surrounding the
region. It does so by solving a sparse linear system based on the
notion that, in the filled output, each pixel in the filled region
equals the average of its north, east, south, and west neighbors.
(It's kind of an interesting method. Maybe that'll be a
future blog topic.)
Here's the example (slightly modified) from the
roifill documentation:
I = imread('eight.tif');
imshow(I)
c = [222 272 300 270 221 194 222];
r = [21 21 75 121 121 75 21];
hold on
plot(c,r,'r','LineWidth',4)
J = roifill(I,c,r);
imshow(J)
And here's what roifill does to our tiny snippet
from the DEM:
Well, the two center pixels now have downhill neighbors, but
WAIT! The (1,2) pixel no longer has a downhill neighbor! OK, time
to 'fess up. I didn't really anticipate that this would be
a problem. I'll have to give this some thought. My first
reaction is: It'll be OK because we can use the original,
unmodified DEM values to compute the pixel flow for the nonplateau
pixels. We only need the modified DEM values to compute pixel flow
for the plateau pixels. But I'll sleep on it.
Assuming I can resolve that problem successfully, we can use
roifill to compute pixel flow directions for the
midplateau pixels. It won't help us, though, for the plateau
pixels that are part of regional maxima or regional minima.
I'll figure out what to do about those next week.
The MathWorks
announced yesterday the availability of MATLAB
® & Simulink® Student Version R2007a.
Readers of this blog might be interested to know that several
additional products, including Image Processing
Toolbox, are now bundled with the product. Previously, these
additional products req...
Readers of this blog might be interested to know that several
additional products, including Image Processing
Toolbox, are now bundled with the product. Previously, these
additional products required a separate purchase.
In my
previous upslope area post, I showed this graphic of pixel flow
around North Pond in Milford, Massachusetts:
Notice that pixels in the pond have no arrows. In fact, the
pixelFlow M-file I showed previously is unable to compute
a pixel flow direction or magnitude for these pixels because...
In my
previous upslope area post, I showed this graphic of pixel flow
around North Pond in Milford, Massachusetts:
Notice that pixels in the pond have no arrows. In fact, the
pixelFlow M-file I showed previously is unable to compute
a pixel flow direction or magnitude for these pixels because they
are in a flat region, or plateau. More specifically,
pixelFlow returns a flow direction of NaN for any
pixel that has no downhill neighbor.
There is a simple way to find all such pixels using
morphological erosion. Erosion with a flat structuring element is
equivalent to a local minimum operator. If the minimum value of a
pixel and its neighbors equals the pixel itself, then we'll
call it a plateau pixel.