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 intenisty 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:

         public static Bitmap AdjustGamma(Bitmap Image, float Value)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
            NewGraphics.Dispose();

            int[] RedRamp = new int[256];
            int[] GreenRamp = new int[256];
            int[] BlueRamp = new int[256];
            for (int x = 0; x < 256; ++x)
            {
                RedRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
                GreenRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
                BlueRamp[x] = Clamp((int)((255.0 * System.Math.Pow(x / 255.0, 1.0 / Value)) + 0.5), 255, 0);
            }

            for (int x = 0; x < NewBitmap.Width; ++x)
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    Color Pixel = NewBitmap.GetPixel(x, y);
                    int Red = RedRamp[Pixel.R];
                    int Green = GreenRamp[Pixel.G];
                    int Blue = BlueRamp[Pixel.B];
                    NewBitmap.SetPixel(x, y, Color.FromArgb(Red, Green, Blue));
                }
            }

            return NewBitmap;
        }

The formula is fairly simple that it's using to determine the value in the arrays:

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:

        private static int Clamp(int Value, int Max, int Min)
        {
            Value = Value > Max ? Max : Value;
            Value = Value < Min ? Min : Value;
            return Value;
        }

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.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/23/2009 at 9:19 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Adding Noise to an Image in C#

When it comes to image processing, more often than not, you're trying to reduce the amount of noise within an image. However there are times where you actually want to add noise to an image... The number of instances where this occurs is small, but they are out there. For instance let's say you want to make an image look like it's from an old movie. You convert the image to black and white, add a bit of noise, use a gaussian blur, and you have a olg, grainy looking image. So how do we add noise?

        public static Bitmap AddNoise(Bitmap Image, int Amount)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), System.Drawing.GraphicsUnit.Pixel);
            NewGraphics.Dispose();
            Random TempRandom = new Random();
            for (int x = 0; x < NewBitmap.Width; ++x)
            {
                for (int y = 0; y < NewBitmap.Height; ++y)
                {
                    Color CurrentPixel = TempBitmap.GetPixel(x, y);
                    int R = CurrentPixel.R + TempRandom.Next(-Amount, Amount + 1);
                    int G = CurrentPixel.G + TempRandom.Next(-Amount, Amount + 1);
                    int B = CurrentPixel.B + TempRandom.Next(-Amount, Amount + 1);
                    R = R > 255 ? 255 : R;
                    R = R < 0 ? 0 : R;
                    G = G > 255 ? 255 : G;
                    G = G < 0 ? 0 : G;
                    B = B > 255 ? 255 : B;
                    B = B < 0 ? 0 : B;
                    Color TempValue = Color.FromArgb(R, G, B);
                    NewBitmap.SetPixel(x, y, TempValue);
                }
            }
            return NewBitmap;
        }

The code above works like the other image processing functions that I've shown. You send in your bitmap and the intensity of the noise you want to show up (it's random but Amount indicates the max/min change allowed for each pixel). And all it does is randomly increases/decreases the brightness of a pixel. That's all there is to it really. And while it works best with black and white images, you can definately use it on color images without much of an issue. Anyway, I hope this helps someone out. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/21/2009 at 10:38 AM
Tags: , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed

Adjusting Brightness of an Image in C#

I've been on another image processing kick... I don't think I'll be happy until I've added every filter out there. Anyway, this time I'm going to show you how to modify the brightness of an image. Brightness can really be thought of as the amount of light that something reflects. The brighter the item the more light it reflects, the dimmer the item the less light it reflects. And since we're dealing with the RGB color space, we can even calculate the brightness of a pixel by simply taking the average of the R, G, and B channels (with a higher number being brighter).

Since a higher number means that the pixel is brighter, all we need to do is add a fixed number to R, G, and B to make a pixel brighter (or subtract the value to make it darker). That sounds pretty easy but I don't really want to loop through each pixel myself. So how do we modify each pixel? ColorMatrix.

        public static Bitmap AdjustBrightness(Bitmap Image, int Value)
        {
            System.Drawing.Bitmap TempBitmap = Image;
            float FinalValue = (float)Value / 255.0f;
            System.Drawing.Bitmap NewBitmap = new System.Drawing.Bitmap(TempBitmap.Width, TempBitmap.Height);
            System.Drawing.Graphics NewGraphics = System.Drawing.Graphics.FromImage(NewBitmap);
            float[][] FloatColorMatrix ={
                    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[] {FinalValue, FinalValue, FinalValue, 1, 1}
                };

            System.Drawing.Imaging.ColorMatrix NewColorMatrix = new System.Drawing.Imaging.ColorMatrix(FloatColorMatrix);
            System.Drawing.Imaging.ImageAttributes Attributes = new System.Drawing.Imaging.ImageAttributes();
            Attributes.SetColorMatrix(NewColorMatrix);
            NewGraphics.DrawImage(TempBitmap, new System.Drawing.Rectangle(0, 0, TempBitmap.Width, TempBitmap.Height), 0, 0, TempBitmap.Width, TempBitmap.Height, System.Drawing.GraphicsUnit.Pixel, Attributes);
            Attributes.Dispose();
            NewGraphics.Dispose();
            return NewBitmap;
        }

The code above takes in an image and an integer between -255 and 255. In turn it uses a color matrix to modify the brightness of the image.  You'll notice that the R, G, and B channels are really unchanged, with only the last row containing our value. In turn we get back a new modified image. That's all there is to it. So give it a try, leave feedback, and happy coding.

kick it on DotNetKicks.com   Shout it
Digg It!DZone It!StumbleUponTechnoratiRedditDel.icio.usNewsVineFurlBlinkListEmail

Posted by: James Craig
Posted on: 4/17/2009 at 10:45 AM
Tags: , , ,
Categories: C#
Post Information: Permalink | Comments (0) | Post RSSRSS comment feed