Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Image Filters

0.00/5 (No votes)
30 Sep 2009 1  
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 :).

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here