Performing Color Transformation Operations in C# GDI+

With the basic idea of color transformation matrices in mind, in this second installment of a three-part series, we will delve into the four types of operations of color transformation matrices in GDI+, as well as give the related samples.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 3
July 23, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

Translating Color Operation

In reality, a translation is the addition calculation necessary to add a value to one or more of the four color components (i.e. red, green, blue, and alpha). The color transformation matrix entries that represent translations are given in the following Figure 1.


Figure 1-the transformation matrix corresponding to translating color operation

The components colored gray in Figure 1 represent the elements concerned with translating color operation. Now, let's take a look at an example that performs the translating color operation.

The following example constructs an Image object from the given file named ColorInput.bmp. Then the code adds 0.5 to the red component of each pixel in the image. The transformed image is drawn alongside the original image.

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);

//load the original image

Bitmap image = new Bitmap("ColorInput.bmp");

ImageAttributes imageAttributes = new ImageAttributes();

int width = image.Width;

int height = image.Height;

//define a color transformation matrix

float[][] colorMatrixElements=

{

new float[]{1.0f, 0.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 1.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 1.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.5f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix=new ColorMatrix(colorMatrixElements);

//enable the color transformation matrix

imageAttributes.SetColorMatrix(colorMatrix,

ColorMatrixFlag.Default,ColorAdjustType.Bitmap);

//render the source image

graphics.DrawImage(image, 0, 0);

//use the color transformation matrix to render the new target image

graphics.TranslateTransform(width+10,0);

graphics.DrawImage(image, new Rectangle(0, 0, width, height),

0, 0,width, height,GraphicsUnit.Pixel,imageAttributes);

The following Figure 2 shows the related running-time snapshot, with the original image on the left and the transformed one on the right.

Figure 2-the running-time snapshot for the translating color operation

From Figure 2, we can easily see that after the translating color transformation, the previous black color is changed into a catsup red color, and the other colors in Figure 2 also change accordingly. Why?

From the above code we can see that the saturation of the red component is set to 0.5 in the color transformation matrix. Take the black color as an example; its related color transformation matrix can be figured out using the following matrix transformation (A=0.5 x 255) in Figure 3.


Figure 3-the color transformation for the black color

In the matrix transformation in Figure 3, the RGB value of black (0, 0, 0) is changed into (128, 0, 0) (i.e. the RGB value of a catsup red color) after the transformation. In the same way, you can figure out the RGBs of all the rest of the colors after the color transformation.

Next, let's shift our attention to another important color calculation-scaling transformation.

Scaling Color Operation

A scaling transformation corresponds to the matrix multiplication. During the scaling operation, each of the four color components of a color is multiplied by a specified number. The following Figure 4 gives the associated transformation matrix.


Figure 4-the color matrix entries that represent scaling transformation

It's worth noticing that the scaling transformation will not influence the color saturation.

Now, let's also construct a sample to see how the scaling transformation will affect the changing colors. The following example constructs two Image objects from the original head.bmp file. Figure 5 gives the related running-time snapshot of the sample.


Figure 5-the running-time snapshot of the scaling transformation sample

Next, let's do some research into the source code, as listed below.

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);


//load the original image

Bitmap image = new Bitmap("head.bmp");

ImageAttributes imageAttributes = new ImageAttributes();

int width = image.Width;

int height = image.Height;


//define the first color transformation matrix

float[][] colorMatrixElements=

{

new float[]{0.5f, 0.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.5f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.5f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix=new ColorMatrix(colorMatrixElements);

//define the second color transformation matrix

float[][] colorMatrixElements2=

{

new float[]{0.5f, 0.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.5f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 500.50f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix2 = new ColorMatrix(colorMatrixElements2);


//enable the first color transformation matrix

imageAttributes.SetColorMatrix(

colorMatrix,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);


//render the source image

graphics.DrawImage(image, 0, 0);


//use the color transformation matrix to render the new target image

graphics.TranslateTransform(width+10,0);

graphics.DrawImage(

image,

new Rectangle(0, 0, width, height),

0, 0,

width, height,GraphicsUnit.Pixel,

imageAttributes);


//clear up the former color transformation

imageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);

//reload another color transformation matrix colorMatrix2

imageAttributes.SetColorMatrix(

colorMatrix2,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);


//use matrix colorMatrix2 to adjust the color and render the transformed image

graphics.TranslateTransform(width+10,0);

graphics.DrawImage(

image,

new Rectangle(0, 0, width, height),

0, 0,

width, height,GraphicsUnit.Pixel,

imageAttributes);

Apparently, here we have leveraged two color matrices to perform the scaling operation. The first three elements in the main diagonal in the first matrix are all 0.5, which indicates the red, green, and blue components of each pixel in the image are evenly scaled down 50 percent, which results in the bright colors in the image being turned into gray. Take the red component for example. The color matrix transformation with the red component is achieved through the following matrix computation in Figure 6.


Figure 6-the red component related matrix transformation

The matrix transformation above indicates that the red color is changed into gray (127, 0, 0, 0) after the transformation.

Moreover, we have defined the second transformation matrix, colorMatrix2. In contrast to the first matrix, the third element in the main diagonal in this matrix becomes 500.5, which means that the blue component is multiplied by 500.5 during the transformation. What on earth will this result in?

As you may imagine, the third picture in Figure 5 is the output result through the colorMatrix2 matrix's associated transformation. Note that in the color matrix calculation of GDI+ when the result of a color component is greater than 1, the factual saturation of the special color only utilizes the fractional part. For example, 500.5 x 1=500.5, and the fractional part of 500.5 is 0.5. Retaining only the fractional part ensures that the result is always in the interval [0, 1].

Next, let's move to another color transformation-rotating color operation.

Rotating Color Operation

In the preceding discussion, since we are always taking a four-dimensional color space to represent a color component, it is rather difficult to visualize the color rotating operation. However, suppose we put aside the alpha component (e.g. fully opaque); we can make it easier to visualize the color rotation with the three basic color components (R, G, B) left. In fact, we can visualize a three-dimensional color space with red, green, and blue axes as shown in Figure 7.


Figure 7-the color rotation in a three-dimensional color space

A color can be thought of as a point in 3-D space. For example, the point (1, 0, 0) in space represents the color red, the point (0, 1, 0) in space represents the color green, and point (0, 0, 1) stands for the blue.


The following illustration shows what it means to rotate the color (1, 0, 0) through an angle of 60 degrees in the Red-Green plane. Rotation in a plane parallel to the Red-Green plane can be thought of as rotation around the blue axis, as is shown in Figure 8.


Figure 8-rotate the color (1, 0, 0) through an angle of 60 degrees in the Red-Green plane

Next, let's take a look at a related example. In this example we are to perform three rotations: the red color rotation around the blue color, green around red, and blue around red, and all through the equal angle of 90 degree. Figure 9 illustrates the corresponding running-time snapshot.


Figure 9-one color rotates around another all through the equal angle of 90 degree

Now, let's start to examine the programming behind this. First, draw the original image:

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);


//load the image

Bitmap image=new Bitmap("Colorinput.bmp");

int width = image.Width;

int height = image.Height;

float degrees = 90;

//change the angle into the radian

double r = degrees * Math.PI/ 180.0f;

ImageAttributes imageAttributes=new ImageAttributes();

//render the source image

graphics.DrawImage(image, 0, 0);

Next, we make the red color rotate around the blue color (the image at the top right corner), which is achieved through the code listed below:

//the red color rotates around the blue one

float[][] colorMatrixElements=

{

new float[]{(float)Math.Cos(r), (float)Math.Sin(r), 0.0f, 0.0f, 0.0f},

new float[]{-(float)Math.Sin(r), (float)Math.Cos(r), 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 1.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix=new ColorMatrix(colorMatrixElements);


//start to use the color transformation matrix to output the new image(R->B)

graphics.TranslateTransform(width+10,0);

//perform the R->B color transformation

imageAttributes.SetColorMatrix(

colorMatrix,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);

graphics.DrawImage(

image,

new Rectangle(0, 10, width, height),

0, 0,width,height,

GraphicsUnit.Pixel,

imageAttributes);

Next, we make the green color rotate around the red color (the image at the bottom left corner), which is achieved in the following manner:

//first clear the previously used color matrix

imageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);


//reload another matrix Matrix2

//the green color rotates around the red one

float[][] colorMatrixElements2=

{

new float[]{1, 0, 0.0f, 0.0f, 0.0f},

new float[]{0, (float)Math.Cos(r), (float)Math.Sin(r), 0.0f, 0.0f},

new float[]{0.0f, -(float)Math.Sin(r), (float)Math.Cos(r), 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix2=new ColorMatrix(colorMatrixElements2);


imageAttributes.SetColorMatrix(

colorMatrix2,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);


//render on the second line

graphics.ResetTransform();

graphics.TranslateTransform(0,height+10);

graphics.DrawImage(image,

new Rectangle(0, 0, width, height),

0, 0,width, height,GraphicsUnit.Pixel,

imageAttributes);

Next, let's continue to take a look at the third case. The blue color rotates around the red color (the image at the bottom right corner), as is shown below:

//again first clear the already-used color matrix

imageAttributes.ClearColorMatrix(ColorAdjustType.Bitmap);

//the blue color rotates around the red one

//first define the related rotation matrix

float[][] colorMatrixElements3=

{

new float[]{(float)Math.Cos(r), 0, -(float)Math.Sin(r), 0.0f, 0.0f},

new float[]{0, 1, 0.0f, 0.0f, 0.0f},

new float[]{(float)Math.Sin(r), 0, (float)Math.Cos(r), 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix3 =new ColorMatrix(colorMatrixElements3);


//reload another matrix Matrix3

imageAttributes.SetColorMatrix(

colorMatrix3,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);

graphics.TranslateTransform(width+10,0);

graphics.DrawImage(

image,

new Rectangle(0, 0, width, height),

0, 0,

width, height,GraphicsUnit.Pixel,

imageAttributes);

As is illustrated in the above Figure 9, we can see distinct influences upon the color information with the three different color rotations. The background in Figure 9 is white, through which we can make certain the basic feature of the color rotation. When we make the red circle around the blue, the original background color (255, 255, 255) is changed into color (0, 255, 255), i.e. when rotating the red color the red component will change after the rotation. Take the above case for example, when the rotating angle equals 90 degrees, the rotated color after the rotation will disappear completely. With this logic in mind, you can  make other adjustment to the rotating angle to see the corresponding different effects.

Finally, let's look into the last kind of color transformation-shearing color.

Shearing Color Operation

Shearing increases or decreases a color component by an amount proportional to another color component. For example, consider the transformation where the red component is increased by one half the value of the blue component. Under such a transformation, the color (0.2, 0.5, 1) would become (0.7, 0.5, 1). The new red component is 0.2 + (1/2)(1) = 0.7. Herein, we say that the red component is a map to the blue component; or in another way, that the blue component is sheared to the red one. Figure 10 shows the color relations in the shearing color operation.


Figure 10-the color components in gray join in the shearing transformation

Now, let's continue to take a look at the related sample. The following example constructs an Image object from the file Colorinput.bmp. Then the code applies the shearing transformation described in the preceding paragraph to each pixel in the image.

Graphics graphics=this.CreateGraphics();

graphics.Clear(Color.White);

//load the image

Bitmap image=new Bitmap("Colorinput.bmp");

ImageAttributes imageAttributes=new ImageAttributes();

int width = image.Width;

int height = image.Height;

//define the color transformation matrix

float[][] colorMatrixElements=

{

new float[]{1.0f, 0.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.0f, 1.0f, 0.0f, 0.0f, 0.0f},

new float[]{0.5f, 0.0f, 1.0f, 0.0f, 0.0f},

new float[]{0.0f, 0.0f, 0.0f, 1.0f, 0.0f},

new float[]{ 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}

};

ColorMatrix colorMatrix=new ColorMatrix(colorMatrixElements);

//enable the color transformation matrix

imageAttributes.SetColorMatrix(

colorMatrix,

ColorMatrixFlag.Default,

ColorAdjustType.Bitmap);

//render the source image

graphics.DrawImage(image, 0, 0);

//use the color transformation matrix defined above to render new image

graphics.TranslateTransform(width+10,0);

graphics.DrawImage(image, new Rectangle(0, 0, width, height),

0, 0,width, height,GraphicsUnit.Pixel,imageAttributes);

In the code, the element at column 1 of row 3 of the color transformation matrix is set to 0.5, which means that during the shearing color transformation, all the increments of the red component are half of the blue component. The following illustration (Figure 11) shows the original image on the left and the newly-sheared one on the right.


Figure 11-the running-time snapshot for the shearing transformation

As is apparently shown in Figure 11, after the shearing operation the red components in the target image increase.

Summary

In this installment, we've thoroughly examined the four kinds of color operations(translating, scaling, rotating, and shearing) in GDI+ and come to realize that the four transformations are the fundamental operations of nearly all coloring support. In the third installment of this series, we will explore the color remapping support in GDI+, as well as try to achieve the effect of Photoshop-like color channel isolating via the color transformation matrices.

-DOWNLOAD SOURCE-

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 11 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials