Introduction
This article discusses color operations on digital images, using the new ColorMatrix
class provided by GDI+. The ColorMatrix
is a welcome addition to the GDI library, especially with the increase in demand of digital imaging applications, as more and more consumer products are made available. This class, as well as many other new GDI classes, provide more control to the developer and reduce dependence on 3rd party applications such as LEAD tools, and others. Some basic knowledge of matrix operations (multiplication, addition, etc), the RGBA colorspace and GDI+ is assumed.
Background
ColorMatrix
operations are performed in the RGBA colorspace (red, green, blue, alpha). A ColorMatrix
consists of a 5x5 matrix, with color values normalized to 1 for full intensity (255 -> 1.0). You might expect the matrix to be 4x4 ( [R, G, B, A] ), which would be sufficient if we only needed to perform linear transformations (multiplication: scaling, rotation, etc). However, one of the most frequent color manipulations, color adjustment, requires adding color values. This is a non-linear operation, referred to as a translation. Adding a 5th element to the color vector ( [R, G, B, A, w] ) combines these two operations, linear and non-linear, into a single operation called an affine transformation. The 5th element of the color vector is simply a dummy element, always with a value of 1, which only serves to allow a translation (addition) of the color vector.
The example below scales the color vector [255, 128, 102, 255] by .5 and then adds a value of 26 to the R, G and B components, leaving the A component at full intensity. Remember that the component values are normalized, with full intensity, 255, equal to 1.0 (values have been rounded to the nearest tenth). Also notice the addition of the 5th element to the color vector, which is simply ignored in the resultant color vector.
This takes the color and transforms it to .
Now that we've covered the basic principle of the ColorMatrix
and it's operations on color vectors, we can start exploring some practical uses.
Applying the code
Applying a ColorMatrix
to an image is quite simple. You must first associate a ColorMatrix
object with an ImageAttributes
object. Then you simply pass the ImageAttributes
object as a parameter to the Graphics.DrawImage
method.
Color adjustment is one of the more common color operations applied to digital images. The code to do this might look as follows:
Public Function translate(ByVal img As Image, ByVal red As Single, _
ByVal green As Single, ByVal blue As Single, _
Optional ByVal alpha As Single = 0) As Boolean
Dim sr, sg, sb, sa As Single
sr = red / 255
sg = green / 255
sb = blue / 255
sa = alpha / 255
dim New ColorMatrix(New Single()() _
{New Single() {1, 0, 0, 0, 0}, _
New Single() {0, 1, 0, 0, 0}, _
New Single() {0, 0, 1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {sr, sg, sb, sa, 1}})
Return draw_adjusted_image(img, cm)
End Function
Private Function draw_adjusted_image(ByVal img As Image, _
ByVal cm As ColorMatrix) As Boolean
Try
Dim bmp As New Bitmap(img)
Dim imgattr As New ImageAttributes()
Dim rc As New Rectangle(0, 0, img.Width, img.Height)
Dim g As Graphics = Graphics.FromImage(img)
imgattr.SetColorMatrix(cm)
g.DrawImage(bmp, rc, 0, 0, img.Width, img.Height, _
GraphicsUnit.Pixel, imgattr)
g.Dispose()
Return True
Catch
Return False
End Try
End Function
Conversion to grayscale is another common conversion. 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.
Public Function grayscale(ByVal img As Image) As Boolean
Dim cm As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {0.299, 0.299, 0.299, 0, 0}, _
New Single() {0.587, 0.587, 0.587, 0, 0}, _
New Single() {0.114, 0.114, 0.114, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
Return draw_adjusted_image(img, cm)
End Function
The code below creates a digital negative:
Public Function negative(ByVal img As Image) As Boolean
Dim cm As ColorMatrix = New ColorMatrix(New Single()() _
{New Single() {-1, 0, 0, 0, 0}, _
New Single() {0, -1, 0, 0, 0}, _
New Single() {0, 0, -1, 0, 0}, _
New Single() {0, 0, 0, 1, 0}, _
New Single() {0, 0, 0, 0, 1}})
Return draw_adjusted_image(img, cm)
End Function
Color channel separations, alpha transparency adjustment, image toning (Sepia, etc) are just a few more common operations that can be easily performed with a ColorMatrix
.