Software Development optimize

How do I... Convert images to grayscale and sepia tone using C#?


The Microsoft .NET Framework provides developers with many different libraries that enable them to create and modify images. In this How do I... post, Zach Smith demonstrates two methods for converting an image to grayscale and sepia-tone using built-in .NET Framework functionality from C#. Before we dive into the code, we need to look at the algorithms used to determine how to convert the image. Each algorithm will take a color as input and then calculate the resultant color. For grayscale this is relatively easy. You simply calculate the brightness of the color and use that value to create a shade of gray. A very basic implementation of this is shown in Listing A.

Note: The TechRepublic PDF download version of this blog post includes a Visual Studio project file will all of the code and libraries mentioned.

Listing A

outputColor = (inputRed + inputGreen + inputBlue) / 3

You then set all three RGB values equal to "outputColor".

Sepia tone is a little more complex because we are no longer working in shades of gray, and we cannot rely on the average of the other colors for our output color. For sepia tone, we will use a calculation similar to the one shown in Listing B.

Listing B

outputRed = (inputRed * .393) + (inputGreen *.769) + (inputBlue * .189)

outputGreen = (inputRed * .349) + (inputGreen *.686) + (inputBlue * .168)

outputBlue = (inputRed * .272) + (inputGreen *.534) + (inputBlue * .131)
If any of these output values is greater than 255, you simply set it to 255. These specific values are the values for sepia tone that are recommended by Microsoft.

The following examples are two of the more common approaches used to convert images to grayscale or sepia tone. While there are other ways to achieve the same result, these two methods do not use unsafe code blocks or external calls to Windows APIs -- techniques some other approaches use. Because of this, these two solutions are cleaner and easier to adapt.

The first method of conversion

The first method of conversion is the SetPixel method. To do this we create a Bitmap and loop through every pixel of the Bitmap, stopping at each one to calculate the color we want to change it to. Then, we call Bitmap.SetPixel to change the pixel to our desired color. An example of this method is shown in Listing C.

Listing C

private void btnGrayscale_Click(object sender, EventArgs e)

{

//Get the image from our PictureBox

Bitmap grayScale = (Bitmap)picOriginal.Image.Clone();

//Store the height/width of the image

int height = grayScale.Size.Height;

int width = grayScale.Size.Width;

//Loop through both the Y (vertical) and X (horizontal)

// coordinates of the image.

for (int yCoordinate = 0; yCoordinate < height; yCoordinate++)

{

for (int xCoordinate = 0; xCoordinate < width; xCoordinate++)

{

//Get the pixel that's at our current coordinate.

Color color = grayScale.GetPixel(xCoordinate, yCoordinate);

//Calculate the gray to use for this pixel.

int grayColor = (color.R + color.G + color.B) / 3;

//Set the pixel to the new gray color.

grayScale.SetPixel(xCoordinate, yCoordinate, Color.FromArgb(grayColor,

grayColor,

grayColor));

}

}

//Set the modified PictureBox to our new image.

picModified.Image = grayScale;

}

The example code above was taken from the sample application included with the download version of this blog post. The sample application also includes an example of converting to sepia tone using this SetPixel method.

The second method of conversion

The second method of conversion is to use an object called a ColorMatrix. You create the ColorMatrix object, obtain a Graphics object from the image you want to convert, create a new ImageAttributes object, which contains the color matrix, and then use the Graphics object to draw the image with the modified attributes. Listing D shows this code in detail, with comments describing what is happening in each step.

Listing D

private void btnMatrixGrayscale_Click(object sender, EventArgs e)

{

//ColorMatrix layout:

// Red Result Green Result Blue Result Alpha Result

//Red Value .299 .299 .299 0 (Ignored)

//Green Value .587 .587 .587 0 (Ignored)

//Blue Value .114 .114 .114 0 (Ignored)

//Alpha Value 0 0 0 1

//This is basically saying that:

// Red should be converted to (R*.299)+(G*.587)+(B*.114)

// Green should be converted to (R*.299)+(G*.587)+(B*.114)

// Blue should be converted to (R*.299)+(G*.587)+(B*.114)

// Alpha should stay the same.

//Create the color matrix.

ColorMatrix matrix = new ColorMatrix(new float[][]{

new float[] {0.299f, 0.299f, 0.299f, 0, 0},

new float[] {0.587f, 0.587f, 0.587f, 0, 0},

new float[] {0.114f, 0.114f, 0.114f, 0, 0},

new float[] { 0, 0, 0, 1, 0},

new float[] { 0, 0, 0, 0, 0}

});

//Create our image to convert.

Image image = (Bitmap)picOriginal.Image.Clone();

//Create the ImageAttributes object and apply the ColorMatrix

ImageAttributes attributes = new ImageAttributes();

attributes.SetColorMatrix(matrix);

//Create a new Graphics object from the image.

Graphics graphics = Graphics.FromImage(image);

//Draw the image using the ImageAttributes we created.

graphics.DrawImage(image,

new Rectangle(0, 0, image.Width, image.Height),

0,

0,

image.Width,

image.Height,

GraphicsUnit.Pixel,

attributes);

//Dispose of the Graphics object.

graphics.Dispose();

picModified.Image = image;

}

The code above converts an image to grayscale using the ColorMatrix method. As you can see, it does not use the simple algorithm of (R+G+B)/3 to convert the image. Instead it uses the same algorithm used by color TVs to display black-and-white images.

Example images

The following are example images created using the sample application included with the download version of this blog post.

Figure A

Original image

Figure B

Grayscale image

Figure C

Sepia tone image
3 comments
Nunuvyah
Nunuvyah

Wrong! To convert to grayscale, first normalize by dividing the pixels by 255.0. Next remove the gamma correction. (For sRGB, gamma is approximately. 2.2, so raise the normalized pixel components to the power of 2.2.) Then you multiply by the luminance values of the primary illuminants. (For sRGB, those are approx. rY = 0.212655 gY = 0.715158 bY = 0.072187) Next apply gamma correction by raising the values to the power of 1/2.2, and then multipy by 255.0 and round to integer values.

ra.therapist
ra.therapist

I have a bitmap shown over a background. I set the transparency using a ColorMatrix. I now want to save image and background. The saved image will not be transparent, but I want the forground image to remain faded.

santeewelding
santeewelding

That you have arisen after a sleep of two years?