C# How to: Gradient Based Edge Detection

Article purpose

This article provides a technical discussion exploring the topic of Gradient Based Edge Detection and related aspects. Several filtering options are illustrated and explained ranging from pure black and white to .

Gradient Based Edge Detection

Sample Source Code

This article is accompanied by a sample source code Visual Studio project which is available for download here.

Using the Sample Application

All of the concepts implemented in this article can be replicated and tested by making use of the sample application included in the associated sample source code. The sample application user interface provides several configurable options to be implemented when performing Gradient Based Edge Detection. The available configuration categories are: Filter Type, Derivative Level, Threshold and Colour Factor Filters.

Gradient Based Edge Detection

Configurable Filter Types exposed to the end user consist of:

  • None – When selecting this option no filtering will be applied. Source/input are displayed reflecting no change. 
  • Edge Detect Mono – This option  represents basic Gradient Based Edge Detection. Resulting are only expressed in terms of black and white pixels.
  • Edge Detect Gradient – Gradient Based Edge Detection revolves around calculating pixel colour gradients. This option signifies  a scenario where the pixels forming resulting express the relevant pixel’s colour gradient, when a pixel has been determined to reflect part of an edge. If  a pixel is not considered to be part of an edge, the relevant pixel’s colour value will be set to black.
  • Sharpen – In terms of , can be achieved by emphasising detected edges in source/input images. Emphasising edges involves combining a source/input and an which express only detected edges.
  • Sharpen Gradient – This option combines calculated colour gradients and the original colour value of a pixel on a per pixel basis when a pixel has been determined to be part of an edge. If a pixel does not form part of an edge, the pixel’s colour value is set to that of the original pixel colour.

Gradient Based Edge Detection

The user interface defines two : First Derivative and Second Derivative. These user interface options relate to the method being implemented, either First Order or Second Order derivative operators.

Comparing a global threshold and colour gradients on a per pixel scenario forms the basis of Gradient Based Edge Detection. The TrackBar labelled Threshold enables the user to adjust the global threshold value implemented in pixel colour gradient comparisons.

Gradient Based Edge Detection

The Colour Factor Filters impact on the level or extent to which colours are expressed in resulting . The three colour factors, Red, Green and Blue are intended to be used in combination with the filtering options: Filter Type and Threshold. Colour Factor Filter affects when implemented in combination:

  • Filter Type – Edge Detect Mono: Not applicable. Edge Detect Mono filtering discards all pixel colour data.
  • Filter Type – Edge Detect Gradient: If a pixel is detected as part of an edge, the pixel’s colour values will be set to the gradient calculated when evaluating edge criteria. Gradient values are multiplied by Colour Factor values before being assigned to a resulting pixel.
  • Filter Type – Sharpen: The pixels which form part of an edge, in terms of the resulting the corresponding pixels will be set to the same colour values. In addition pixel colour values in the resulting are multiplied by with the relevant Colour Factor. The pixels not detected as part of an edge will not be multiplied with any Colour Factor values.
  • Filter Type – Sharpen Gradient: Edge detected pixels in a source/input will have the effect of corresponding pixels in the resulting being assigned to the calculated colour gradient value, multiplied with the relevant Colour Factor value. In the scenario of a pixel not being detected as forming part of an edge, Colour Factors will not be implemented.
  • Threshold: The global threshold value specified by the user determines the level of sensitivity to which edges will be detected. The degree to which edges are detected through the threshold value impacts upon whether a pixel will be multiplied with the relevant Colour Factor value.

Gradient Based Edge Detection

The user has the option of saving filtered to the local system by clicking the Save Image button. The image below is a screenshot of the Gradient Based Edge Detection sample application in action:

Gradient Based Edge Detection Sample Application

Gradient Based Edge Detection Theory

Gradient Based Edge Detection qualifies to be classified as a neighbouring pixel algorithm. When calculating a pixel’s value in order to determine if a pixel should be expressed as part of an edge or not, the result will be determined by:

  • The values expressed by neighbouring pixels. The more intense or sudden differences that occur between neighbouring pixels will result in higher accuracy .
  • A user specified global threshold value used in comparison operations acts as a cut-off value, ultimately being the final factor to determine if a pixel should be expressed as part of an edge.

Gradient Based Edge Detection

