Click here to Skip to main content
Licence 
First Posted 29 Jul 2004
Views 48,066
Bookmarked 19 times

Multiple Matrices With ColorMatrix in C#

By | 29 Jul 2004 | Article
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.

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.

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.

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

About the Author

dcoolidge

Web Developer

United States United States

Member

.Net wannabe

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 5 PinmemberMember 434321323:56 22 Mar '11  
GeneralMost of this code can be optimised out PinmemberMikeDC16:18 19 Sep '06  
GeneralRe: Most of this code can be optimised out Pinmemberdcoolidge7:01 20 Sep '06  
GeneralDrawImage Performace issue Pinmemberms44cn22:04 5 Sep '06  
GeneralRe: DrawImage Performace issue Pinmemberdcoolidge11:07 7 Sep '06  
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    Rant Rant    Admin Admin   

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120529.1 | Last Updated 30 Jul 2004
Article Copyright 2004 by dcoolidge
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid