Quantcast
Channel: Morphology Filters – Software by Default
Viewing all articles
Browse latest Browse all 14

C# How to: Boolean Edge Detection

$
0
0

Article purpose

The purpose of this article is to detail Boolean Function Based Edge Detection. The filtering implemented in article occurs on a per pixel basis. The implementation relies on linear algebra. No GDI+ or traditional drawing methods are required.

Sample Source Code

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

Using the Sample Application

Implemented as part of this article’s sample source code is a Sample Application. The concepts detailed in this article have all been implemented and tested using the associated Sample Application.

The first task required in using the Sample Application comes in the form of having to specify a source/input . Select files from the local system by clicking the Load Image button.

On the right-hand side of the Sample Application’s user interface the user will be presented with a set of controls which relate to various filter options. Users are able to specify implementation methods when adjusting filter options.

Filter type values are: None, Edge Detect and Sharpen.  Selecting a filter type of None results in no filtering being implemented, the original input/source will be displayed reflecting no change. When users select the Edge Detect filter type the resulting output reflects a black and white image of which only the detected edges are visible. The Sharpen filter type implements Boolean Edge Detection producing a sharpened by means of highlighting detected edges within the original input/source .

The Trackbar labelled Threshold is intended to allow users the option of reducing expressed as detected edges in the resulting . The level of present differs depending on the input/source specified, hence the option of implementing a threshold.

The three remaining TrackBar controls are labelled Red, Green and Blue. The Colour Factor filter options allows the user to specify the extend to which detected edges are expressed when sharpening an . When all three factor values are set to the same value edges appear white if the factor value exceeds zero. Factor values set to zero results in detected edges appearing as darker/black edge lines. Factor values can be set per colour value, which will have the effect of creating a coloured outline being visible in the result . The colour of the outlining effect can be controlled by adjusting individual colour factor values.

After having implemented image filtering the user has the option of saving the result to the local file system by clicking the Save Image button. The image shown below is screenshot of the Boolean Edge Detection sample application in action:

Boolean Edge Detection Sample Application

The Local Threshold and Boolean Function Based Edge Detection

Boolean Edge Detection is considered a a subset of . This method of employs both a local and global threshold. Implementation of the Boolean Edge Detection algorithm can be achieved by completing the following steps:

  1. Initiate a process of iterating each pixel that forms part of the source/input . Calculate a local threshold value based on a 3×3 /window. The should be positioned in a fashion where the pixel currently being iterated is located in the middle of the . Calculate a mean value using as input the 9 values covered by the . Create a new blank set to 3×3 dimensions. Compare each pixel in the source image to the calculated mean value. If a pixel’s value exceeds that of the mean value set the corresponding location on the blank to one. If a pixel’s value does not exceed that of the mean value set the corresponding location on the blank to zero.
  2. In the next step compare the newly created to the set of 16 edge masks. If the new is represented in the edge masks the middle pixel being iterated should be set to indicate an edge.
  3. The first two steps have to be repeated for each pixel contained in the source , in other words each pixel should be iterated. Edges should now be detected as you progress through image pixels, although false edges will also be present as a result of .
  4. False edges that were detected can be removed when implementing a global threshold. Firstly calculate the variance of each 3×3 . If the pixel currently being iterated was detected as part of an edge in step 2 and the variance calculated exceeds the global threshold the pixel can be considered as part of an edge. If the variance calculated equates to less than the global threshold a pixel does not form part of an edge even if the calculated matches one of the 16 edge masks.

The following image illustrates the 16 edge masks:

Edge Masks

Implementing Boolean Edge Detection

The sample source code implements the BooleanEdgeDetectionFilter targeting the class. This method implements the Boolean Edge Detection theoretical steps discussed in the previous section.

In order to determine if a newly calculated , as described in step 1, matches any of the 16 pre-defined edge masks the BooleanEdgeDetectionFilter implements comparison. The reasoning behind string based edge mask comparison boils down to efficiency, both in terms of reducing code complexity and improving performance. The method defines a generic List of type string and then proceeds to add 16 , each representing an edge mask. Edge mask strings express an edge mask in terms of a row and column format. The following code snippet lists the 16 edge masks strings being defined:

List<string> edgeMasks = new List<string>();

edgeMasks.Add("011011011"); edgeMasks.Add("000111111"); edgeMasks.Add("110110110"); edgeMasks.Add("111111000"); edgeMasks.Add("011011001"); edgeMasks.Add("100110110"); edgeMasks.Add("111011000"); edgeMasks.Add("111110000"); edgeMasks.Add("111011001"); edgeMasks.Add("100110111"); edgeMasks.Add("001011111"); edgeMasks.Add("111110100"); edgeMasks.Add("000011111"); edgeMasks.Add("000110111"); edgeMasks.Add("001011011"); edgeMasks.Add("001011011"); edgeMasks.Add("110110100");

The following code snippet list the complete implementation of the BooleanEdgeDetectionFilter :

public static Bitmap BooleanEdgeDetectionFilter(
                                this Bitmap sourceBitmap,
                                BooleanFilterType filterType,
                                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);
