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.