In the sample source code we implement the following steps when calculating whether a pixel should be considered as part of an edge:

  1. Iterate each pixel that forms part of the source/input .
  2. Calculate and combine horizontal and vertical gradients for each of the colour components Red, Green and Blue. If the sum total of each colour component’s calculated gradient exceeds the global threshold value consider the pixel being iterated as part of an edge. If the sum total of colour gradients equate to less than the global threshold implement step 3.
  3. Calculate a pixel’s horizontal gradient per colour component. When comparing the gradient sum total against the global threshold consider the pixel being iterated part of an edge if the sum total of gradient values exceed that of the threshold. If the total of colour gradient value do not exceed the threshold value continue to step 4.
  4. Calculate a pixel’s vertical gradient per colour component. When comparing the gradient sum total against the global threshold consider the pixel being iterated part of an edge if the sum total of gradient values exceed that of the threshold. If the sum total of colour gradients  do not exceed the threshold value continue to step 5.
  5. Calculate and combine diagonal gradients for each of the colour components Red, Green and Blue. If the sum total of each colour component’s calculated gradient exceeds the global threshold value consider the pixel being iterated as being part of an edge. If the sum total of colour gradients equate to less than the global threshold the pixel being iterated should not be considered as part of an edge.

Gradient Based Edge Detection

If we determined that a pixel forms part of an edge, the value expressed by the corresponding pixel in the resulting will be determined by the Image Filter configuration value:

  • Edge Detect Mono – All pixels will be set to white.
  • Edge Detect Gradient – Each colour component will be assigned to the related colour gradient calculated when performing . Each Colour gradient will be multiplied with the related colour factor.
  • Sharpen – The value of a resulting pixel will be calculated as the product of the corresponding source pixel and the related colour factor value.
  • Sharpen Gradient – Results are calculated in terms of the sum total of the corresponding input pixel and the product of the related colour gradient and colour factor value.

Gradient Based Edge Detection

Implementing Gradient Based Edge Detection

The sample source code associated with this article provides the defines of the GradientBasedEdgeDetectionFilter targeting the class. This method  iterates every pixel contained in the source/input . Whilst iterating pixels the method creates a 3×3 window/ covering the neighbouring pixels surrounding the pixel currently being iterated. Colour gradients are calculated from every pixel’s neighbouring pixels.

The following Code snippet provides the definition of the GradientBasedEdgeDetectionFilter :

public static Bitmap GradientBasedEdgeDetectionFilter( 
                                this Bitmap sourceBitmap, 
                                EdgeFilterType filterType, 
                                DerivativeLevel derivativeLevel,  
                                float redFactor = 1.0f, 
                                float greenFactor = 1.0f, 
                                float blueFactor = 1.0f, 
                                byte threshold = 0) 
{ 
    BitmapData sourceData = 
               sourceBitmap.LockBits(new Rectangle (0, 0, 
               sourceBitmap.Width, sourceBitmap.Height), 
               ImageLockMode.ReadOnly, 
               PixelFormat.Format32bppArgb); 

byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];
byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
int derivative = (int)derivativeLevel; int byteOffset = 0; int blueGradient, greenGradient, redGradient = 0; double blue = 0, green = 0, red = 0;
bool exceedsThreshold = false;
for(int offsetY = 1; offsetY < sourceBitmap.Height - 1; offsetY++) { for (int offsetX = 1; offsetX < sourceBitmap.Width - 1; offsetX++) { byteOffset = offsetY * sourceData.Stride + offsetX * 4;
blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]) / derivative;
blueGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]) / derivative;
byteOffset++;
greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]) / derivative;
greenGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]) / derivative;
byteOffset++;
redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]) / derivative;
redGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]) / derivative;
if (blueGradient + greenGradient + redGradient > threshold) { exceedsThreshold = true ; } else { byteOffset -= 2;
blueGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]); byteOffset++;
greenGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]); byteOffset++;
redGradient = Math.Abs(pixelBuffer[byteOffset - 4] - pixelBuffer[byteOffset + 4]);
if (blueGradient + greenGradient + redGradient > threshold) { exceedsThreshold = true ; } else { byteOffset -= 2;
blueGradient = Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]);
byteOffset++;
greenGradient = Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]);
byteOffset++;
redGradient = Math.Abs(pixelBuffer[byteOffset - sourceData.Stride] - pixelBuffer[byteOffset + sourceData.Stride]);
if (blueGradient + greenGradient + redGradient > threshold) { exceedsThreshold = true ; } else { byteOffset -= 2;
blueGradient = Math.Abs(pixelBuffer[byteOffset - 4 - sourceData.Stride] - pixelBuffer[byteOffset + 4 + sourceData.Stride]) / derivative;
blueGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride + 4] - pixelBuffer[byteOffset + sourceData.Stride - 4]) / derivative;
byteOffset++;
greenGradient = Math.Abs(pixelBuffer[byteOffset - 4 - sourceData.Stride] - pixelBuffer[byteOffset + 4 + sourceData.Stride]) / derivative;
greenGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride + 4] - pixelBuffer[byteOffset + sourceData.Stride - 4]) / derivative;
byteOffset++;
redGradient = Math.Abs(pixelBuffer[byteOffset - 4 - sourceData.Stride] - pixelBuffer[byteOffset + 4 + sourceData.Stride]) / derivative;
redGradient += Math.Abs(pixelBuffer[byteOffset - sourceData.Stride + 4] - pixelBuffer[byteOffset + sourceData.Stride - 4]) / derivative;
if (blueGradient + greenGradient + redGradient > threshold) { exceedsThreshold = true ; } else { exceedsThreshold = false ; } } } }
byteOffset -= 2;
if (exceedsThreshold) { if (filterType == EdgeFilterType.EdgeDetectMono) { blue = green = red = 255; } else if (filterType == EdgeFilterType.EdgeDetectGradient) { blue = blueGradient * blueFactor; green = greenGradient * greenFactor; red = redGradient * redFactor; } else if (filterType == EdgeFilterType.Sharpen) { blue = pixelBuffer[byteOffset] * blueFactor; green = pixelBuffer[byteOffset + 1] * greenFactor; red = pixelBuffer[byteOffset + 2] * redFactor; } else if (filterType == EdgeFilterType.SharpenGradient) { blue = pixelBuffer[byteOffset] + blueGradient * blueFactor; green = pixelBuffer[byteOffset + 1] + greenGradient * greenFactor; red = pixelBuffer[byteOffset + 2] + redGradient * redFactor; } } else { if (filterType == EdgeFilterType.EdgeDetectMono || filterType == EdgeFilterType.EdgeDetectGradient) { blue = green = red = 0; } else if (filterType == EdgeFilterType.Sharpen || filterType == EdgeFilterType.SharpenGradient) { blue = pixelBuffer[byteOffset]; green = pixelBuffer[byteOffset + 1]; red = pixelBuffer[byteOffset + 2]; } }
blue = (blue > 255 ? 255 : (blue < 0 ? 0 : blue));
green = (green > 255 ? 255 : (green < 0 ? 0 : green));
red = (red > 255 ? 255 : (red < 0 ? 0 : red));
resultBuffer[byteOffset] = (byte)blue; resultBuffer[byteOffset + 1] = (byte)green; resultBuffer[byteOffset + 2] = (byte)red; resultBuffer[byteOffset + 3] = 255; } } Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);
BitmapData resultData = resultBitmap.LockBits(new Rectangle (0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);
Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);
resultBitmap.UnlockBits(resultData);
return resultBitmap; }

