Click here to Skip to main content
Click here to Skip to main content

Image Filters

, 30 Sep 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Different ways to apply image filters.

Demo

Background

In about 20 years of working with GDI, I never needed to do image filters. "If not now, when?" I decided to start with brightness and contrast. After a relatively extensive research, I came up with three reasonable approaches, and since I was already doing it, I decided to check the GetPixel / SetPixel speed – is it as slow as everyone claims?

Goals

  1. To be open minded and persistent - even with great tools like AForge, you can often write a better, simpler, and faster solution yourself, with relatively little effort.
  2. For more advanced members: it seems to me - for some strange reason, the unsafe mode is very popular. Very often, there is no need for it – you can accomplish the same with simple marshaling, or by other means.
  3. Most important – translation of the QColorMatrix from C++ to C#. While doing this research – I did not see a better approach to image filtering, compared to the use of the QColorMatrix approach. This subject is very advanced; while the code itself is very simple and very readable, the math is relatively complicated. I can not explain the code unless I explain how the ColorMatrix works. But that is not the goal of this article. If your math level is strong enough, and you understand matrix multiplications and rotations, you can very easily understand and follow the code. If your math level is not strong enough, you can just use it as shown below - it works Smile | :) .

Method 1

At first, my search brought me to this article: Image Processing Lab in C#. It uses the AForge library. I was too lazy to look for the source. It was much easier for me to use Refractory and get the objects that control brightness and contracts – that was how the AForgeFilter object was created. There are three things I do not like about the AForge way:

  1. Unsafe mode, you might have a business requirement not to use unsafe mode.
  2. Seems to me: sometimes you might want to apply brightness and contrast filters at the same time. With AForge, you can’t do it.
  3. As my follow up research indicates, it is too slow.

The first problem I solved very easily – just use marshaling instead of unsafe mode. The attached demo shows how long it took to process the image. I could not notice that marshaling works any slower compared to the unsafe mode, so why use unsafe?

Method 2

Unfortunately, I did not keep the link of where I found the second method's algorithms. (The OtherFilter object). It is much simpler compared with AForge, and it is faster.

Method 3

I was not completely satisfied. There is a ColorMatrix object. There must be a way to use it for image filtering. The next article I hit was: Playing with ColorMatrix by Sjaak Priester. Fortunately, I am equally fluent in C++ and C#. QColorMatrix is a more or less direct translation of the original C++ QColorMatrix. How fast is it? Applying four filters and Gamma is ~2 times faster compared to the second method, and ~7 times faster compared to AForge…

Method 4

If any one is not yet convinced not to use the GetPixel / SetPixel methods (the OtherFilterSlow object) – take a look at how slow it is: ~10 times slower. Still want to use it?

Using the code

Please note: if you are going to use the AForgeFilter object, you will need to check with the AForge community. I do not know what their license is, and my code is just a refractory from aforge.dll. Otherwise, the code is used as explained below. To adjust brightness:

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled; 
AForgeFilter pFilterBrightness = new AForgeFilter();
pFilterBrightness.AdjustValue = (double)TrackBarBrightness1.Value / 1000;
Bitmap pBitmapBrightness = pFilterBrightness.Apply(pSource);

To adjust contrast:

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled; 
AForgeFilter pFilterContrast= new AForgeFilter();
pFilterContrast.Factor = (double)TrackBarContrast1.Value / 1000;
Bitmap pBitmapBrightness = pFilterContrast.Apply(pSource);

In the example, I wanted to compare safe mode to unsafe mode, and changed brightness and contrast at the same time. Here is the code:

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled; 
AForgeFilter pFilterBrightness = new AForgeFilter();
pFilterBrightness.AdjustValue = (double)TrackBarBrightness1.Value / 1000;
Bitmap pBitmapBrightness = checkBoxSafe.Checked ? 
   pFilterBrightness.ApplySafe(pSource) : pFilterBrightness.Apply(pSource);
AForgeFilter pFilterContrast = new AForgeFilter();
pFilterContrast.Factor = (double)TrackBarContrast1.Value / 1000;
Bitmap pBitmapContrast = checkBoxSafe.Checked ? 
   pFilterContrast.ApplySafe(pBitmapBrightness) : 
   pFilterContrast.Apply(pBitmapBrightness);

For the second method:

Brightness

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled;
Bitmap pBitmap = pSource.Clone(new Rectangle(0, 0, pSource.Width, pSource.Height), 
                               pSource.PixelFormat);
new Brightness().Adjust(pBitmap, TrackBarBrightness2.Value);

Contrast

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled;
Bitmap pBitmap = pSource.Clone(new Rectangle(0, 0, pSource.Width, pSource.Height), 
                               pSource.PixelFormat);
Contrast().Adjust(pBitmap, TrackBarContrast2.Value);

Brightness and Contrast

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled;
Bitmap pBitmap = pSource.Clone(new Rectangle(0, 0, pSource.Width, pSource.Height), 
                               pSource.PixelFormat);
new BrightnessContrast().Adjust(pBitmap, TrackBarBrightness2.Value, TrackBarContrast2.Value);

The third method allows you to change four filters and gamma:

QColorMatrix pQColorMatrix = new QColorMatrix();
pQColorMatrix.ScaleColors(TrackBarContrast3.Value * 0.05f, 
                          QColorMatrix.MatrixOrder.MatrixOrderPrepend);
pQColorMatrix.TranslateColors(TrackBarBrightness3.Value * 0.05f, 
                              QColorMatrix.MatrixOrder.MatrixOrderAppend);
pQColorMatrix.SetSaturation(TrackBarSaturation3.Value * 0.05f, 
                            QColorMatrix.MatrixOrder.MatrixOrderAppend);
pQColorMatrix.RotateHue(TrackBarHue3.Value * 4.0f);

Bitmap pSource = global::WindowsFormsApplication14.Properties.Resources.untitled;
Bitmap pResult = pQColorMatrix.Adjust(pSource, TrackBarGamma3.Value * 0.05f);

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Fiwel
Software Developer (Senior)
United States United States
No Biography provided

Comments and Discussions

 
GeneralMy vote of 5 PinmemberMetafunken24-Jun-14 3:27 
Questionmy vote of 5 too! Pinmemberzeebedee11-Nov-12 22:00 
AnswerRe: my vote of 5 too! PinmemberFiwel12-Nov-12 8:29 
GeneralMy vote of 5 Pinmemberyoke31-Aug-12 15:19 
GeneralRe: Unsharpmask & Blur PinmemberFiwel7-Oct-10 6:04 
Generalspeed PinmemberJohnWallis4230-Sep-09 16:07 
GeneralRe: speed PinmemberKochise3-Oct-09 23:11 
GeneralRe: speed PinmemberGordon Smith6-Oct-09 0:52 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150123.1 | Last Updated 30 Sep 2009
Article Copyright 2009 by Fiwel
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid