Posts Tagged 'Morphologial Filters'

C# How to: Image Distortion Blur

Article Purpose

This article explores the process of implementing an Image Distortion Blur filter. This image filter is classified as a non-photo realistic image filter, primarily implemented in rendering artistic effects.

Flower: Distortion Factor 15

Flower: Distortion Factor 15

Sample Source Code

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

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Using the Sample Application

The sample source code that accompanies this article includes a based sample application. The concepts explored in this article have all been implemented as part of the sample application. From an end user perspective the following configurable options are available:

  • Load/Save Images – Clicking the Load Image button allows a user to specify a source/input . If desired, output filtered can be saved to the local system by clicking the Save Image button.
  • Distortion Factor – The level or intensity of distortion applied when implementing the filter can be specified when adjusting the Distortion Factor through the user interface. Lower factor values result in less distortion being evident in resulting . Specifying higher factor values result in more intense distortion being applied.

The following image is screenshot of the Image Distortion Blur sample application:

ImageDistortionBlur_SampleApplication

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Image Distortion

In this article and the accompanying sample source code are distorted through slightly adjusting each individual ’s coordinates. The direction and distance by which coordinates are adjusted differ per as a result of being randomly selected. The maximum distance offset applied depends on the user specified Distortion Factor. Once all coordinates have been updated, implementing a provides smoothing and an effect.

Applying an Image Distortion Filter requires implementing the following steps:

  1. Iterate Pixels – Each forming part of the source/input should be iterated.
  2. Calculate new Coordinates – For every being iterated generate two random values representing XY-coordinate offsets to be applied to a ’s current coordinates. Offset values can equate to less than zero in order to represent coordinates above or to the left of the current .
  3. Apply Median Filter – The newly offset will appear somewhat speckled in the resulting . Applying a reduces the speckled appearance whilst retaining a distortion effect.

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Median Filter

Applying a is the final step required when implementing an Image Distortion Blur filter. are often implemented in reducing . The method of image distortion illustrated in this article express similarities when compared to . In order to soften the appearance of we implement a .

A can be applied through implementing the following steps:

  1. Iterate Pixels – Each forming part of the source/input should be iterated.
  2. Inspect Pixel Neighbourhood – Each neighbouring in relation to the currently being iterated should be added to a temporary collection.
  3. Determine Neighbourhood Median – Once all neighbourhood have been added to a temporary collection, sort the collection by value. The element value located at the middle of the collection represents the neighbourhood’s value.

Flower: Distortion Factor 10

Flower: Distortion Factor 10

Flower: Distortion Factor 15

Flower: Distortion Factor 15

Implementing Image Distortion

The sample source code defines the DistortionBlurFilter method, an targeting the class. The following code snippet illustrates the implementation:

public static Bitmap DistortionBlurFilter( 
         this Bitmap sourceBitmap, int distortFactor) 
{
    byte[] pixelBuffer = sourceBitmap.GetByteArray(); 
    byte[] resultBuffer = sourceBitmap.GetByteArray(); 

int imageStride = sourceBitmap.Width * 4; int calcOffset = 0, filterY = 0, filterX = 0; int factorMax = (distortFactor + 1) * 2; Random rand = new Random();
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { filterY = distortFactor - rand.Next(0, factorMax); filterX = distortFactor - rand.Next(0, factorMax);
if (filterX * 4 + (k % imageStride) < imageStride && filterX * 4 + (k % imageStride) > 0) { calcOffset = k + filterY * imageStride + 4 * filterX;
if (calcOffset >= 0 && calcOffset + 4 < resultBuffer.Length) { resultBuffer[calcOffset] = pixelBuffer[k]; resultBuffer[calcOffset + 1] = pixelBuffer[k + 1]; resultBuffer[calcOffset + 2] = pixelBuffer[k + 2]; } } }
return resultBuffer.GetImage(sourceBitmap.Width, sourceBitmap.Height).MedianFilter(3); }

Flower: Distortion Factor 15