Gradient Based Edge Detection

Sample Images

The banner images depicting a butterfly featured throughout this article were generated using the sample application. The original image has been licenced under the Creative Commons Attribution-Share Alike 3.0 Unported, 2.5 Generic, 2.0 Generic and 1.0 Generic license. The original image is attributed to Kenneth Dwain Harrelson and can be downloaded from Wikipedia.

The sample image featuring a Scarlet Macaw has been licensed under the Creative Commons Attribution-Share Alike 3.0 Germany license. The original image can be downloaded from .

The Original Image

Ara_macao_-flying_away-8a

Edge Detect, Second Derivative, Threshold 50 

Edge Detect, Second Derivative, Threshold 50

Edge Detect Gradient, First Derivative, Blue

Edge Detect Gradient, First Derivative, Blue

Edge Detect Gradient, First Derivative, Green

Edge Detect Gradient, First Derivative, Green

Edge Detect Gradient, First Derivative, Green and Blue

Edge Detect Gradient, First Derivative, Green and Blue

Edge Detect Gradient, First Derivative, Red

Edge Detect Gradient, First Derivative, Red

Edge Detect Gradient, First Derivative, Red and Blue

Edge Detect Gradient, First Derivative, Red and Blue

Edge Detect Gradient, First Derivative, Red and Green

Edge Detect Gradient, First Derivative, Red and Green

Edge Detect Gradient, First Derivative, Red, Green and Blue

Edge Detect Gradient, First Derivative, Red, Green and Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Black

Edge Detect Sharpen, Second Derivative, Threshold 40, Black

Edge Detect Sharpen, Second Derivative, Threshold 40, Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Green

Edge Detect Sharpen, Second Derivative, Threshold 40, Green

Edge Detect Sharpen, Second Derivative, Threshold 40, Green and Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Green and Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Red

Edge Detect Sharpen, Second Derivative, Threshold 40, Red

Edge Detect Sharpen, Second Derivative, Threshold 40, Red and Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Red and Blue

Edge Detect Sharpen, Second Derivative, Threshold 40, Red and Green

Edge Detect Sharpen, Second Derivative, Threshold 40, Red and Green

Edge Detect Sharpen, Second Derivative, Threshold 40, White

