
Adjusting The Contrast Of An Image.Image contrast is a function of scale. This is to say that the relative differences between one pixel and the next are increased with greater contrast and decreased with smaller contrast. The easiest way to perform this adjustment with GDI+ is using the ColorMatrix class to scale the pixels. The ColorMatrix is used in conjunction with the ImageAttributes class to process the pixels of an image as it is drawn so, to get an image with different contrast we just need a method of setting the scale of the red, green and blue elements to the same relative values. This is accomplished with a ColorMatrix that looks like the one shown below. C 0 0 0 0 0 C 0 0 0 0 0 C 0 0 0 0 0 1 0 0 0 0 0 1
In this case the "C" is the contrast scale component. To leave the contrast as it is in the original, the contrast scaling value may be set to 1.0. This creates an identity matrix which will process the image without change. To halve the contrast you can use 0.5 and to double it you would use 2. The setting in matrix position [3,3] is to maintain the alpha component unchanged.
Adjusting the contrast in this manner also changes the brightness of an image. Reducing contrast makes the image darker because reducing the scale of the colours moves the RGB values towards zero. Conversely, increasing the scale makes the image brighter because the values are driven towards the maximum of 255. Images that are adjusted for color also often need to be adjusted for brightness.
A Bug or a Feature?
There is one small problem with this theory and that is the ColorMatrix has a nasty habit of causing arithmetic overflows in the images colour values such that simply scaling will cause an undesirable colourization of the image. Any red, green or blue colour elements having a zero value can overflow to some large value which causes the pixel to take on a totally different colour. To fix this, and it is a blatant fudge, we simply need to shift the colours minutely in one direction or another and the problem goes away. The fudge in the code below offsets the image colours by a measly 0.001, just a tenth of one percent. This means that our final matrix looks like this...
C 0 0 0 0 0 C 0 0 0 0 0 C 0 0 0 0 0 1 0 0.001 0.001 0.001 0 1
The colour purists may complain but it's better than the alternative.
The following listings show an application that enables you to adjust the contrast of an image.
Show me code in C#
using System; using System.IO; using System.Drawing; using System.Drawing.Imaging; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
namespace ImageContrast { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form {
Bitmap _image;
float _contrastFactor=1f;
private System.Windows.Forms.Button button1; private System.Windows.Forms.Button button2; private System.Windows.Forms.Button button3; private System.Windows.Forms.TrackBar trackBar1; private System.Windows.Forms.PictureBox pictureBox1; private System.Windows.Forms.Label label1; /// <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() { this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.button3 = new System.Windows.Forms.Button(); this.trackBar1 = new System.Windows.Forms.TrackBar(); this.pictureBox1 = new System.Windows.Forms.PictureBox(); this.label1 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); this.SuspendLayout(); // // button1 // this.button1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.button1.Location = new System.Drawing.Point(448, 280); this.button1.Name = "button1"; this.button1.TabIndex = 0; this.button1.Text = "Open"; this.button1.Click += new System.EventHandler(this.button1_Click); // // button2 // this.button2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.button2.Location = new System.Drawing.Point(448, 312); this.button2.Name = "button2"; this.button2.TabIndex = 0; this.button2.Text = "Save"; this.button2.Click += new System.EventHandler(this.button2_Click); // // button3 // this.button3.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.button3.Location = new System.Drawing.Point(448, 344); this.button3.Name = "button3"; this.button3.TabIndex = 0; this.button3.Text = "Done"; this.button3.Click += new System.EventHandler(this.button3_Click); // // trackBar1 // this.trackBar1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.trackBar1.Location = new System.Drawing.Point(464, 88); this.trackBar1.Maximum = 100; this.trackBar1.Name = "trackBar1"; this.trackBar1.Orientation = System.Windows.Forms.Orientation.Vertical; this.trackBar1.Size = new System.Drawing.Size(45, 176); this.trackBar1.TabIndex = 1; this.trackBar1.TickFrequency = 10; this.trackBar1.Value = 25; this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll); // // pictureBox1 // this.pictureBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.pictureBox1.Location = new System.Drawing.Point(8, 8); this.pictureBox1.Name = "pictureBox1"; this.pictureBox1.Size = new System.Drawing.Size(432, 360); this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage; this.pictureBox1.TabIndex = 2; this.pictureBox1.TabStop = false; // // label1 // this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.label1.Location = new System.Drawing.Point(456, 40); this.label1.Name = "label1"; this.label1.Size = new System.Drawing.Size(56, 23); this.label1.TabIndex = 3; this.label1.Text = "1"; this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(536, 389); this.Controls.Add(this.label1); this.Controls.Add(this.pictureBox1); this.Controls.Add(this.trackBar1); this.Controls.Add(this.button1); this.Controls.Add(this.button2); this.Controls.Add(this.button3); this.Name = "Form1"; this.Text = "Form1"; ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); this.ResumeLayout(false);
} #endregion
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }
private void button1_Click(object sender, System.EventArgs e) { OpenFileDialog dlg=new OpenFileDialog(); dlg.Filter="Image files|*.bmp; *.jpg; *.gif; *.tif; *.png"; if(dlg.ShowDialog()==DialogResult.OK) { _image=(Bitmap)Image.FromFile(dlg.FileName,true); this.Text=dlg.FileName; } this.trackBar1.Value=25; //reset the contrast and update the image UpdateImage(); }
private void button3_Click(object sender, System.EventArgs e) { Application.Exit(); }
private void trackBar1_Scroll(object sender, System.EventArgs e) { _contrastFactor=0.04f*this.trackBar1.Value;
this.label1.Text=this._contrastFactor.ToString("0.00"); UpdateImage(); }
/// <summary> /// Adjusts the contrast of the image by modifying the scale of the original colours using a ColorMatrix /// </summary> void UpdateImage() { if(_image==null) return; Image oldImage=this.pictureBox1.Image; // save the old image so we can dispose of it nicely
Bitmap bm=new Bitmap(this._image.Width, this._image.Height); //create a new image Graphics g=Graphics.FromImage(bm); //ready to draw on it ImageAttributes ia=new ImageAttributes(); //create the scaling matrix ColorMatrix cm=new ColorMatrix(new float[][]{ new float[]{_contrastFactor,0f,0f,0f,0f}, new float[]{0f,_contrastFactor,0f,0f,0f}, new float[]{0f,0f,_contrastFactor,0f,0f}, new float[]{0f,0f,0f,1f,0f}, //including the BLATANT FUDGE new float[]{0.001f,0.001f,0.001f,0f,1f}}); //use it in the image attributes ia.SetColorMatrix(cm); //draw the original to the temporary using the matrix g.DrawImage(_image,new Rectangle(0,0,_image.Width,_image.Height),0,0,_image.Width,_image.Height,GraphicsUnit.Pixel,ia); g.Dispose(); //Don't need this anymore; ia.Dispose(); // or this this.pictureBox1.Image=bm; //replace the picture; if(oldImage!=null) oldImage.Dispose(); // get rid of the old one if it exists. }
private void button2_Click(object sender, System.EventArgs e) { //Saves the image in the chosen format if(_image==null) return; SaveFileDialog dlg=new SaveFileDialog(); dlg.Filter="Image files|*.bmp; *.jpg; *.gif; *.tif; *.png "; dlg.FileName=this.Text; if(dlg.ShowDialog()==DialogResult.OK) { this.Text=dlg.FileName; ImageFormat fmt=ImageFormat.Jpeg; switch(Path.GetExtension(dlg.FileName).ToLower()) { case ".jpg": case ".jpeg": fmt=ImageFormat.Jpeg; break; case ".bmp": fmt=ImageFormat.Bmp; break; case ".png": fmt=ImageFormat.Png; break; case ".tif": case ".tiff": fmt=ImageFormat.Tiff; break; case ".gif": fmt=ImageFormat.Gif; break; } //make the image in the picturebox the working image this._image.Dispose(); this.pictureBox1.Image.Save(dlg.FileName,fmt); this._image=(Bitmap)this.pictureBox1.Image; } }
} }
Show me code in VB
Imports System Imports System.IO Imports System.Drawing Imports System.Drawing.Imaging Imports System.Collections Imports System.ComponentModel Imports System.Windows.Forms Imports System.Data
Namespace ImageContrast '/ <summary> '/ Summary description for Form1. '/ </summary>
Public Class Form1 Inherits System.Windows.Forms.Form
Private _image As Bitmap
Private _contrastFactor As Single = 1F
Private WithEvents button1 As System.Windows.Forms.Button Private WithEvents button2 As System.Windows.Forms.Button Private WithEvents button3 As System.Windows.Forms.Button Private WithEvents trackBar1 As System.Windows.Forms.TrackBar Private pictureBox1 As System.Windows.Forms.PictureBox Private label1 As System.Windows.Forms.Label '/ <summary> '/ Required designer variable. '/ </summary> Private components As System.ComponentModel.Container = Nothing
Public Sub New() ' ' Required for Windows Form Designer support ' InitializeComponent() End Sub 'New
' ' TODO: Add any constructor code after InitializeComponent call '
'/ <summary> '/ Clean up any resources being used. '/ </summary> 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 'Dispose
#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 Sub InitializeComponent() Me.button1 = New System.Windows.Forms.Button Me.button2 = New System.Windows.Forms.Button Me.button3 = New System.Windows.Forms.Button Me.trackBar1 = New System.Windows.Forms.TrackBar Me.pictureBox1 = New System.Windows.Forms.PictureBox Me.label1 = New System.Windows.Forms.Label CType(Me.trackBar1, System.ComponentModel.ISupportInitialize).BeginInit() Me.SuspendLayout() ' ' button1 ' Me.button1.Anchor = CType(System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.button1.Location = New System.Drawing.Point(448, 280) Me.button1.Name = "button1" Me.button1.TabIndex = 0 Me.button1.Text = "Open" ' ' button2 ' Me.button2.Anchor = CType(System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.button2.Location = New System.Drawing.Point(448, 312) Me.button2.Name = "button2" Me.button2.TabIndex = 0 Me.button2.Text = "Save" ' ' button3 ' Me.button3.Anchor = CType(System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.button3.Location = New System.Drawing.Point(448, 344) Me.button3.Name = "button3" Me.button3.TabIndex = 0 Me.button3.Text = "Done" ' ' trackBar1 ' Me.trackBar1.Anchor = CType(System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.trackBar1.Location = New System.Drawing.Point(464, 88) Me.trackBar1.Maximum = 100 Me.trackBar1.Name = "trackBar1" Me.trackBar1.Orientation = System.Windows.Forms.Orientation.Vertical Me.trackBar1.Size = New System.Drawing.Size(45, 176) Me.trackBar1.TabIndex = 1 Me.trackBar1.TickFrequency = 10 Me.trackBar1.Value = 25 ' ' pictureBox1 ' Me.pictureBox1.Anchor = CType(System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.pictureBox1.Location = New System.Drawing.Point(8, 8) Me.pictureBox1.Name = "pictureBox1" Me.pictureBox1.Size = New System.Drawing.Size(432, 360) Me.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage Me.pictureBox1.TabIndex = 2 Me.pictureBox1.TabStop = False ' ' label1 ' Me.label1.Anchor = CType(System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Right, System.Windows.Forms.AnchorStyles) Me.label1.Location = New System.Drawing.Point(456, 40) Me.label1.Name = "label1" Me.label1.Size = New System.Drawing.Size(56, 23) Me.label1.TabIndex = 3 Me.label1.Text = "1" Me.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter ' ' Form1 ' Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(536, 389) Me.Controls.Add(label1) Me.Controls.Add(pictureBox1) Me.Controls.Add(trackBar1) Me.Controls.Add(button1) Me.Controls.Add(button2) Me.Controls.Add(button3) Me.Name = "Form1" Me.Text = "Form1" CType(Me.trackBar1, System.ComponentModel.ISupportInitialize).EndInit() Me.ResumeLayout(False) End Sub 'InitializeComponent #End Region
'/ <summary> '/ The main entry point for the application. '/ </summary> <STAThread()> _ Shared Sub Main() Application.Run(New Form1) End Sub 'Main
Private Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button1.Click Dim dlg As New OpenFileDialog dlg.Filter = "Image files|*.bmp; *.jpg; *.gif; *.tif; *.png" If dlg.ShowDialog() = DialogResult.OK Then _image = CType(Image.FromFile(dlg.FileName, True), Bitmap) Me.Text = dlg.FileName End If Me.trackBar1.Value = 25 'reset the contrast and update the image UpdateImage() End Sub 'button1_Click
Private Sub button3_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles button3.Click Application.Exit() End Sub 'button3_Click
Private Sub trackBar1_Scroll(ByVal sender As Object, ByVal e As System.EventArgs) Handles trackBar1.Scroll |