Winfroms Draw Image With Point Filtring
Article purpose
This article is based around creating basic Image filters. The different types of filters discussed are: Grayscale, Transparency, Image Negative and Sepia tone. All filters are implemented as extension methods targeting the Image class, as well as the Bitmap class as the result of inheritance and upcasting.
Note: This article is a follow up to C# How to: Image filtering by directly manipulating Pixel ARGB values. The previously published related article implements image filtering by performing calculations and updating image pixel colour component values namely Alpha , Red , Green and Blue . This article achieves the same image filtering through implementing various ColorMatrix transformations, in essence providing an alternative solution. For the sake of convenience I have included the pixel manipulation extension methods in addition to the ColorMatrix extension methods detailed by this article.
Sample source code
This article is accompanied by a sample source code Visual Studio project which is available for download here.
Implementing a ColorMatrix
From MSDN Documentation:
Defines a 5 x 5 matrix that contains the coordinates for the RGBAW space. Several methods of the ImageAttributes class adjust image colors by using a color matrix.
The matrix coefficients constitute a 5 x 5 linear transformation that is used for transforming ARGB homogeneous values. For example, an ARGB vector is represented as red, green, blue, alpha and w, where w is always 1.
When implementing a translation using the ColorMatrix class values specified are added to one or more of the four colour components. A value that is to be added may only range from 0 to 1 inclusive. Note that adding a negative value results in subtracting values. A good article that illustrates implementing a ColorMatrix can be found on MSDN: How to: Translate Image Colors.
The following code snippet provides the implementation of the ApplyColorMatrix method.
private static Bitmap ApplyColorMatrix(Image sourceImage, ColorMatrix colorMatrix) { Bitmap bmp32BppSource = GetArgbCopy(sourceImage); Bitmap bmp32BppDest = new Bitmap(bmp32BppSource.Width, bmp32BppSource.Height, PixelFormat.Format32bppArgb);
using (Graphics graphics = Graphics.FromImage(bmp32BppDest)) { ImageAttributes bmpAttributes = new ImageAttributes(); bmpAttributes.SetColorMatrix(colorMatrix); graphics.DrawImage(bmp32BppSource, new Rectangle(0, 0, bmp32BppSource.Width, bmp32BppSource.Height), 0, 0, bmp32BppSource.Width, bmp32BppSource.Height, GraphicsUnit.Pixel, bmpAttributes);
}
bmp32BppSource.Dispose();
return bmp32BppDest; }
The ApplyColorMatrix method signature defines a parameter of type Image and a second parameter of type ColorMatrix. This method is intended to apply the specified ColorMatrix upon the Image parameter specified.
The source image is firstly copied in order to ensure that the image that is to be transformed is defined with a pixel format of 32 bits per pixel , consisting of the colour components Alpha , Red , Green and Blue – PixelFormat.Format32bppArgb. Next we create a blank memory bitmap defined to reflect the same size dimensions as the original source image. A ColorMatrix can be implemented by means of applying an ImageAttribute when invoking the DrawImage defined by the Graphics class.
Creating an ARGB copy
The source code snippet listed below converts source images into 32Bit ARGB formatted images:
private static Bitmap GetArgbCopy(Image sourceImage) { Bitmap bmpNew = new Bitmap(sourceImage.Width, sourceImage.Height, PixelFormat.Format32bppArgb);
using(Graphics graphics = Graphics.FromImage(bmpNew)) { graphics.DrawImage(sourceImage, new Rectangle (0, 0, bmpNew.Width, bmpNew.Height), new Rectangle (0, 0, bmpNew.Width, bmpNew.Height), GraphicsUnit.Pixel); graphics.Flush(); }
return bmpNew; }
The GetArgbCopy method creates a blank memory Bitmap having the same size dimensions as the source image. The newly created Bitmap is explicitly specified to conform to a 32Bit ARGB format. By making use of a Graphics object of which the context is bound to the new Bitmap instance the source code draws the original image to the new Bitmap.
The Transparency Filter
The transparency filter is intended to create a copy of an image, increase the copy's level of transparency and return the modified copy to the calling code. Listed below is source code which defines the DrawWithTransparency extension method.
public static Bitmap DrawWithTransparency(this Image sourceImage) { ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[]{1, 0, 0, 0, 0}, new float[]{0, 1, 0, 0, 0}, new float[]{0, 0, 1, 0, 0}, new float[]{0, 0, 0, 0.3f, 0}, new float[]{0, 0, 0, 0, 1} });
return ApplyColorMatrix(sourceImage, colorMatrix); }
Due to the ApplyColorMatrix method defined earlier implementing an image filter simply consists of defining the filter algorithm in the form of a ColorMatrix and then invoking ApplyColorMatrix.
The ColorMatrix is defined to apply no change to the Red , Green and Blue components whilst reducing the Alpha component by 70%.
The Grayscale Filter
All of the image filter extension methods illustrated in this article are implemented in a fashion similar to the DrawWithTransparency method. The DrawAsGrayscale extension method is implemented as follows:
public static Bitmap DrawAsGrayscale(this Image sourceImage) { ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[]{.3f, .3f, .3f, 0, 0}, new float[]{.59f, .59f, .59f, 0, 0}, new float[]{.11f, .11f, .11f, 0, 0}, new float[]{0, 0, 0, 1, 0}, new float[]{0, 0, 0, 0, 1} });
return ApplyColorMatrix(sourceImage, colorMatrix); }
The grayscale filter is achieved by adding together 11% blue , 59% green and 30% red , then assigning the total value to each colour component.
The Sepia Tone Filter
The sepia tone filter is implemented in the extension method DrawAsSepiaTone . Notice how this method follows the same convention as the previously discussed filters. The source code listing is detailed below.
public static Bitmap DrawAsSepiaTone(this Image sourceImage) { ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[]{.393f, .349f, .272f, 0, 0}, new float[]{.769f, .686f, .534f, 0, 0}, new float[]{.189f, .168f, .131f, 0, 0}, new float[]{0, 0, 0, 1, 0}, new float[]{0, 0, 0, 0, 1} });
return ApplyColorMatrix(sourceImage, colorMatrix); }
The formula used to calculate a sepia tone differs significantly from the grayscale filter discussed previously. The formula can be simplified as follows:
- Red Component: Sum total of: 39.3% red, 34.9% green , 27.2% blue
- Green Component: Sum total of: 76.9% red, 68.6% green , 53.4% blue
- Blue Component: Sum total of: 18.9% red, 16.8% green , 13.1% blue
The Negative Image Filter
We can implement an image filter that resembles film negatives by literally inverting every pixel's colour components. Listed below is the source code implementation of the DrawAsNegative extension method.
public static Bitmap DrawAsNegative(this Image sourceImage) { ColorMatrix colorMatrix = new ColorMatrix(new float[][] { new float[]{-1, 0, 0, 0, 0}, new float[]{0, -1, 0, 0, 0}, new float[]{0, 0, -1, 0, 0}, new float[]{0, 0, 0, 1, 0}, new float[]{1, 1, 1, 1, 1} });
return ApplyColorMatrix(sourceImage, colorMatrix); }
Notice how the negative image filter subtracts 1 from each colour component, remember the valid range being 0 to 1 inclusive. This ColorMatrix in reality inverts each pixel's colour component bits. The transform being applied can also be expressed as implementing the bitwise compliment operator on each pixel.
The implementation
The image filters described in this article are all implemented by means of a Windows Forms application. Image filtering is applied by selecting the corresponding radio button. The source image loaded from the file system serves as input to the various image filter methods, the filtered image copy returned will be displayed next to the original source image.
The following code snippet details the radio button checked changed event handler :
private void OnCheckChangedEventHandler(object sender, EventArgs e) { if (picSource.BackgroundImage != null) { if (rdGrayscaleBits.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.CopyAsGrayscale(); } else if (rdGrayscaleDraw.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.DrawAsGrayscale(); } else if (rdTransparencyBits.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.CopyWithTransparency(); } else if (rdTransparencyDraw.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.DrawWithTransparency(); } else if (rdNegativeBits.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.CopyAsNegative(); } else if (rdNegativeDraw.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.DrawAsNegative(); } else if (rdSepiaBits.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.CopyAsSepiaTone(); } else if (rdSepiaDraw.Checked == true) { picOutput.BackgroundImage = picSource.BackgroundImage.DrawAsSepiaTone(); } } }
Related Articles
- C# How to: Image filtering by directly manipulating Pixel ARGB values
- C# How to: Image filtering implemented using a ColorMatrix
- C# How to: Blending Bitmap images using colour filters
- C# How to: Bitmap Colour Substitution implementing thresholds
- C# How to: Generating Icons from Images
- C# How to: Swapping Bitmap ARGB Colour Channels
- C# How to: Bitmap Pixel manipulation using LINQ Queries
- C# How to: Linq to Bitmaps – Partial Colour Inversion
- C# How to: Bitmap Colour Balance
- C# How to: Bi-tonal Bitmaps
- C# How to: Bitmap Colour Tint
- C# How to: Bitmap Colour Shading
- C# How to: Image Solarise
- C# How to: Image Contrast
- C# How to: Bitwise Bitmap Blending
- C# How to: Image Arithmetic
Winfroms Draw Image With Point Filtring
Source: https://softwarebydefault.com/2013/03/03/colomatrix-image-filters/