Fun with Color Matrices

I just had to make a quick little article on the Color Matrix, since they are such fun!

Of course, you all are probably familiar with the Transparent Picture matrix.
    Dim GFX As Graphics, Bmp As Bitmap, ColorMx As Imaging.ColorMatrix, Ia As Imaging.ImageAttributes

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GFX = Me.CreateGraphics()  ''Draws to the form.
        Bmp = New Bitmap("C:\pachinko.gif")   'Picture of a flying pachinko ball weapon.
        Ia = New Imaging.ImageAttributes    'Can set color matrices for us.
    End Sub

    Private Sub Btn4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn4.Click
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {1.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 1.0F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 1.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.4F, 1.0F}})
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)
    End Sub
This decreases the picture's visibility to 40%. The colors become [R, G, B, 0.4, dc] which means R, G, B are unchanged, the alpha channel, which measures opacity, becomes 40%, or 102, and we really don't care (dc) about the last term.
Among other useful matrices are the grayscaler. The gray scale component of an RGB color can be found by the expression:
N = 0.3 * R + 0.59 * G + 0.11 * B. This gray value, N, is to be the setting for R, G, and B, so that the final result is:
[ N , N , N , A , dc].
    Dim GFX As Graphics, Bmp As Bitmap, ColorMx As Imaging.ColorMatrix, Ia As Imaging.ImageAttributes

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GFX = Me.CreateGraphics()  ''Draws to the form.
        Bmp = New Bitmap("C:\pachinko.gif")   'Picture of a flying pachinko ball weapon.
        Ia = New Imaging.ImageAttributes    'Can set color matrices for us.
    End Sub

    Private Sub Btn6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn6.Click
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.3F, 0.3F, 0.3F, 0.0F, 0.0F}, _
            New Single() {0.58F, 0.58F, 0.58F, 0.0F, 0.0F}, _
            New Single() {0.11F, 0.11F, 0.11F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 0.0F}})
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)

    End Sub
And then there are less useful matrices, such as the psychedelic "purple hills" matrix (merely switches the green and blue channels):
    Dim GFX As Graphics, Bmp As Bitmap, ColorMx As Imaging.ColorMatrix, Ia As Imaging.ImageAttributes

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GFX = Me.CreateGraphics()  ''Draws to the form.
        Bmp = New Bitmap("C:\pachinko.gif")   'Picture of a flying pachinko ball weapon.
        Ia = New Imaging.ImageAttributes    'Can set color matrices for us.
    End Sub

    Private Sub Btn5_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn5.Click
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {1.0F, 0.0F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 1.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 1.0F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)

    End Sub
The grayscale-optimize for green, which gives everything a dated look:
    Dim GFX As Graphics, Bmp As Bitmap, ColorMx As Imaging.ColorMatrix, Ia As Imaging.ImageAttributes

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        GFX = Me.CreateGraphics()  ''Draws to the form.
        Bmp = New Bitmap("C:\pachinko.gif")   'Picture of a flying pachinko ball weapon.
        Ia = New Imaging.ImageAttributes    'Can set color matrices for us.
    End Sub

    Private Sub Btn6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn6.Click
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.0F, 0.3F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.58F, 0.58F, 0.58F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.11F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)

    End Sub
In addition, you can specify grayscales other than gray, such as a blue scale, a green scale (makes an excellent night-vision), or a sepia scale (which gets you those olden photograph looks).
Say that you have a color named C and you want to convert the picture to this color scale.
The formula itself is based on two color matrices being multipled together.
Fortunately, it can be simplified by taking the tracks of the color, dividing them by 255 of course, and then...
multiplying the resulting R value to everything in the first column, the G value to everything in the second, and the B value to everything in the third.
So, for instance, blue scale (which is quite dark):
The color is [ 0, 0, 255], divided by 255 is [0F, 0F, 1F]. The color matrix becomes:
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.3F * 0F, 0.3F * 0F, 0.3F * 1F, 0.0F, 0.0F}, _
            New Single() {0.58F * 0F, 0.58F * 0F, 0.58F * 1F, 0.0F, 0.0F}, _
            New Single() {0.11F * 0F, 0.11F * 0F, 0.11F * 1F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})

'or (simplified) 

        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.0F, 0.0F, 0.3F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.58F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.11F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
For green scale, the color is [ 0, 255, 0]. divided by 255 is [0F, 1F, 0F]. The color matrix becoming:
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.3F * 0F, 0.3F * 1F, 0.3F * 0F, 0.0F, 0.0F}, _
            New Single() {0.58F * 0F, 0.58F * 1F, 0.58F * 0F, 0.0F, 0.0F}, _
            New Single() {0.11F * 0F, 0.11F * 1F, 0.11F * 0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})

'or (simplified) 

        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.0F, 0.3F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.59F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.11F, 0.0F, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
Or, codewise, this can be accomplished in a simpler manner:
    Private Sub Btn6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn6.Click
        Dim C As Color, Rc, Gc, Bc As Single
        'C is the color that our picture will be scaled to.
        C = Color.Red
        Rc = C.R / 255.0F
        Gc = C.G / 255.0F
        Bc = C.B / 255.0F
        'All values must be divided by 255 by virtue of the color matrix.
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.3F * Rc, 0.3F * Gc, 0.3F * Bc, 0.0F, 0.0F}, _
            New Single() {0.59F * Rc, 0.59F * Gc, 0.59F * Bc, 0.0F, 0.0F}, _
            New Single() {0.11F * Rc, 0.11F * Gc, 0.11F * Bc, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
        'R multiplies the first column, G the second, and B the third.
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)

    End Sub
Try SandyBrown as the scaling color. Also, the original grayscale is based on white as the scaling color, so if C = Color.White, you'll just get a grayscale.
If you wanted the grayscale to actually be based on gray [128, 128, 128], change the
/ 255.0F
that divides all three color tracks to
/ 128.0F
which is approximately multiplying the color tracks by 2, bumping Gray into the [ 1F, 1F, 1F] position formerly occupied by White.
    Private Sub Btn6_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Btn6.Click
        Dim C As Color, Rc, Gc, Bc As Single
        'C is the color that our picture will be scaled to.
        C = Color.SandyBrown
        Rc = C.R / 128.0F
        Gc = C.G / 128.0F
        Bc = C.B / 128.0F
        'All values must be divided by 255 by virtue of the color matrix.
        ColorMx = New Imaging.ColorMatrix(New Single()() { _
            New Single() {0.3F * Rc, 0.3F * Gc, 0.3F * Bc, 0.0F, 0.0F}, _
            New Single() {0.59F * Rc, 0.59F * Gc, 0.59F * Bc, 0.0F, 0.0F}, _
            New Single() {0.11F * Rc, 0.11F * Gc, 0.11F * Bc, 0.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 1.0F, 0.0F}, _
            New Single() {0.0F, 0.0F, 0.0F, 0.0F, 1.0F}})
        'R multiplies the first column, G the second, and B the third.
        Ia.SetColorMatrix(ColorMx)
        GFX.DrawImage(Bmp, New Rectangle(64, 0, Bmp.Width, Bmp.Height), 0, 0, Bmp.Width, Bmp.Height, GraphicsUnit.Pixel, Ia)
        'Now this REALLY looks like an antique picture!
    End Sub
Be warned, Color.White will give you a really bright grayscale sunlight. Have fun with your color matrix like I did.