Flower: Distortion Factor 15

Implementing a Median Filter

The MedianFilter targets the class. The implementation as follows:

public static Bitmap MedianFilter(this Bitmap sourceBitmap, 
                                  int matrixSize) 
{ 
    byte[] pixelBuffer = sourceBitmap.GetByteArray(); 
    byte[] resultBuffer = new byte[pixelBuffer.Length]; 
    byte[] middlePixel; 

int imageStride = sourceBitmap.Width * 4; int filterOffset = (matrixSize - 1) / 2; int calcOffset = 0, filterY = 0, filterX = 0; List<int> neighbourPixels = new List<int>();
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { filterY = -filterOffset; filterX = -filterOffset; neighbourPixels.Clear();
while (filterY <= filterOffset) { calcOffset = k + (filterX * 4) + (filterY * imageStride);
if (calcOffset > 0 && calcOffset + 4 < pixelBuffer.Length) { neighbourPixels.Add(BitConverter.ToInt32( pixelBuffer, calcOffset)); }
filterX++;
if (filterX > filterOffset) { filterX = -filterOffset; filterY++; } }
neighbourPixels.Sort(); middlePixel = BitConverter.GetBytes( neighbourPixels[filterOffset]);
resultBuffer[k] = middlePixel[0]; resultBuffer[k + 1] = middlePixel[1]; resultBuffer[k + 2] = middlePixel[2]; resultBuffer[k + 3] = middlePixel[3]; }
return resultBuffer.GetImage(sourceBitmap.Width, sourceBitmap.Height); }

Flower: Distortion Factor 25

Flower: Distortion Factor 25

Sample Images

This article features a number of sample images. All featured images have been licensed allowing for reproduction. The following images feature as sample images:

674px-Lil_chalcedonicum_01EB_Griechenland_Hrisomiglia_17_07_01

683px-Lil_carniolicum_subsp_ponticum_01EB_Tuerkei_Ikizdere_02_07_93

1022px-LiliumSargentiae

1024px-Lilium_longiflorum_(Easter_Lily)

1280px-LiliumBulbiferumCroceumBologna

LiliumSuperbum1

Orange_Lilium_-_Relic38_-_Ontario_Canada

White_and_yellow_flower

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:

C# How to: Fuzzy Blur Filter

Article Purpose

This article serves to illustrate the concepts involved in implementing a Fuzzy Blur Filter. This filter results in rendering  non-photo realistic images which express a certain artistic effect.

Frog: Filter Size 19×19

Frog: Filter Size 19x19

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

The sample source code accompanying this article includes a based test application. The concepts explored throughout this article can be replicated/tested using the sample application.

When executing the sample application the user interface exposes a number of configurable options:

  • Loading and Saving Images – Users are able to load source/input from the local system by clicking the Load Image button. Clicking the Save Image button allow users to save filter result .
  • Filter Size – The specified filter size affects the filter intensity. Smaller filter sizes result in less blurry being rendered, whereas larger filter sizes result in more blurry being rendered.
  • Edge Factors – The contrast of fuzzy expressed in resulting depend on the specified edge factor values. Values less than one result in detected being darkened and values greater than one result in detected image edges being lightened.

The following image is a screenshot of the Fuzzy Blur Filter sample application in action:

Fuzzy Blur Filter Sample Application

Frog: Filter Size 9×9

Frog: Filter Size 9x9

Fuzzy Blur Overview

The Fuzzy Blur Filter relies on the interference of when performing in order to create a fuzzy effect. In addition results from performing a .

The steps involved in performing a Fuzzy Blur Filter can be described as follows:

  1. Edge Detection and Enhancement – Using the first edge factor specified enhance by performing Boolean Edge detection. Being sensitive to , a fair amount of detected will actually be in addition to actual .
  2. Mean Filter Blur – Using the edge enhanced created in the previous step perform a blur. The enhanced edges will be blurred since a does not have edge preservation properties. The size of the implemented depends on a user specified value.
  3. Edge Detection and Enhancement –  Using the blurred created in the previous step once again perform Boolean Edge detection, enhancing detected edges according to the second edge factor specified.

