# Hue Rotation with F# and GDI+

Cristian Merighi () First article in F#. Topic, useful and pretextuous at the same time, is how to hue rotate an image using GDI+ libraries.

I'm not that into those techno-philosophical disputes pro or contra a particular type of programming language. The thing I know is that I've never tried a functional language before F#.
I've been missing something.

I approached this new technology to experiment asynchronous and parallelized functionalities (waiting for PLinq and the CLR 4), but I suddenly fell in love with its fluent and natural syntax and patterns.

I just want to subscribe this first experience of mine signing a bunch of code lines relevant to GDI+ image management, specifically Hue rotation.

Brief theory excursus: most known and used among the color spaces is without doubt the so named RGB (from Red, Greeen, Blue).
This space can be sketched as a 3D environment generated by the three axes identified by the base colors.
Each color channel has available 1 byte (8 bits) of informations (in base-10, 28 values: from 0 to 255).

The imaginary line which connects the black point (R = 0, G = 0, B = 0) and the white one (255, 255, 255) is the gray axis.
Hue rotation is all about moving (rotating) colors around the gray axis (see figure). To handle this kind of rotation let us disturb our fellows 3D vectors and quaternions. Quaternions are very useful in this scenario:

1. General reason: they obviate the gimbal lock problem.
2. Specific reason: they easily permits to get a correspondent 3D rotation matrix, ideal for us: we in fact need to generate a ColorMatrix and apply it to the original image.

About quaternions' theory, I'd address you to resources and literature aailable on the web or in the libraries, the following code will be commented specifying the goal of the line more than its algebraic meaning.

#light

namespace Pacem.Drawing

open System.Drawing

module internal ColorMatrix =

let internal FromAngleAxisRotation(i, j, k, theta) =

// quaternion-like

let angleInRadians = (theta % 360.0) * 0.017453292519943295

let length = sqrt (i*i + j*j + k*k)

// love the pipeline pattern ;)

if (length = 0.0) then System.InvalidOperationException() |> raise

let sinTheta = 0.5 * angleInRadians |> sin

// preparing the 4 parameters of the quaternion (x, y, x, w)

let x = i * sinTheta / length

let y = j * sinTheta / length

let z = k * sinTheta / length

let w = 0.5 * angleInRadians |> cos

// quaternion to rotation matrix

let m11 = 1.0 - 2.0 * y * y - 2.0 * z * z |> float32

let m12 = 2.0 * x * y + 2.0 * w * z |> float32

let m13 = 2.0 * x * z - 2.0 * w * y |> float32

let m21 = 2.0 * x * y - 2.0 * w * z |> float32

let m22 = 1.0 - 2.0 * x * x - 2.0 * z * z |> float32

let m23 = 2.0 * y * z + 2.0 * w * x |> float32

let m31 = 2.0 * w * y + 2.0 * x * z |> float32

let m32 = 2.0 * y * z - 2.0 * w * x |> float32

let m33 = 1.0 - 2.0 * x * x - 2.0 * y * y |> float32

// notice array ctor: [| item1; item2; ... itemN |]

let source = [|

[| m11; m12; m13; 0.0f; 0.0f |];

[| m21; m22; m23; 0.0f; 0.0f |];

[| m31; m32; m33; 0.0f; 0.0f |];

[| 0.0f; 0.0f; 0.0f; 1.0f; 0.0f |];

[| 0.0f; 0.0f; 0.0f; 0.0f; 1.0f |]

|]

// result to return

System.Drawing.Imaging.ColorMatrix(source)

I love duck-typing! ...I still love duck-typing (now rotated by 123°)! Now how to use it to load, manipulate and save images.
Warning: this is decontextualized code, outside any module or type (= won't compile).

use attr = new ImageAttributes()

// degrees is the variable that carries the angle to rotate by.

// (1.0, 1.0, 1.0) has obviously the same direction of (255.0, 255.0, 255.0).

attr.SetColorMatrix(Pacem.Drawing.ColorMatrix.FromAngleAxisRotation(1.0, 1.0, 1.0, degrees))

use bmp = new Bitmap("c:\\myOriginalImage.jpg")

let w = bmp.Width

let h = bmp.Height

let rc = Rectangle(0, 0, w, h)

use graphics = bmp |> Graphics.FromImage

graphics.DrawImage(bmp, rc, 0, 0, w, h, GraphicsUnit.Pixel, attr)

bmp.Save("c:\\myHueRotatedImage.jpg")

Maybe this is not the more enlightning example about F# potentials, but it's a start.
About me, I've already rewritten my GDI+ libraries asynchronizing and parallelizing wherever possible, and I was stunned: on my Quad core, even the heavier cycles solve in one or two tenths of second for pretty huge images (1024x768).

Take care. Bye.

## Feedbacks

• #### Re: Hue Rotation with F# and GDI+

Carlos Alloatti Sunday, June 13, 2010 Excellent article thanks! What if we did not want to rotate, but apply an specific hue value?

feedback