List<string> edgeMasks = new List<string>();
edgeMasks.Add("011011011"); edgeMasks.Add("000111111"); edgeMasks.Add("110110110"); edgeMasks.Add("111111000"); edgeMasks.Add("011011001"); edgeMasks.Add("100110110"); edgeMasks.Add("111011000"); edgeMasks.Add("111110000"); edgeMasks.Add("111011001"); edgeMasks.Add("100110111"); edgeMasks.Add("001011111"); edgeMasks.Add("111110100"); edgeMasks.Add("000011111"); edgeMasks.Add("000110111"); edgeMasks.Add("001011011"); edgeMasks.Add("001011011"); edgeMasks.Add("110110100");
int filterOffset = 1; int calcOffset = 0;
int byteOffset = 0; int matrixMean = 0; int matrixTotal = 0; double matrixVariance = 0;
double blueValue = 0; double greenValue = 0; double redValue = 0;
string matrixPatern = String.Empty;
for (int offsetY = filterOffset; offsetY < sourceBitmap.Height - filterOffset; offsetY++) { for (int offsetX = filterOffset; offsetX < sourceBitmap.Width - filterOffset; offsetX++) { byteOffset = offsetY * sourceData.Stride + offsetX * 4;
matrixMean = 0; matrixTotal = 0; matrixVariance = 0;
matrixPatern = String.Empty;
//Step 1: Calculate local matrix for (int filterY = -filterOffset; filterY <= filterOffset; filterY++) { for (int filterX = -filterOffset; filterX <= filterOffset; filterX++) { calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);
matrixMean += pixelBuffer[calcOffset]; matrixMean += pixelBuffer[calcOffset + 1]; matrixMean += pixelBuffer[calcOffset + 2]; } }
matrixMean = matrixMean / 9;
//Step 4: Calculate Variance for (int filterY = -filterOffset; filterY <= filterOffset; filterY++) { for (int filterX = -filterOffset; filterX <= filterOffset; filterX++) { calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);
matrixTotal = pixelBuffer[calcOffset]; matrixTotal += pixelBuffer[calcOffset+1]; matrixTotal += pixelBuffer[calcOffset+2];
matrixPatern += (matrixTotal > matrixMean ? "1" : "0" );
matrixVariance += Math.Pow(matrixMean - (pixelBuffer[calcOffset] + pixelBuffer[calcOffset + 1] + pixelBuffer[calcOffset + 2]), 2); } }
matrixVariance = matrixVariance / 9;
if (filterType == BooleanFilterType.Sharpen) { blueValue = pixelBuffer[byteOffset]; greenValue = pixelBuffer[byteOffset + 1]; redValue = pixelBuffer[byteOffset + 2];
//Step 4: Exlclude noise using global // threshold if (matrixVariance > threshold) { //Step 2: Compare newly calculated // matrix and image masks if (edgeMasks.Contains(matrixPatern)) { blueValue = (blueValue * blueFactor); greenValue = (greenValue * greenFactor); redValue = (redValue * redFactor);
blueValue = (blueValue > 255 ? 255 : (blueValue < 0 ? 0 : blueValue));
greenValue = (greenValue > 255 ? 255 : (greenValue < 0 ? 0 : greenValue));
redValue = (redValue > 255 ? 255 : (redValue < 0 ? 0 : redValue)); } } } //Step 4: Exlclude noise using global // threshold //Step 2: Compare newly calculated // matrix and image masks else if (matrixVariance > threshold && edgeMasks.Contains(matrixPatern)) { blueValue = 255; greenValue = 255; redValue = 255; } else { blueValue = 0; greenValue = 0; redValue = 0; }
resultBuffer[byteOffset] = (byte)blueValue; resultBuffer[byteOffset + 1] = (byte)greenValue; resultBuffer[byteOffset + 2] = (byte)redValue; 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; }

Sample Images

This article features a photograph of The Eiffel Tower used in generating sample . The original image has been licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from Wikipedia: Original Image.

The Original Image

Tour_Eiffel_Wikimedia_Commons

Edge Detection, Threshold 50

Boolean Edge Detection Threshold 50

Sharpen, Threshold 50, Blue

Boolean Edge Detection Threshold 50 Sharpen Blue

Sharpen, Threshold 50, Green

Boolean Edge Detection Threshold 50 Sharpen Green

Sharpen, Threshold 50, Green and Blue

Boolean Edge Detection Threshold 50 Sharpen Green Blue

Sharpen, Threshold 50, Red

Boolean Edge Detection Threshold 50 Sharpen Red

Sharpen, Threshold 50, Red and Blue

Boolean Edge Detection Threshold 50 Sharpen Red Blue

Sharpen, Threshold 50, Red and Green

Boolean Edge Detection Threshold 50 Sharpen Red Green

Sharpen, Threshold 50, White – Red, Green and Blue

Boolean Edge Detection Threshold 50 Sharpen 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:


Filed under: Augmented Reality, C#, Code Samples, Edge Detection, Extension Methods, Graphic Filters, Graphics, How to, Image Filters, Learn Everyday, Microsoft, Morphology Filters, New Version, Opensource, Update Tagged: Augmented Reality, Binary Image, Bitmap ARGB, Bitmap Filters, Bitmap.LockBits, BitmapData, Boolean Edge Detection, C#, Change detection, Code Sample, Computer vision, Converting Images, Convolution filters, Convolution Kernel, Convolution matrix, Edge Masks, Feature extraction, Graphic Filters, Image, Image Edge Detection, Image Morphology, Image processing, Image Transform, Line Detection, Machine vision, Matrix, Pixel Filters

Viewing all articles
Browse latest Browse all 14

Trending Articles