Click here to Skip to main content
15,867,453 members
Articles / Desktop Programming / Win32

Image Filters

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
30 Sep 2009CPOL3 min read 67.1K   6.2K   68   10
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:

C++
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:

C++
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:

C++
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

C++
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

C++
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

C++
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:

C++
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)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Member 150787168-Jul-22 14:27
Member 150787168-Jul-22 14:27 
GeneralMy vote of 5 Pin
Metafunken24-Jun-14 2:27
Metafunken24-Jun-14 2:27 
Questionmy vote of 5 too! Pin
dommy1A11-Nov-12 21:00
dommy1A11-Nov-12 21:00 
AnswerRe: my vote of 5 too! Pin
Fiwel12-Nov-12 7:29
Fiwel12-Nov-12 7:29 
GeneralMy vote of 5 Pin
yoke31-Aug-12 14:19
yoke31-Aug-12 14:19 
GeneralRe: Unsharpmask & Blur Pin
Fiwel7-Oct-10 5:04
Fiwel7-Oct-10 5:04 
Generalspeed Pin
JohnWallis4230-Sep-09 15:07
JohnWallis4230-Sep-09 15:07 
GeneralRe: speed Pin
Kochise3-Oct-09 22:11
Kochise3-Oct-09 22:11 
GeneralRe: speed Pin
Gordon Smith5-Oct-09 23:52
Gordon Smith5-Oct-09 23:52 

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

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