Sobel-Outline

advertisement
Primer on First principles of the Sobel algorithm
Sobel has been around a along time, since 1969, so it’s hard to find simple code that is not a library
function call. E.g. OpenCV and MATLAB Sobel is not of much help if you really want to understand it
from first principles because it calls into a library (see
http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/sobel_derivatives/sobel_derivatives.html,
http://www.mathworks.com/help/images/ref/edge.html and
http://www.mathworks.com/discovery/edge-detection.html ).
I think if you adapt my example sharpen.c (http://mercury.pr.erau.edu/~siewerts/extra/code/computervision/sharpen-psf/sharpen.c ), that will be a good starting point for a pure C test implementation using
an uncompressed PPM. Then work on CUDA (or adapt existing example in CUDA Samples).
Sobel is normally applied to an uncompressed graymap or to each color channel of a pixmap that is in
memory, loaded from a PPM, PGM, JPG, PNG etc. with required parsing and decompression to get it into
an array of intensity values with conversion to floating point and back to intensity values (e.g. 0 to 255).
Often a blur transform is done prior to the gradient edge transforms (traditional, but not necessary, just
provides nicer results). Pixmap transformations can be done as well as a graymap can be done by
applying Sobel to each channel, but at 3 times the complexity. Whether color matters or not is an
interesting topic to explore (are the edges different in each of the bands, or do they correspond well).
A good reference for all gradient edge finders in general is E.R. Davies, Chapter 5, Edge Detection and for
Sobel in particular, he provides and external reference to:
Convolution simply means “take the pixel of interest” and multiply each transform value times the
neighbor over which the sliding transform lies and sum all of them including the pixel of interest (just
like any PSF). Convolution is covered in chapter 2 in E.R. Davies.
To calculate the gradient of each point in the image, the image is convolved with the Sobel Kernel.
Convolution is done by moving the kernel across the image, one pixel at a time. At each pixel, the pixel
and its neighbors are weighted by the corresponding value in the kernel, and summed to produce a new
value. This operation is shown in the following diagram (adapted from http://cudaprogramming.blogspot.com/2013/01/sobel-filter-implementation-in-c.html ).
~~~~~~~~~~~~~~~~~~~
| k00 | k10 | k20 |
|~~~~~+~~~~~+~~~~~+
| k01 | k11 | k21 |
|~~~~~+~~~~~+~~~~~+
| k02 | k12 | k22 |
|~~~~~+~~~~~+~~~~~+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| i00 | i10 | i20 | i30 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i01 | i11 | i21 | i31 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i02 | i12 | i22 | i32 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i03 | i13 | i23 | i33 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
|
.. |
.. |
.. |
.. | ..
Applying the kernel to the to the first pixel gives us an output value for that pixel (note underline and
bold for correspondence)
o00 = (k11 * i00) + (k12 * i01) + (k21 * i10) + (k22 * i11)
we treat it as though the kernel has been overlaid onto the image, with the centre pixel of the kernel
aligning we the first pixel in the image. Then we multiple each entry in the kernel by the value beneath
it, and sum them to produce a single single output value from that pixel.
You’ll have boundary conditions on edges and corners, but just adjust so the center of the transform is
over the pixel of interest and use only those neighbors that exist in the multiply and accumulate
convolution.
As you get into the center of the image, you will not have boundary conditions, so you’ll have all of the
neighbors involved in the convolution:
This operation is shown in the following diagram.
~~~~~~~~~~~~~~~~~~~
| k00 | k10 | k20 |
|~~~~~+~~~~~+~~~~~+
| k01 | k11 | k21 |
|~~~~~+~~~~~+~~~~~+
| k02 | k12 | k22 |
|~~~~~+~~~~~+~~~~~+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| i00 | i10 | i20 | i30 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i01 | i11 | i21 | i31 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i02 | i12 | i22 | i32 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| i03 | i13 | i23 | i33 | ..
|~~~~~+~~~~~+~~~~~+~~~~~+~~~
| .. | .. | .. | .. | ..
Applying the kernel to the to the first pixel gives us an output value for that pixel (note underline and
bold for correspondence0.
o11 = (k00 * i00) + (k10 * i10) + (k20 * i20) + (k01 * i01) + (k11 * i11) + (k21 * i21) + (k02 * i02) + (k12 *
i12) + (k22 * i22);
So, depending on the corner or edge that the pixel of interest lies on, you’ll have either 4, 6, or all 9
sums.
Another option is to start Sobel and create an extrapolation of data beyond the true edge (sometimes
this looks better and avoids false edge that is really the image boundary). But I would start simple and
see what things look like. The kernels used are what make Sobel a specific gradient edge finder
compare to other options (e.g. Prewitt).
The kernels used for Sobel Edge Detection are shown below.
~~~~~~~~~~~~~
|-1 | 0 | 1 |
|~~~+~~~+~~~|
|-2 | 0 | 2 |
|~~~+~~~+~~~|
|-1 | 0 | 1 |
~~~~~~~~~~~~~
x gradient kernel
~~~~~~~~~~~~~
|-1 |-2 |-1 |
|~~~+~~~+~~~|
| 0 | 0 | 0 |
|~~~+~~~+~~~|
| 1 | 2 | 1 |
~~~~~~~~~~~~~
y gradient kernel
Output the new pixel value into a new image array (so you don’t use it again as you slide the transform
through the pixels of interest in the source image).
Here’s a decent description of Sobel Operator:
1.
2.
3.
4.
5.
6.
Iterate the transform over every pixel in the image (OR TILE)
Apply the x gradient kernel (FIRST)
Apply the y gradient kernel (SECOND)
Find the length of the gradient using pythagoras' theorem
Normalise the gradient length to the range 0-255 (THIS IS WHERE IT CONVERTS TO GRAYMAP)
Set the pixels to the new values (IN A DIFFERENT IMAGE BUFFER)
Settings include the weightings used in the kernel for convolution (but default Sobel values are provided
in kernels above for classic Sobel) and a threshold for a bitmap version of the edges can be used rather
than straight normalized value (the normalized value is traditional, but converted back to a discrete
range of 0…255 for example).
From Wikipedia (https://en.wikipedia.org/wiki/Sobel_operator ), this is summarized as the following
mathematical transform:
They provide 2 test images on Wikipedia so you can compare:
Soble is straight forward to implement in C using a PGM (Portable Graymap) or PPM (Portable Pixmap)
file format to load and save. You can use Irfanview to convert any JPG, PNG, etc. into a PPM or GIMP
(http://www.gimp.org/downloads/ ). You can also compare results to MATLAB and OpenCV, which have
libraries for loading a wider variety of image formats (PNG, JPG, PPM, PGM, etc.).
Another very useful reference is - http://www.dspguide.com , especially Chapter 6 & 24 on convolutions
for images.
Download