Frog: Filter Size 9×9

Frog: Filter Size 9x9

Mean Filter

A Blur, also known as a , can be performed through . The size of the / implemented when preforming will be determined through user input.

Every / element should be set to one. The resulting value should be multiplied by a factor value equating to one divided by the / size. As an example, a / size of 3×3 can be expressed as follows:

Mean Kernel

An alternative expression can also be:

Mean Kernel

Frog: Filter Size 9×9

Frog: Filter Size 9x9

Boolean Edge Detection without a local threshold

When performing Boolean Edge Detection a local threshold should be implemented in order to exclude . In this article we rely on the interference of in order to render a fuzzy effect. By not implementing a local threshold when performing Boolean Edge detection the sample source code ensures sufficient interference from .

The steps involved in performing Boolean Edge Detection without a local threshold can be described as follows:

  1. Calculate Neighbourhood Mean – Iterate each forming part of the source/input . Using a 3×3 size calculate the mean value of the neighbourhood surrounding the currently being iterated.
  2. Create Mean comparison Matrix – Once again using a 3×3 size compare each neighbourhood to the newly calculated mean value. Create a temporary 3×3 size , each element’s value should be the result of mean comparison. Should the value expressed by a neighbourhood exceed the mean value the corresponding temporary element should be set to one. When the calculated mean value exceeds the value of a neighbourhood the corresponding temporary  element should be set to zero.
  3. Compare Edge Masks – Using sixteen predefined edge masks compare the temporary created in the previous step to each edge mask. If the temporary matches one of the predefined edge masks multiply the specified factor to the currently being iterated.

Note: A detailed article on Boolean Edge detection implementing a local threshold can be found here:

Frog: Filter Size 9×9

Frog: Filter Size 9x9

The sixteen predefined edge masks each represent an in a different direction. The predefined edge masks can be expressed as:

Boolean Edge Masks

Frog: Filter Size 13×13

Frog: Filter Size 13x13

Implementing a Mean Filter

The sample source code defines the MeanFilter method, an targeting the class. The definition listed as follows:

private static Bitmap MeanFilter(this Bitmap sourceBitmap, 
                                 int meanSize)
{
    byte[] pixelBuffer = sourceBitmap.GetByteArray(); 
    byte[] resultBuffer = new byte[pixelBuffer.Length];

double blue = 0.0, green = 0.0, red = 0.0; double factor = 1.0 / (meanSize * meanSize);
int imageStride = sourceBitmap.Width * 4; int filterOffset = meanSize / 2; int calcOffset = 0, filterY = 0, filterX = 0;
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { blue = 0; green = 0; red = 0; filterY = -filterOffset; filterX = -filterOffset;
while (filterY <= filterOffset) { calcOffset = k + (filterX * 4) + (filterY * imageStride);
calcOffset = (calcOffset < 0 ? 0 : (calcOffset >= pixelBuffer.Length - 2 ? pixelBuffer.Length - 3 : calcOffset));
blue += pixelBuffer[calcOffset]; green += pixelBuffer[calcOffset + 1]; red += pixelBuffer[calcOffset + 2];
filterX++;
if (filterX > filterOffset) { filterX = -filterOffset; filterY++; } }
resultBuffer[k] = ClipByte(factor * blue); resultBuffer[k + 1] = ClipByte(factor * green); resultBuffer[k + 2] = ClipByte(factor * red); resultBuffer[k + 3] = 255; }
return resultBuffer.GetImage(sourceBitmap.Width, sourceBitmap.Height); }

Frog: Filter Size 19×19

Frog: Filter Size 19x19

Implementing Boolean Edge Detection

Boolean Edge detection is performed in the sample source code through the implementation of the BooleanEdgeDetectionFilter method. This method has been defined as an targeting the class.

The following code snippet provides the definition of the BooleanEdgeDetectionFilter :