Edge Detect Sharpen, Second Derivative, Threshold 40, White

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Green

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Green

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Green and Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Green and Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red and Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red and Blue

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red and Green

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, Red and Green

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, White

Edge Detect Sharpen Gradient, First Derivative, Threshold 0, White

Related Articles and Feedback

Feedback and questions are always encouraged. If you know of an alternative implementation or have ideas on a more efficient implementation please share in the comments section.

I’ve published a number of articles related to imaging and images of which you can find URL links here:

31 Responses to “C# How to: Gradient Based Edge Detection”



  1. 1 C# How to: Image Cartoon Effect | Software by Default Trackback on June 2, 2013 at 4:12 PM
  2. 2 C# How to: Sharpen Edge Detection | Software by Default Trackback on June 7, 2013 at 5:12 AM
  3. 3 C# How to: Calculating Gaussian Kernels | Software by Default Trackback on June 8, 2013 at 10:59 AM
  4. 4 C# How to: Image Blur | Software by Default Trackback on June 9, 2013 at 10:20 PM
  5. 5 C# How to: Image Transform Rotate | Software by Default Trackback on June 16, 2013 at 10:40 AM
  6. 6 C# How to: Image Transform Shear | Software by Default Trackback on June 16, 2013 at 5:45 PM
  7. 7 C# How to: Compass Edge Detection | Software by Default Trackback on June 22, 2013 at 9:35 PM
  8. 8 C# How to: Oil Painting and Cartoon Filter | Software by Default Trackback on June 30, 2013 at 10:48 AM
  9. 9 C# How to: Stained Glass Image Filter | Software by Default Trackback on June 30, 2013 at 10:50 AM
  10. 10 C# How to: Boolean Edge Detection | Software by Default Trackback on June 30, 2013 at 1:56 PM
  11. 11 C# How to: Morphological Edge Detection | Software by Default Trackback on June 30, 2013 at 2:02 PM
  12. 12 C# How to: Image Erosion and Dilation | Software by Default Trackback on June 30, 2013 at 2:10 PM
  13. 13 C# How to: Image Colour Average | Software by Default Trackback on June 30, 2013 at 2:20 PM
  14. 14 C# How to: Image Unsharp Mask | Software by Default Trackback on June 30, 2013 at 2:28 PM
  15. 15 C# How to: Image Median Filter | Software by Default Trackback on June 30, 2013 at 3:16 PM
  16. 16 C# How to: Difference Of Gaussians | Software by Default Trackback on June 30, 2013 at 3:27 PM
  17. 17 C# How to: Image Edge Detection | Software by Default Trackback on June 30, 2013 at 3:33 PM
  18. 18 C# How to: Image Convolution | Software by Default Trackback on June 30, 2013 at 3:55 PM
  19. 19 C# How to: Generate a Web Service from WSDL | Software by Default Trackback on June 30, 2013 at 4:08 PM
  20. 20 C# How to: Decoding/Converting Base64 strings to Bitmap images | Software by Default Trackback on June 30, 2013 at 4:14 PM
  21. 21 C# How to: Bitmap Colour Substitution implementing thresholds | Software by Default Trackback on July 6, 2013 at 4:33 PM
  22. 22 C# How to: Swapping Bitmap ARGB Colour Channels | Software by Default Trackback on July 6, 2013 at 5:02 PM
  23. 23 C# How to: Image filtering by directly manipulating Pixel ARGB values | Software by Default Trackback on July 8, 2013 at 2:58 AM
  24. 24 C# How to: Image ASCII Art | Software by Default Trackback on July 14, 2013 at 7:22 AM
  25. 25 C# How to: Weighted Difference of Gaussians | Software by Default Trackback on July 14, 2013 at 8:11 PM
  26. 26 C# How to: Image Boundary Extraction | Software by Default Trackback on July 21, 2013 at 10:24 AM
  27. 27 C# How to: Image Abstract Colours Filter | Software by Default Trackback on July 28, 2013 at 7:41 PM
  28. 28 C# How to: Fuzzy Blur Filter | Software by Default Trackback on August 9, 2013 at 6:39 AM
  29. 29 C# How to: Image Distortion Blur | Software by Default Trackback on August 9, 2013 at 10:13 PM
  30. 30 C# How to: Standard Deviation Edge Detection | Software by Default Trackback on August 8, 2015 at 8:10 AM
  31. 31 C# How to: Min/Max Edge Detection | Software by Default Trackback on August 9, 2015 at 11:30 AM

Leave a comment




Dewald Esterhuizen

Blog Stats

  • 869,810 hits

Enter your email address to follow and receive notifications of new posts by email.

Join 228 other subscribers

Archives

RSS SoftwareByDefault on MSDN

  • An error has occurred; the feed is probably down. Try again later.