Click here to Skip to main content
15,881,803 members
Articles / Programming Languages / C#
Article

Multiple Matrices With ColorMatrix in C#

Rate me:
Please Sign up or sign in to vote.
4.40/5 (10 votes)
29 Jul 2004 79.9K   1.6K   21   6
Using multiple matrices to manipulate an image.

Introduction

In my current job, I was creating a control that manipulated the brightness and contrast of an image. I didn't want to call Graphics.DrawImage more than once. The solution was to do a matrix multiply on the two matrices (brightness and contrast) before drawing the image. Just for fun, I included a picture of my daughter in the project...

The main part of the code I wanted to share was the matrices and the matrix multiplication.

C#
private void NewMatrices()
{
  // Initialize the matices;
  bm = new float[5][];
  cm = new float[5][];
  for (int i = 0; i < 5; i++)
  {
    bm[i] = new float[5];
    cm[i] = new float[5];
  }
  // Set the values of the brightness matrix
  float brightness = 0.2f;
  bm[0][0] = 1; bm[0][1] = 0; bm[0][2] = 0; bm[0][3] = 0; bm[0][4] = 0;
  bm[1][0] = 0; bm[1][1] = 1; bm[1][2] = 0; bm[1][3] = 0; bm[1][4] = 0;
  bm[2][0] = 0; bm[2][1] = 0; bm[2][2] = 1; bm[2][3] = 0; bm[2][4] = 0;
  bm[3][0] = 0; bm[3][1] = 0; bm[3][2] = 0; bm[3][3] = 1; bm[3][4] = 0;
  bm[4][0] = brightness; bm[4][1] = brightness;
  bm[4][2] = brightness; bm[4][3] = 1; bm[4][4] = 1;
  // Set the values of contrast matrix
  float contrast = 20f;
  float T = 0.5f * (1f - contrast);
  cm[0][0] = contrast; cm[0][1] = 0; cm[0][2] = 0; cm[0][3] = 0; cm[0][4] = 0;
  cm[1][0] = 0; cm[1][1] = contrast; cm[1][2] = 0; cm[1][3] = 0; cm[1][4] = 0;
  cm[2][0] = 0; cm[2][1] = 0; cm[2][2] = contrast; cm[2][3] = 0; cm[2][4] = 0;
  cm[3][0] = 0; cm[3][1] = 0; cm[3][2] = 0; cm[3][3] = 1; cm[3][4] = 0;
  cm[4][0] = T; cm[4][1] = T; cm[4][2] = T; cm[4][3] = 1; cm[4][4] = 1;
}

private float[][] Multiply(float[][] f1, float[][] f2)
{
  float[][] X = new float[5][];
  for (int d = 0; d < 5; d++)
    X[d] = new float[5];
  int size = 5;
  float[] column = new float[5];
  for (int j = 0; j < 5; j++)
  {
    for (int k = 0; k < 5; k++)
    {
      column[k] = f1[k][j];
    }
    for (int i = 0; i < 5; i++)
    {
      float[] row = f2[i];
      float s = 0;
      for (int k = 0; k < size; k++)
      {
        s += row[k] * column[k];
      }
      X[i][j] = s;
    } 
  }
  return X;
}

Another interesting part of the code is the DrawImage function. It takes in a matrix (i.e., float[][]) and draws an image with that matrix.

C#
private void DrawImage(float[][] Matrix)
{
  ColorMatrix m = new ColorMatrix(Matrix);
  ImageAttributes ia = new ImageAttributes();
  ia.SetColorMatrix(m);
  Rectangle rMy = new Rectangle(0,0,i.Width, i.Height);
  Bitmap bm = new Bitmap(i.Width, i.Height);
  Graphics g = Graphics.FromImage((Image)bm);
  g.Clear(Color.Black);
  g.DrawImage(i, rMy, 0, 0, i.Width, i.Height, 
                               GraphicsUnit.Pixel, ia);
  pictureBox1.Image = (Image)bm;
}

So now, we can call DrawImage with one of our matrices we created above, or use Multiply to combine them.

C#
DrawImage(cm);
DrawImage(bm);
DrawImage(Multiply(cm,bm);

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
.Net wannabe

Comments and Discussions

 
SuggestionA cleaner code - more versatile Pin
Elmue31-Aug-14 11:09
Elmue31-Aug-14 11:09 
GeneralMy vote of 5 Pin
Member 434321322-Mar-11 23:56
Member 434321322-Mar-11 23:56 
GeneralMost of this code can be optimised out Pin
MikeDC19-Sep-06 16:18
MikeDC19-Sep-06 16:18 
GeneralRe: Most of this code can be optimised out Pin
dcoolidge20-Sep-06 7:01
dcoolidge20-Sep-06 7:01 
GeneralDrawImage Performace issue Pin
ms44cn5-Sep-06 22:04
ms44cn5-Sep-06 22:04 
GeneralRe: DrawImage Performace issue Pin
dcoolidge7-Sep-06 11:07
dcoolidge7-Sep-06 11:07 
As opposed to what my article is saying, I did end up doing two Graphics.DrawImage. The first DrawImage clips the image to the display. The next DrawImage applies the matrix. If your display area is small this works pretty well. The following code shows how.

// Draw the clipped image
Rectangle myRec = new Rectangle(0, 0, viewEndX - viewStartX, viewEndY - viewStartY);

Bitmap bm = new Bitmap(viewEndX - viewStartX, viewEndY - viewStartY);

Graphics g = Graphics.FromImage((Image)bm);

g.DrawImage(bigImage, myRec, viewStartX, viewStartY,
viewEndX, viewEndY,
GraphicsUnit.Pixel);

// Apply the filter to the clipped image.
Bitmap bm2 = new Bitmap(viewEndX - viewStartX, viewEndY - viewStartY);
Graphics g2 = Graphics.FromImage((Image)bm2);

System.Drawing.Imaging.ImageAttributes m_ia = new ImageAttributes();

float[][] brightness = GetBrightnessMatrix(m_Brightness, m_Brightness, m_Brightness, 1);
float[][] contrast = GetContrastMatrix(m_Contrast);

float[][] matrix = Multiply(brightness, contrast);
System.Drawing.Imaging.ColorMatrix cm = new System.Drawing.Imaging.ColorMatrix(matrix);
m_ia.SetColorMatrix(cm);

g2.DrawImage(bm, myRec, 0, 0, PIC_WIDTH, PIC_HEIGHT, GraphicsUnit.Pixel , m_ia);

// Now the image is in bm2

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.