public static Bitmap BooleanEdgeDetectionFilter( 
       this Bitmap sourceBitmap, float edgeFactor) 
{
    byte[] pixelBuffer = sourceBitmap.GetByteArray(); 
    byte[] resultBuffer = new byte[pixelBuffer.Length]; 
    Buffer.BlockCopy(pixelBuffer, 0, resultBuffer, 
                     0, pixelBuffer.Length); 

List<string> edgeMasks = GetBooleanEdgeMasks(); int imageStride = sourceBitmap.Width * 4; int matrixMean = 0, pixelTotal = 0; int filterY = 0, filterX = 0, calcOffset = 0; string matrixPatern = String.Empty;
for (int k = 0; k + 4 < pixelBuffer.Length; k += 4) { matrixPatern = String.Empty; matrixMean = 0; pixelTotal = 0; filterY = -1; filterX = -1;
while (filterY < 2) { calcOffset = k + (filterX * 4) + (filterY * imageStride);
calcOffset = (calcOffset < 0 ? 0 : (calcOffset >= pixelBuffer.Length - 2 ? pixelBuffer.Length - 3 : calcOffset)); matrixMean += pixelBuffer[calcOffset]; matrixMean += pixelBuffer[calcOffset + 1]; matrixMean += pixelBuffer[calcOffset + 2];
filterX += 1;
if (filterX > 1) { filterX = -1; filterY += 1; } }
matrixMean = matrixMean / 9; filterY = -1; filterX = -1;
while (filterY < 2) { calcOffset = k + (filterX * 4) + (filterY * imageStride);
calcOffset = (calcOffset < 0 ? 0 : (calcOffset >= pixelBuffer.Length - 2 ? pixelBuffer.Length - 3 : calcOffset));
pixelTotal = pixelBuffer[calcOffset]; pixelTotal += pixelBuffer[calcOffset + 1]; pixelTotal += pixelBuffer[calcOffset + 2]; matrixPatern += (pixelTotal > matrixMean ? "1" : "0"); filterX += 1;
if (filterX > 1) { filterX = -1; filterY += 1; } }
if (edgeMasks.Contains(matrixPatern)) { resultBuffer[k] = ClipByte(resultBuffer[k] * edgeFactor);
resultBuffer[k + 1] = ClipByte(resultBuffer[k + 1] * edgeFactor);
resultBuffer[k + 2] = ClipByte(resultBuffer[k + 2] * edgeFactor); } }
return resultBuffer.GetImage(sourceBitmap.Width, sourceBitmap.Height); }

Frog: Filter Size 13×13

Frog: Filter Size 13x13

The predefined edge masks implemented in mean comparison have been wrapped by the GetBooleanEdgeMasks method. The definition as follows:

public static List<string> GetBooleanEdgeMasks() 
{
    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("110110100");
return edgeMasks; }

Frog: Filter Size 19×19

Frog: Filter Size 19x19

Implementing a Fuzzy Blur Filter

The FuzzyEdgeBlurFilter method serves as the implementation of a Fuzzy Blur Filter. As discussed earlier a Fuzzy Blur Filter involves enhancing through Boolean Edge detection, performing a blur and then once again performing Boolean Edge detection. This method has been defined as an extension method targeting the class.

The following code snippet provides the definition of the FuzzyEdgeBlurFilter method:

public static Bitmap FuzzyEdgeBlurFilter(this Bitmap sourceBitmap,  
                                         int filterSize,  
                                         float edgeFactor1,  
                                         float edgeFactor2) 
{
    return  
    sourceBitmap.BooleanEdgeDetectionFilter(edgeFactor1). 
    MeanFilter(filterSize).BooleanEdgeDetectionFilter(edgeFactor2); 
}

Frog: Filter Size 3×3

Frog: Filter Size 3x3

Sample Images

This article features a number of sample images. All featured images have been licensed allowing for reproduction. The following images feature as sample images:

Litoria_tyleri

Schrecklicherpfeilgiftfrosch-01

