HOME | SIGN UP | ACCOUNT | SUBSCRIBE | TROUBLESHOOTING | LOGIN
News · Meetings · Jobs · Downloads · Universal Thread articles · Web articles · Conference coverages · Consultants · Blogs · FAQ · User groups · Photos · Videos

Special effects on images with new GDIPlus-X classes - Part 2

Cesar Chalom
Cesar is an independent software developer. He is an active member of brazilian Visual FoxPro groups.

In the first part of this article, I showed how we can apply some interesting effects to images with the use of color matrices the new GdiPlus-X library. In this article, I’ll continue showing some interesting applications of color matrices.

IMPORTANT:

All samples shown in this article use the new GDIPlus-X library, that is still in ALPHA version, but is already stable and reliable to do the majority of GDI+ tasks. So, before you start, please download the latest stable release from Codeplex: http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX

In that article, I used the example below to apply a color matrix to get the gray scale version of an image:

_SCREEN.AddProperty("System", NEWOBJECT("xfcSystem", LOCFILE("system.vcx","vcx"))) 
LOCAL loBitmap AS xfcBitmap
LOCAL loNewBitmap AS xfcBitmap
LOCAL loGfx AS xfcGraphics
LOCAL loAttr AS xfcImageAttributes
LOCAL loClrMatrix AS xfcColorMatrix
LOCAL loRect AS xfcRectangle 

WITH _SCREEN.System.Drawing 
   loBitmap = .Bitmap.New(GETPICT())
   loNewBitmap = .Bitmap.New(loBitmap.Width, loBitmap.Height) 
   * Create a Graphics object to be able to draw in the bitmap
   loGfx = .Graphics.FromImage(loNewBitmap) 
   loClrMatrix = .Imaging.ColorMatrix.New( ;
	0.33, 0.33, 0.33, 0.0, 0.0, ;
	0.33, 0.33, 0.33, 0.0, 0.0, ;
	0.33, 0.33, 0.33, 0.0, 0.0, ;
	0.0 , 0.0 , 0.0 , 1.0, 0.0, ;
	0.0 , 0.0 , 0.0 , 0.0, 1.0) 
   loAttr = .Imaging.ImageAttributes.New()
   loAttr.SetColorMatrix(loClrMatrix)
   loRect = .Rectangle.New(0,0,loBitmap.Width, loBitmap.Height)
   loGfx.DrawImage(loBitmap, loRect, loRect, .GraphicsUnit.Pixel, loAttr) 
   loNewBitmap.Save("c:\NewImage.png", .Imaging.ImageFormat.Png)
   * Show the transformed image
   RUN /N explorer.exe c:\NewImage.png
ENDWITH
RETURN

IDENTITY MATRIX

It is very important to understand what each position in the color matrix means. The identity color matrix is a matrix that when applied to any image will return exactly the same original picture. Depending on the desired effect, we will apply changes in some specific positions in the identity matrix. So, if you change the contents of “loClrMatrix” to the matrix below, the resulting image will be exactly the same as the original.

loClrMatrix = .Imaging.ColorMatrix.New( ;
   1, 0, 0, 0, 0, ;
   0, 1, 0, 0, 0, ;
   0, 0, 1, 0, 0, ;
   0, 0, 0, 1, 0, ;
   0, 0, 0, 0, 1) 

GRAYSCALE 1

Conversion to gray scale is another common conversion. Below is the commonest gray scale matrix, which converts each pixel color to the average between the Red, Green and Blue channels.

loClrMatrix = .Imaging.ColorMatrix.New( ;
   0.33, 0.33, 0.33, 0.0, 0.0, ;
   0.33, 0.33, 0.33, 0.0, 0.0, ;
   0.33, 0.33, 0.33, 0.0, 0.0, ;
   0.0 , 0.0 , 0.0 , 1.0, 0.0, ;
   0.0 , 0.0 , 0.0 , 0.0, 1.0) 

GRAYSCALE 2

Grayscale values are determined by calculating the luminosity of a color, which is a weighted average of the R, G and B color components. The average is weighted according to the sensitivity of the human eye to each color component. The weights used here are as given by the NTSC (North America Television Standards Committee) and are widely accepted.

The effective luminance of a pixel is calculated with the following formula: C = 0.3 RED + 0.59 GREEN + 0.11 BLUE. So, using the color matrix below we will obtain another gray scale version of the image, more familiar with NTSC pattern. Bob Powell explains this operation with detail: http://www.bobpowell.net/grayscale.htm

loClrMatrix = .Imaging.ColorMatrix.New( ;
   0.30, 0.30, 0.30, 0.0, 0.0, ;
   0.59, 0.59, 0.59, 0.0, 0.0, ;
   0.11, 0.11, 0.11, 0.0, 0.0, ;
   0.0 , 0.0 , 0.0 , 1.0, 0.0, ;
   0.0 , 0.0 , 0.0 , 0.0, 1.0) 

