
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)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.outputGreen = (inputRed * .349) + (inputGreen *.686) + (inputBlue * .168)
outputBlue = (inputRed * .272) + (inputGreen *.534) + (inputBlue * .131)
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 imagesThe following are example images created using the sample application included with the download version of this blog post.