Dendropsophus_microcephalus_-_calling_male_(Cope,_1886)

Atelopus_zeteki1

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:

C# How to: Image Boundary Extraction

Article Purpose

This article explores various concepts, which feature in combination when implementing Image Boundary Extraction. Concepts covered within this article include: Morphological and , Addition and Subtraction, Boundary Sharpening, Boundary Tracing and Boundary Extraction.

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Greed, Blue

Sample Source Code

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

Using the Sample Application

This article’s accompanying sample source code includes the definition of a sample application. The sample application serves as an implementation of the concepts discussed in this article. In using the sample application concepts can be easily tested and replicated.

The sample application has been defined as a . The user interface enables the user to configure several options which influence the output produced from filtering processes. The following section describes the options available to a user when executing the sample application:

  • Loading and Saving files – Users can specify source/input through clicking the Load Image button. If desired, resulting filtered can be saved to the local system when clicking the Save Image button.
  • Filter Type – The types of filters implemented represent variations on Image Boundary Extraction. The supported filter types are: Conventional Boundary extraction, Boundary Sharpening and Boundary Tracing.
  • Filter Size – Filter intensity/strength will mostly be reliant on the filter size implemented. A Filter size represents the number of neighbouring examined when applying filters.
  • Colours Applied – The sample source code and sample application provides functionality allowing a filter to only effect user specified colour components. Colour components are represented in the form of an RGB colour scheme. The inclusion or exclusion of the colour components Red, Green and Blue will be determined through user configuration.
  • Structuring Element – As mentioned, the Filter Size option determines the size of neighbourhood examined. The ’s setup determine the neighbouring   within the neighbourhood size bounds that should be used as input when calculating filter results.

The following is a screenshot of the Image Boundary Extraction sample application in action:

Image Boundary Extaction Sample  Application

Parrot: Boundary Extraction, 3×3, Green

Parrot: Boundary Extraction, 3x3, Green

Morphological Boundary Extraction

Image Boundary Extraction can be considered a method of . In contrast to more commonly implemented   methods, Image Boundary Extraction originates from Morphological Image Filters.

When drawing a comparison, Image Boundary Extraction and express strong similarities. results from the difference in and . Considered from a different point of view, creating one expressing thicker edges and another expressing thinner edges provides the means to calculate the difference in edges.

Image Boundary Extraction implements the same concept as . The base concept can be regarded as calculating the difference between two which rendered the same , but expressing a difference in . Image Boundary Extraction relies on calculating the difference between either and the source or and the source . The difference between and in most cases result in more of difference than the difference between and the source or and the source . The result of Image Boundary Extraction representing less of a difference than can be observed in Image Boundary Extraction being expressed in finer/smaller width lines.

is another method of which functions along the same basis. Edges are determined by calculating the difference between two , each having been filtered from the same source , using a of differing intensity levels.

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Green, Blue

Boundary Sharpening

The concept of Boundary Sharpening refers to enhancing or sharpening the boundaries or edges expressed in a source/input . Boundaries can be easily determined or extracted as discussed earlier when exploring Boundary Extraction.

The steps involved in performing Boundary Sharpening can be described as follows:

  1. Extract Boundaries – Determine boundaries by performing and calculating the difference between the dilated and the source .
  2. Match Source Edges and Extracted Boundaries – The boundaries extracted in the previous step represent the difference between and the original source . Ensure that extracted boundaries match the source through performing on a copy of the source/input .
  3. Emphasise Extracted boundaries in source image – Perform addition using the extracted boundaries and dilated copy of the source .

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Green, Blue

Boundary Tracing

Boundary Tracing refers to applying filters which result in /boundaries appearing darker or more pronounced. This type of filter also relies on Boundary Extraction.

Boundary Tracing can be implemented in two steps, described as follows:

  1. Extract Boundaries – Determine boundaries by performing and calculating the difference between the dilated and the source .
  2. Emphasise Extracted boundaries in source image – Subtract the extracted boundaries from the original source .

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Green, Blue