Note that using this technique the result is slightly different from the one using the prior technique.

CONTRAST

According to Bob Powell, “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 color matrix that looks like the one shown below.

loClrMatrix = .Imaging.ColorMatrix.New( ;
    C,   0,   0,  0,  0, ;
    0,   C,   0,  0,  0, ;
    0,   0,   C,  0,  0, ;
    0,   0,   0,  1,  0, ;
   .1,  .1,  .1,  0,  1)
The variable “C” means the contrast scale component. Use the value “1” to keep the contrast unchanged. “0” will clear

In the sample below I used 1.40 for the C variable, that means an increase of 40% in contrast.

BRIGHTNESS

That’s very simple to change the brightness too. According to Bob Powell, “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 color matrix that looks like the one shown below.

loClrMatrix = .Imaging.ColorMatrix.New( ;
   1,  0,  0,  0,  0, ;
   0,  1,  0,  0,  0, ;
   0,  0,  1,  0,  0, ;
   0,  0,  0,  1,  0, ;
   B,  B,  B,  0,  1)
The variable “B” means the brightness scale component. The brightness value ranges from -1 to +1. Use a zero value for no brightness change. In the sample below I used -0.20 for the B variable, that means a decrease of 20% in brightness.

NEGATIVE

For a negative image, we just need to set all the contrast main values to -1

loClrMatrix = .Imaging.ColorMatrix.New( ;
   -1,  0,  0,  0,  0, ;
   0 , -1,  0,  0,  0, ;
   0 ,  0, -1,  0,  0, ;
   0 ,  0,  0,  1,  0, ;
   0 ,  0,  0,  0,  1)

There is a known problem related by BobPowell at http://www.bobpowell.net/negativeimage.htm that occurs “when an image contains colors that have zero values in any of the RGB triplet bytes. The matrix multiplies the color triplet byte values by the values in it's matrix and so zero multiplied by -1 is still zero. This makes the inverse of primary colors such as red or blue look black. To correct this problem it is necessary to ensure that none of the triplet values in an image are zero. This can be accomplished using a compression matrix that compresses the gamut very slightly and shifts the whole range up a little. The following code shows such a compression matrix. The values are chosen to shift the value of each byte in the image into the range 1-255 as opposed to the original range 0-255.”

Having this, we need to apply a slight modification in our color matrix, specifically at the positions 40,41 and 42 in order to make a slight compensation on the image.

loClrMatrix = .Imaging.ColorMatrix.New( ;
   -1,  0,  0,  0,  0, ;
   0 , -1,  0,  0,  0, ;
   0 ,  0, -1,  0,  0, ;
   0 ,  0,  0,  1,  0, ;
   1 ,  1,  1,  0,  1)
And the resulting image is totally satisfactory.

SATURATION

According to the Wikipedia http://en.wikipedia.org/wiki/Saturation_(color_theory) , the Saturation “is the intensity of a specific hue. A highly saturated hue has a vivid, intense color, while a less saturated hue appears more muted and grey. With no saturation at all, the hue becomes a shade of grey. Saturation is one of three components of the HSL color space and the HSV color space.”

We can also change the saturation of an image applying a specific color matrix.

The “S” variable ranges from 0 to 4, where zero value returns a grayscale version of the image; 1 means no change.

“SCompl” is the saturation complement
“SR”, “SG” and “SB” are the saturation complements for the red, green and blue channels

Bob Powell again provides valuable information on this subject. http://www.bobpowell.net/imagesaturation.htm

LOCAL S, SCompl, SR, SG, SB
S = 0 && Greyscale
S = 4 && Saturated image
SCompl = 1 - S
SR = 0.3086 * SCompl
SG = 0.6094 * SCompl
SB = 0.0820 * SCompl
loClrMatrix = .Imaging.ColorMatrix.New( ;
   (SR+S), SR    , SR    , 0, 0, ;
   SG    , (SG+S), SG    , 0, 0, ;
   SB    , SB    , (SB+S), 0, 0, ;
   0     , 0     , 0     , 1, 0, ; 
   0     , 0     , 0     , 0, 1)

Using S = 0 we get the gray scale version:

Using S = 2 we obtain a color saturated image of 100%

COLOR SCALE TRANSFORMATIONS

To change a single color is very easy too. If we want to change one specific color channel, we can just change the variables lnRed, lnGreen and lnBlue. These are the same values that we used for the contrast transformation. If you use the same values for the red, green and blue channels you’ll obtain the same results. lnRed, lnGreen and lnBlue usually range from 0 to 1.

loClrMatrix = .Imaging.ColorMatrix.New( ;
   lnRed, 0      , 0     , 0, 0, ;
   0    , lnGreen, 0     , 0, 0, ;
   0    , 0      , lnBlue, 0, 0, ;
   0    , 0      , 0     , 1, 0, ; 
   0.1  , 0.1    , 0.1   , 0, 1)
