Other Posts in Image Editing

  1. Perlin Noise
  2. Fault Formation
  3. Cellular Textures
  4. Resizing an Image in C#
  5. Box Blur and Gaussian Blur... Sort of...
  6. Thermal Erosion
  7. Using Mid Point Displacement to Create Cracks
  8. Fluvial Erosion
  9. Creating Marble Like Textures Procedurally
  10. Procedural Textures and Dilation
  11. Converting Image to Black and White in C#
  12. Getting an HTML Based Color Palette from an Image in C#
  13. Adding Noise/Jitter to an Image in C#
  14. Creating Pixelated Images in C#
  15. Edge detection in C#
  16. Using Sin to Get What You Want... In C#...
  17. Noise Reduction of an Image in C# using Median Filters
  18. Image Dilation in C#
  19. Sepia Tone in C#
  20. Kuwahara Filter in C#
  21. Matrix Convolution Filters in C#
  22. Symmetric Nearest Neighbor in C#
  23. Bump Map Creation Using C#
  24. Normal Map Creation Using C#
  25. Creating Negative Images using C#
  26. Red, Blue, and Green Filters in C#
  27. Converting an Image to ASCII Art in C#
  28. Adjusting Brightness of an Image in C#
  29. Adding Noise to an Image in C#
  30. Adjusting the Gamma of an Image Using C#
  31. Adjusting Contrast of an Image in C#
  32. Drawing a Box With Rounded Corners in C#
  33. Anding Two Images Together Using C#
  34. Motion Detection in C#
  35. Creating Thermometer Chart in C#
  36. Colorizing a Black and White Image in C#
  37. Extracting an Icon From a File
  38. Setting the Pixel Format and Image Format of an Image in .Net
  39. Using Unsafe Code for Faster Image Manipulation
  40. Sobel Edge Detection and Laplace Edge Detection in C#

Adjusting the Gamma of an Image Using C#


I covered how to adjust the brightness of an image last week. Today I'm going to talk about a subject that is very similar but at the same time fairly different: Gamma. Gamma determines the intensity of the light produced by a CRT... You see back in the day of CRT TVs (early portion of it anyway as this was discovered fairly early), it was thought that the intensity of the color produced was proportional to the input voltage. However that wasn't the case. Instead they found that TVs that used same voltage showed colors in completely different intensities. What it turned out is that the intensity was dictated by the input voltage raised to the power of gamma. Gamma being pretty much being a random (as far as your concerned) number between .2 and 5, and usually centering around 2.5. What that means is your green, while a nice shade of green, may not be as green as my green, which is totally greener...

In order to combat this, most devices use gamma correction. This is done by creating an array of values that have the "corrected" colors as they should be displayed. So for instance if you have a pixel with a green value of 3, you'd look in the array in the third slot to see what value it should really be. Right about now you're wishing I'd shut up and show you how to implement it already, so here you go:

   1: /// <summary>
   2: /// Adjusts the Gamma
   3: /// </summary>
   4: /// <param name="OriginalImage">Image to change</param>
   5: /// <param name="Value">Used to build the gamma ramp (usually .2 to 5)</param>
   6: /// <returns>A bitmap object</returns>
   7: public static Bitmap AdjustGamma(Bitmap OriginalImage, float Value)
   8: {
   9:     Bitmap NewBitmap = new Bitmap(OriginalImage.Width, OriginalImage.Height);
  10:     BitmapData NewData = Image.LockImage(NewBitmap);
  11:     BitmapData OldData = Image.LockImage(OriginalImage);
  12:     int NewPixelSize = Image.GetPixelSize(NewData);
  13:     int OldPixelSize = Image.GetPixelSize(OldData);
  15:     int[] RedRamp = new int[256];
  16:     int[] GreenRamp = new int[256];
  17:     int[] BlueRamp = new int[256];
  18:     for (int x = 0; x < 256; ++x)
  19:     {
  20:         RedRamp[x] = MathHelper.Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
  21:         GreenRamp[x] = MathHelper.Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
  22:         BlueRamp[x] = MathHelper.Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
  23:     }
  25:     for (int x = 0; x < NewBitmap.Width; ++x)
  26:     {
  27:         for (int y = 0; y < NewBitmap.Height; ++y)
  28:         {
  29:             Color Pixel = Image.GetPixel(OldData, x, y, OldPixelSize);
  30:             int Red = RedRamp[Pixel.R];
  31:             int Green = GreenRamp[Pixel.G];
  32:             int Blue = BlueRamp[Pixel.B];
  33:             Image.SetPixel(NewData, x, y, Color.FromArgb(Red, Green, Blue), NewPixelSize);
  34:         }
  35:     }
  37:     Image.UnlockImage(NewBitmap, NewData);
  38:     Image.UnlockImage(OriginalImage, OldData);
  39:     return NewBitmap;
  40: }

Note that the code above uses a couple of functions from my utility library, mainly Image.LockImage, UnlockImage, etc. Most of them can be removed or replaced with the built in GetPixel/SetPixel functions (or you can simply download my library and get a ton of extra code along with it). Anyway, the formula that is used is fairly simple to determine the value in the arrays:

   1: Value=((x/255)^(1/InputValue))+0.5

Where x/255 simulates the voltage (if we were talking about CRTs) and1/InputValue being the gamma. You may also notice that it calls a function called Clamp:

   1: private static int Clamp(int Value, int Max, int Min)
   2: {
   3:     Value = Value > Max ? Max : Value;
   4:     Value = Value < Min ? Min : Value;
   5:     return Value;
   6: }

The clamp function just makes sure that we're between 0 and 255 (inclusive). Anyway, that's all there is to implementing it. Just call it, sending in your image and the gamma value (once again, your best results will be between .2 and 5). The function will in turn send back a new, gamma corrected image. So try it out, leave feedback, and happy coding.