Implementing Morphological Erosion and Dilation

The accompanying sample source code defines the MorphologyOperation method,  defined as an targeting the class. In terms of parameters this method expects a two dimensional array representing a . The other required  parameter represents an value indicating which Morphological Operation to perform, either or .

The following code snippet provides the definition in full:

private static Bitmap MorphologyOperation(this Bitmap sourceBitmap,
                                          bool[,] se,
                                          MorphologyOperationType morphType,
                                          bool applyBlue = true,
                                          bool applyGreen = true,
                                          bool applyRed = true)
{ 
    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 filterOffset = (se.GetLength(0) - 1) / 2; int calcOffset = 0, byteOffset = 0; byte blueErode = 0, greenErode = 0, redErode = 0; byte blueDilate = 0, greenDilate = 0, redDilate = 0;
for (int offsetY = 0; offsetY < sourceBitmap.Height - filterOffset; offsetY++) { for (int offsetX = 0; offsetX < sourceBitmap.Width - filterOffset; offsetX++) { byteOffset = offsetY * sourceData.Stride + offsetX * 4;
blueErode = 255; greenErode = 255; redErode = 255; blueDilate = 0; greenDilate = 0; redDilate = 0;
for (int filterY = -filterOffset; filterY <= filterOffset; filterY++) { for (int filterX = -filterOffset; filterX <= filterOffset; filterX++) { if (se[filterY + filterOffset, filterX + filterOffset] == true) { calcOffset = byteOffset + (filterX * 4) + (filterY * sourceData.Stride);
calcOffset = (calcOffset < 0 ? 0 : (calcOffset >= pixelBuffer.Length + 2 ? pixelBuffer.Length - 3 : calcOffset));
blueDilate = (pixelBuffer[calcOffset] > blueDilate ? pixelBuffer[calcOffset] : blueDilate);
greenDilate = (pixelBuffer[calcOffset + 1] > greenDilate ? pixelBuffer[calcOffset + 1] : greenDilate);
redDilate = (pixelBuffer[calcOffset + 2] > redDilate ? pixelBuffer[calcOffset + 2] : redDilate);
blueErode = (pixelBuffer[calcOffset] < blueErode ? pixelBuffer[calcOffset] : blueErode);
greenErode = (pixelBuffer[calcOffset + 1] < greenErode ? pixelBuffer[calcOffset + 1] : greenErode);
redErode = (pixelBuffer[calcOffset + 2] < redErode ? pixelBuffer[calcOffset + 2] : redErode); } } }
blueErode = (applyBlue ? blueErode : pixelBuffer[byteOffset]); blueDilate = (applyBlue ? blueDilate : pixelBuffer[byteOffset]);
greenErode = (applyGreen ? greenErode : pixelBuffer[byteOffset + 1]); greenDilate = (applyGreen ? greenDilate : pixelBuffer[byteOffset + 1]);
redErode = (applyRed ? redErode : pixelBuffer[byteOffset + 2]); redDilate = (applyRed ? redDilate : pixelBuffer[byteOffset + 2]);
if (morphType == MorphologyOperationType.Erosion) { resultBuffer[byteOffset] = blueErode; resultBuffer[byteOffset + 1] = greenErode; resultBuffer[byteOffset + 2] = redErode; } else if (morphType == MorphologyOperationType.Dilation) { resultBuffer[byteOffset] = blueDilate; resultBuffer[byteOffset + 1] = greenDilate; resultBuffer[byteOffset + 2] = redDilate; }
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; }

Parrot: Boundary Extraction, 3×3, Red, Green

Parrot: Boundary Extraction, 3x3, Red, Green

Implementing Image Addition

The sample source code encapsulates the process of combining two separate through means of addition. The AddImage method serves as a single declaration of addition functionality. This method has been defined as an targeting the class. Boundary Sharpen filtering implements addition.

The following code snippet provides the definition of the AddImage :

private static Bitmap AddImage(this Bitmapsource Bitmap, 
                               Bitmap addBitmap)
{
    BitmapData sourceData =
               sourceBitmap.LockBits(new Rectangle (0, 0,
               sourceBitmap.Width, sourceBitmap.Height),
               ImageLockMode.ReadOnly,
               PixelFormat.Format32bppArgb);

byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, resultBuffer, 0, resultBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
BitmapData addData = addBitmap.LockBits(new Rectangle(0, 0, addBitmap.Width, addBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] addBuffer = new byte[addData.Stride * addData.Height];
Marshal.Copy(addData.Scan0, addBuffer, 0, addBuffer.Length);
addBitmap.UnlockBits(addData);
for (int k = 0; k + 4 < resultBuffer.Length && k + 4 < addBuffer.Length; k += 4) { resultBuffer[k] = AddColors(resultBuffer[k], addBuffer[k]); resultBuffer[k + 1] = AddColors(resultBuffer[k + 1], addBuffer[k + 1]); resultBuffer[k + 2] = AddColors(resultBuffer[k + 2], addBuffer[k + 2]); resultBuffer[k + 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; }
private static byte AddColors(byte color1, byte color2) 
{
    int result = color1 + color2; 

return (byte)(result < 0 ? 0 : (result > 255 ? 255 : result)); }

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Green, Blue

Implementing Image Subtraction

In a similar fashion regarding the AddImage method the sample code defines the SubractImage method.  By definition this method serves as an targeting the class. Image subtraction has been implemented in Boundary Extraction and Boundary Tracing.

The definition of the SubtractImage method listed as follows:

private static Bitmap SubtractImage(this Bitmap sourceBitmap,  
                                         Bitmap subtractBitmap) 
{
    BitmapData sourceData = 
               sourceBitmap.LockBits(new Rectangle(0, 0, 
               sourceBitmap.Width, sourceBitmap.Height), 
               ImageLockMode.ReadOnly, 
               PixelFormat.Format32bppArgb); 

byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];
Marshal.Copy(sourceData.Scan0, resultBuffer, 0, resultBuffer.Length);
sourceBitmap.UnlockBits(sourceData);
BitmapData subtractData = subtractBitmap.LockBits(new Rectangle(0, 0, subtractBitmap.Width, subtractBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
byte[] subtractBuffer = new byte[subtractData.Stride * subtractData.Height];
Marshal.Copy(subtractData.Scan0, subtractBuffer, 0, subtractBuffer.Length);
subtractBitmap.UnlockBits(subtractData);
for (int k = 0; k + 4 < resultBuffer.Length && k + 4 < subtractBuffer.Length; k += 4) { resultBuffer[k] = SubtractColors(resultBuffer[k], subtractBuffer[k]);
resultBuffer[k + 1] = SubtractColors(resultBuffer[k + 1], subtractBuffer[k + 1]);
resultBuffer[k + 2] = SubtractColors(resultBuffer[k + 2], subtractBuffer[k + 2]);
resultBuffer[k + 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; }
private static byte SubtractColors(byte color1, byte color2) 
{
    int result = (int)color1 - (int)color2; 

return (byte)(result < 0 ? 0 : result); }

 Parrot: Boundary Extraction, 3×3, Green

Parrot: Boundary Extraction, 3x3, Green

Implementing Image Boundary Extraction

In the sample source code processing Image Boundary Extraction can be achieved when invoking the BoundaryExtraction method. Defined as an , the BoundaryExtraction method targets the class.

As discussed earlier, this method performs Boundary Extraction through subtracting the source from a dilated copy of the source .

The following code snippet details the definition of the BoundaryExtraction method:

private static Bitmap
BoundaryExtraction(this Bitmap sourceBitmap, 
                   bool[,] se, bool applyBlue = true, 
                   bool applyGreen = true, bool applyRed = true) 
{
    Bitmap resultBitmap = 
           sourceBitmap.MorphologyOperation(se,  
           MorphologyOperationType.Dilation, applyBlue,  
                                  applyGreen, applyRed); 

resultBitmap = resultBitmap.SubtractImage(sourceBitmap);
return resultBitmap; }

Parrot: Boundary Extraction, 3×3, Red, Blue

Parrot: Boundary Extraction, 3x3, Red, Blue

Implementing Image Boundary Sharpening

Boundary Sharpening in the sample source code has been implemented through the definition of the BoundarySharpen method. The BoundarySharpen targets the class. The following code snippet provides the definition:

private static Bitmap 
BoundarySharpen(this Bitmap sourceBitmap, 
                bool[,] se, bool applyBlue = true, 
                bool applyGreen = true, bool applyRed = true) 
{
    Bitmap resultBitmap = 
           sourceBitmap.BoundaryExtraction(se, applyBlue, 
                                           applyGreen, applyRed); 

resultBitmap = sourceBitmap.MorphologyOperation(se, MorphologyOperationType.Dilation, applyBlue, applyGreen, applyRed).AddImage(resultBitmap);
return resultBitmap; }

Parrot: Boundary Extraction, 3×3, Green

Parrot: Boundary Extraction, 3x3, Green

Implementing Image Boundary Tracing

Boundary Tracing has been defined through the BoundaryTrace , which targets the class. Similar to the BoundarySharpen method this method performs Boundary Extraction, the result of which serves to be subtracted from the original source . Subtracting boundaries/edges result in those boundaries/edges being darkened, or traced. The definition of the BoundaryTracing detailed as follows:

private static Bitmap
BoundaryTrace(this Bitmap sourceBitmap, 
              bool[,] se, bool applyBlue = true, 
              bool applyGreen = true, bool applyRed = true) 
{
    Bitmap resultBitmap =
    sourceBitmap.BoundaryExtraction(se, applyBlue,  
                                    applyGreen, applyRed); 

resultBitmap = sourceBitmap.SubtractImage(resultBitmap);
return resultBitmap; }

Parrot: Boundary Extraction, 3×3, Green, Blue

Parrot: Boundary Extraction, 3x3, Green, Blue

Implementing a Wrapper Method

The BoundaryExtractionFilter method is the only method defined as publicly accessible. Following convention, this method’s definition signals the method as an targeting the class. This method has the intention of acting as a wrapper method, a single method capable of performing Boundary Extraction, Boundary Sharpening and Boundary Tracing, depending on method parameters.

The definition of the BoundaryExtractionFilter method detailed by the following code snippet:

public static Bitmap
BoundaryExtractionFilter(this Bitmap sourceBitmap, 
                         bool[,] se, BoundaryExtractionFilterType  
                         filterType, bool applyBlue = true, 
                         bool applyGreen = true, bool applyRed = true) 
{
    Bitmap resultBitmap = null; 

if (filterType == BoundaryExtractionFilterType.BoundaryExtraction) { resultBitmap = sourceBitmap.BoundaryExtraction(se, applyBlue, applyGreen, applyRed); } else if (filterType == BoundaryExtractionFilterType.BoundarySharpen) { resultBitmap = sourceBitmap.BoundarySharpen(se, applyBlue, applyGreen, applyRed); } else if (filterType == BoundaryExtractionFilterType.BoundaryTrace) { resultBitmap = sourceBitmap.BoundaryTrace(se, applyBlue, applyGreen, applyRed); }
return resultBitmap; }

Parrot: Boundary Extraction, 3×3, Red, Green, Blue

Parrot: Boundary Extraction, 3x3, Red, Green, Blue

Sample Images

This article features a number of sample images. All featured images have been licensed allowing for reproduction. The following images feature as sample images:

1280px-Ara_macao_-Diergaarde_Blijdorp_-flying-8a

Ara_macao_-flying_away-8a

Ara_ararauna_Luc_Viatour

1280px-Macaws_at_Seaport_Village_-USA-8a

Ara_macao_-on_a_small_bicycle-8

Psarisomus_dalhousiae_-_Kaeng_Krachan

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:


Dewald Esterhuizen

Blog Stats

  • 869,941 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.