http://www.bobpowell.net/grayscale.htm
Colours in an image may be converted to a shade of gray by calculating the effective
brightness or luminance of the colour and using this value to create a shade of gray
that matches the desired brightness.
The following code snippet isn't really a good example of how it should be done in a production situation but it does show the principles involved clearly. For every day use. see the ColorMatrix example below.
The effective luminance of a pixel is calculated with the following formula:
Y=0.3RED+0.59GREEN+0.11Blue
This luminance value can then be turned into a grayscale pixel using Color.FromArgb(Y,Y,Y).
Converting an image from colour to monochrome can be performed using the following code:
[C#]
public Bitmap ConvertToGrayscale(Bitmap source)
{
Bitmap bm = new Bitmap(source.Width,source.Height);
for(int y=0;y<bm.Height;y++)
{
for(int x=0;x<bm.Width;x++)
{
Color c=source.GetPixel(x,y);
int luma = (int)(c.R*0.3 + c.G*0.59+ c.B*0.11);
bm.SetPixel(x,y,Color.FromArgb(luma,luma,luma));
}
}
return bm;
}
[VB]
Public Function ConvertToGrayscale(ByVal source As Bitmap) as Bitmap
Dim bm as new Bitmap(source.Width,source.Height)
Dim x
Dim y
For y=0 To bm.Height
For x=0 To bm.Width
Dim c as Color = source.GetPixel(x,y)
Dim luma as Integer = CInt(c.R*0.3 + c.G*0.59 + c.B*0.11)
bm.SetPixel(x,y,Color.FromArgb(luma,luma,luma)
Next
Next
Return bm
End Function
The images below show a color image and its monochrome conversion.
Alternative Version using the ColorMatrix class
Jacob Grass ( http://www.windowsforms.net ) sent me an excellent alternative to the
previous method which uses a colour matrix shear to create the greyscale. While this is
an effective and quick method of performing the monochrome manipulation, colour
geeks will tell you that the luminance values are all off and the grey balance of the
final image is not correct.
Note: Since I first posted this article, Gilles Khouzam has provided me with a ColorMatrix shear that maintains the luminance correctly. I have placed this matrix definition in the code provided by Jacob and you can see the difference by commenting out one matrix and substituting the other.
[C#]
using System; using System.Drawing; using System.Drawing.Imaging; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
namespace GrayShear { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null;
public Form1() { // // Required for Windows Form Designer support // InitializeComponent();
// // TODO: Add any constructor code after InitializeComponent call // }
/// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); }
#region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(296, 269); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load);
} #endregion
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }
private void Form1_Load(object sender, System.EventArgs e) { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter="Image files (*.BMP, *.JPG, *.GIF)|*.bmp;*.jpg;*.gif"; if(dlg.ShowDialog()==DialogResult.OK) { Image img = Image.FromFile(dlg.FileName); Bitmap bm = new Bitmap(img.Width,img.Height); Graphics g = Graphics.FromImage(bm);
ColorMatrix cm = new ColorMatrix(new float[][]{ new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0.5f,0.5f,0.5f,0,0}, new float[]{0,0,0,1,0,0}, new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
/*
//Gilles Khouzams colour corrected grayscale shear ColorMatrix cm = new ColorMatrix(new float[][]{ new float[]{0.3f,0.3f,0.3f,0,0}, new float[]{0.59f,0.59f,0.59f,0,0}, new float[]{0.11f,0.11f,0.11f,0,0}, new float[]{0,0,0,1,0,0}, new float[]{0,0,0,0,1,0}, new float[]{0,0,0,0,0,1}});
*/
ImageAttributes ia = new ImageAttributes(); ia.SetColorMatrix(cm); g.DrawImage(img,new Rectangle(0,0,img.Width,img.Height),0,0,img.Width,img.Height,GraphicsUnit.Pixel,ia); g.Dispose(); this.BackgroundImage=bm; } } } }
[VB]
Imports System.Drawing.Imaging
Public Class Form1 Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New() MyBase.New()
'This call is required by the Windows Form Designer. InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose() End If End If MyBase.Dispose(disposing) End Sub
'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer
'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() components = New System.ComponentModel.Container() Me.Text = "Form1" End Sub
#End Region
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim dlg As OpenFileDialog = New OpenFileDialog() dlg.Filter = "Image files (*.BMP, *.JPG, *.GIF)|*.bmp;*.jpg;*.gif" If dlg.ShowDialog() = DialogResult.OK Then Dim img As Image = Image.FromFile(dlg.FileName) Dim bm As Bitmap = New Bitmap(img.Width, img.Height) Dim g As Graphics = Graphics.FromImage(bm) Dim cm As ColorMatrix = New ColorMatrix(New Single()() _ {New Single() {0.5, 0.5, 0.5, 0, 0}, _ New Single() {0.5, 0.5, 0.5, 0, 0}, _ New Single() {0.5, 0.5, 0.5, 0, 0}, _ New Single() {0, 0, 0, 1, 0}, _ New Single() {0, 0, 0, 0, 1}})
'Gilles Khouzams colour corrected grayscale shear
'Dim cm As ColorMatrix = New ColorMatrix(New Single()() _ ' {New Single() {0.3, 0.3, 0.3, 0, 0}, _ ' New Single() {0.59, 0.59, 0.59, 0, 0}, _ ' New Single() {0.11, 0.11, 0.11, 0, 0}, _ ' New Single() {0, 0, 0, 1, 0}, _ ' New Single() {0, 0, 0, 0, 1}})
Dim ia As ImageAttributes = New ImageAttributes() ia.SetColorMatrix(cm) g.DrawImage(img, New Rectangle(0, 0, img.Width, img.Height), 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, ia) g.Dispose() Me.BackgroundImage = bm End If End Sub
End Class
In conclusion, the technique of turning a colour image into an accurate gray scale is most easily accomplished using the ColorMatrix class initialized with the classic luminance calculation values.