in the sample below I used lnRed = 1.2 , lnGreen = 0.8 and lnBlue = 0, that means an increase of 20% in Red, decrease of 20% in green and eliminating totally the blue channel.

APPLYING ALL EFFECTS AT THE SAME TIME

The color matrix is applied to the image using the Graphics.Drawimage function, with the image attributes object as a parameter. So, if we want to apply more than one effect at the same time to na image, one way would be to call Graphics.DrawImage for every color matrix. That would be a very process and time consuming operation.

The solution is to do a matrix multiply on two matrices (eg. Saturation and brightness) before drawing the image. The matrices multiplication is not so obvious, for this task you can look at some of your mathematics books from school times, or check this link from Mathworld http://mathworld.wolfram.com/MatrixMultiplication.html . The Matrix multiplication is much faster than setting a new color matrix and redrawing the image. Microsoft did not include a Matrix multiply function in gdiplus.dll or in the .NET original classes.

It was very easy to decide to add the Multiply function to the ColorMatrix class. You can use it this way:

loNewMatrix = loMatrix1.Multiply(loMatrix1, loMatrix2)
The sample below applies a color matrix resulting from the multiplication of the ColorScale and Brightness color matrices to an image. It increases the red component in 40%, decreases the blue in 50%, and increases the brightness at 20% in one time.

WITH _SCREEN.System.Drawing 
   lnRed   = 1.4  && increase of 40%
   lnGreen = 1    && keep the same
   lnBlue  = 0.5  && decrease in 50%
   B = 0.2  && increase brightness in 20%
   loBitmap = .Bitmap.New(GETPICT())
   loNewBitmap = .Bitmap.New(loBitmap.Width, loBitmap.Height) 
   * Create a Graphics object to be able to draw in the bitmap
   loGfx = .Graphics.FromImage(loNewBitmap) 
   loBright = .Imaging.ColorMatrix.New( ;
 	1, 0, 0, 0, 0, ;
	0, 1, 0, 0, 0, ;
	0, 0, 1, 0, 0, ;
	0, 0, 0, 1, 0, ;
	B, B, B, 0, 1) 
   loColors = .Imaging.ColorMatrix.New( ;
	lnRed, 0      , 0     , 0, 0, ;
	0    , lnGreen, 0     , 0, 0, ;
	0    , 0      , lnBlue, 0, 0, ;
	0    , 0      , 0     , 1, 0, ;
	0    , 0      , 0     , 0, 1) 

   loNewMatrix = loBright.Multiply(loBright, loColors)
   loAttr = .Imaging.ImageAttributes.New()
   loAttr.SetColorMatrix(loNewMatrix)
   loRect = .Rectangle.New(0,0,loBitmap.Width, loBitmap.Height)
   loGfx.DrawImage(loBitmap, loRect, loRect, .GraphicsUnit.Pixel, loAttr) 
   loNewBitmap.Save("c:\NewImage.png", .Imaging.ImageFormat.Png)
   * Show the transformed image
   RUN /N explorer.exe c:\NewImage.png
ENDWITH
In the sample folder of the Gdiplus-X classes we included a sample form called “ColorMatricesAdvanced.scx”. Using that form you can apply changes to contrast, brightness, saturation, and hue to any image. That form applies 9 colormatrices at a time using the color matrix multiplication technique. The main code stays at the CreateColorMatrix method of the form.

The original picture stays on the left. To obtain the image on the right I first reduced the blue channel of the image to zero. That produced a very cool effect, converting the flowers to yellow. Then I changed the “Hue2” slide bar, to make the flowers orange like.

There are many more cool effects that we can obtain using color matrices. On the web you will find many interesting samples, originally prepared for C or Visual Basic. This is not a problem any more, because the GDIPlus-X classes are compatible with most of those published codes.

Hope you enjoy !

RELATED LINKS

Bob Powell's GDI+ FAQS http://www.bobpowell.net

How to: Use a Color Matrix to Transform a Single Color http://msdn2.microsoft.com/en-us/library/6tf7sa87.aspx

Article: ColorMatrix Basics - Simple Image Color Adjustment by Michael Combs http://www.codeproject.com/vb/net/colormatrix.asp?df=100&forumid=14842&exp=0&select=1072852&tid=1072852#xx1072852xx

Article: GDI+ Graphics Transformation - By Mahesh Chand. http://www.robert.to/csharp/csharp4.html

More articles from this author

NoTitleDate
1.Advanced pie charts with GDI+June 2006
2.Multiframe Images with GDI+May 2006
3.Saving and retrieving metadata information from your pictures with GDI+April 2006
4.Special effects on images with new GDIPlus-X classes - Part 1August 2006

Copyright © 1993 - 2014 Level Extreme Inc., All Rights Reserved · Telephone: 506-783-9007 Email: info@universalthread.com · Privacy & Security · Copyright · Terms & Conditions