### Article Purpose

This article provides a discussion exploring the concept of image rotation as a geometric transformation. In addition to conventional image rotation this article illustrates the concept of individual colour channel rotation.

*Daisy: Rotate Red 0 ^{o}, Green 10^{o}, Blue 20^{o}*

### Sample Source Code

This article is accompanied by a sample source code Visual Studio project which is available for download here.

### Using the Sample Application

A Sample Application has been included in the sample source code that accompanies this article. The sample application serves as an implementation of the concepts discussed throughout this article. Concepts can be easily tested and replicated using the sample application.

*Daisy: Rotate Red 15 ^{o}, Green 5^{o}, Blue 10^{o}*

When using the sample application users are able to load source/input images from the local file system by clicking the ** Load Image** button. Required user input via the user interface can be found in the form of three numeric up/down controls labelled

**,**

*Blue***and**

*Green***respectively. Each control represents the degree to which the related colour component should be rotated. Possible input values range from**

*Red***to**

*–360***. Positive values result in clockwise rotation, whereas negative values result in counter clockwise rotation. The sample application enables users to save result images to the local file system by clicking the**

*360***button.**

*Save Image*The following image is a screenshot of the ** Image Transform Rotate** sample application in action:

### Image Rotation Transformation

A rotational transformation applied to an image from a theoretical point of view is based in Transformation Geometry. From Wikipedia we learn the following definition:

In mathematics,

transformation geometry(ortransformational geometry) is the name of a mathematical and pedagogic approach to the study of geometry by focusing on groups of geometric transformations, and the properties of figures that are invariant under them. It is opposed to the classical synthetic geometry approach of Euclidean geometry, that focus on geometric constructions.

*Rose: Rotate Red –20 ^{o}, Green 0^{o}, Blue 20^{o}*

In this article image rotation is implemented through applying a set rotation transform algorithm to the coordinates of each pixel forming part of a source/input image. In the corresponding result image the calculated rotated pixel coordinates in terms of colour channel values will be assigned to the colour channel values of the original pixel.

The algorithms implemented when calculating a pixel’s rotated coordinates can be expressed as follows:

Symbols/variables contained in the algorithms:

The result of rotating a pixel’s x-coordinate.*R (x) :*The result of rotating a pixel’s y-coordinate.*R (y) :*The source pixel’s x-coordinate.*x :*The source pixel’s y-coordinate.*y :*The width in pixels of the source image.*W :*The height in pixels of the source image.*H :*The lower case Greek alphabet letter alpha. The value represented by alpha reflects the degree of rotation.**ɑ :**

*Butterfly: Rotate Red 10 ^{o}, Green 0^{o}, Blue 0^{o}*

In order to apply a rotation transformation each pixel forming part of the source/input image should be iterated. The algorithms expressed above should be applied to each pixel.

The pixel coordinates located at exactly the middle of an image can be calculated through dividing the image width with a factor of two in regards to the ** X-coordinate**. The

**can be calculated through dividing the image height also with a factor of two. The algorithms calculate the coordinates of the image middle pixel and implements the coordinates as offsets. Implementing the pixel offsets results in images being rotated around the image’s middle, as opposed to the the top left pixel**

*Y-coordinate***.**

*(0,0)*This article and the associated sample source code extends the concept of traditional rotation through implementing rotation on a per colour channel basis. Through user input the individual degree of rotation can be specified for each colour channel, namely ** Red**,

**and**

*Green***. Functionality has been implemented allowing each colour channel to be rotated to a different degree. In essence the algorithms described above have to be implemented three times per pixel iterated.**

*Blue**Daisy: Rotate Red 30 ^{o}, Green 0^{o}, Blue 180^{o}*

### Implementing a Rotation Transformation

The sample source code implements a rotation transformation through the definition of two extension methods: ** RotateXY** and

**.**

*RotateImage*The ** RotateXY** extension method targets the Point structure. This method serves as an encapsulation of the logic behind calculating rotating coordinates at a specified angle. The practical C# code implementation of the algorithms discussed in the previous section can be found within this method. The definition as follows:

public static Point RotateXY(this Point source, double degrees, int offsetX, int offsetY) { Point result = new Point(); result.X = (int)(Math.Round((source.X - offsetX) * Math.Cos(degrees) - (source.Y - offsetY) * Math.Sin(degrees))) + offsetX;

result.Y = (int)(Math.Round((source.X - offsetX) * Math.Sin(degrees) + (source.Y - offsetY) * Math.Cos(degrees))) + offsetY;

return result; }

*Rose: Rotate Red –60 ^{o}, Green 0^{o}, Blue 60^{o}*

The ** RotateImage** extension method targets the Bitmap class. This method expects three rotation degree/angle values, each corresponding to a colour channel. Positive degrees result in clockwise rotation and negative values result in counter clockwise rotation. The definition as follows:

public static Bitmap RotateImage(this Bitmap sourceBitmap, double degreesBlue, double degreesGreen, double degreesRed) { BitmapData sourceData = sourceBitmap.LockBits(new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

byte[] pixelBuffer = new byte[sourceData.Stride * sourceData.Height];

byte[] resultBuffer = new byte[sourceData.Stride * sourceData.Height];

Marshal.Copy(sourceData.Scan0, pixelBuffer, 0, pixelBuffer.Length);

sourceBitmap.UnlockBits(sourceData);

//Convert to Radians degreesBlue = degreesBlue * Math.PI / 180.0; degreesGreen = degreesGreen * Math.PI / 180.0; degreesRed = degreesRed * Math.PI / 180.0;

//Calculate Offset in order to rotate on image middle int xOffset = (int )(sourceBitmap.Width / 2.0); int yOffset = (int )(sourceBitmap.Height / 2.0);

int sourceXY = 0; int resultXY = 0;

Point sourcePoint = new Point(); Point resultPoint = new Point();

Rectangle imageBounds = new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height);

for (int row = 0; row < sourceBitmap.Height; row++) { for (int col = 0; col < sourceBitmap.Width; col++) { sourceXY = row * sourceData.Stride + col * 4;

sourcePoint.X = col; sourcePoint.Y = row;

if (sourceXY >= 0 && sourceXY + 3 < pixelBuffer.Length) { //Calculate Blue Rotation

resultPoint = sourcePoint.RotateXY(degreesBlue, xOffset, yOffset);

resultXY = (int)(Math.Round( (resultPoint.Y * sourceData.Stride) + (resultPoint.X * 4.0)));

if (imageBounds.Contains(resultPoint) && resultXY >= 0) { if (resultXY + 6 < resultBuffer.Length) { resultBuffer[resultXY + 4] = pixelBuffer[sourceXY];

resultBuffer[resultXY + 7] = 255; }

if (resultXY + 3 < resultBuffer.Length) { resultBuffer[resultXY] = pixelBuffer[sourceXY];

resultBuffer[resultXY + 3] = 255; } }

//Calculate Green Rotation

resultPoint = sourcePoint.RotateXY(degreesGreen, xOffset, yOffset);

resultXY = (int)(Math.Round( (resultPoint.Y * sourceData.Stride) + (resultPoint.X * 4.0)));

if (imageBounds.Contains(resultPoint) && resultXY >= 0) { if (resultXY + 6 < resultBuffer.Length) { resultBuffer[resultXY + 5] = pixelBuffer[sourceXY + 1];

resultBuffer[resultXY + 7] = 255; }

if (resultXY + 3 < resultBuffer.Length) { resultBuffer[resultXY + 1] = pixelBuffer[sourceXY + 1];

resultBuffer[resultXY + 3] = 255; } }

//Calculate Red Rotation

resultPoint = sourcePoint.RotateXY(degreesRed, xOffset, yOffset);

resultXY = (int)(Math.Round( (resultPoint.Y * sourceData.Stride) + (resultPoint.X * 4.0)));

if (imageBounds.Contains(resultPoint) && resultXY >= 0) { if (resultXY + 6 < resultBuffer.Length) { resultBuffer[resultXY + 6] = pixelBuffer[sourceXY + 2]; resultBuffer[resultXY + 7] = 255; }

if (resultXY + 3 < resultBuffer.Length) { resultBuffer[resultXY + 2] = pixelBuffer[sourceXY + 2];

resultBuffer[resultXY + 3] = 255; } } } } }

Bitmap resultBitmap = new Bitmap(sourceBitmap.Width, sourceBitmap.Height);

BitmapData resultData = resultBitmap.LockBits(new Rectangle (0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

Marshal.Copy(resultBuffer, 0, resultData.Scan0, resultBuffer.Length);

resultBitmap.UnlockBits(resultData);

return resultBitmap; }

*Daisy: Rotate Red 15 ^{o}, Green 5^{o}, Blue 5^{o}*

### Sample Images

This article features a number of sample images. All featured images have been licensed allowing for reproduction.

The sample images featuring an image of a ** yellow daisy** is licensed under the Creative Commons Attribution-Share Alike 2.5 Generic license and can be downloaded from Wikimedia.org.

The sample images featuring an image of a ** white daisy** is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from Wikipedia.

The sample images featuring an image of a ** CPU** is licensed under the Creative Commons Attribution-Share Alike 2.0 Generic license. The original author is credited as Andrew Dunn. The original image can be downloaded from Wikipedia.

The sample images featuring an image of a * rose* is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported, 2.5 Generic, 2.0 Generic and 1.0 Generic license. The original image can be downloaded from Wikipedia.

The sample images featuring an image of a ** butterfly** is licensed under the Creative Commons Attribution 3.0 Unported license and can be downloaded from Wikimedia.org.

*The Original Image*

*CPU: Rotate Red 90 ^{o}, Green 0^{o}, Blue –30^{o}*

*CPU: Rotate Red 0 ^{o}, Green 10^{o}, Blue 0^{o}*

*CPU: Rotate Red –4 ^{o}, Green 4^{o}, Blue 6^{o}*

*CPU: Rotate Red 10 ^{o}, Green 0^{o}, Blue 0^{o}*

*CPU: Rotate Red 10 ^{o}, Green –5^{o}, Blue 0^{o}*

*CPU: Rotate Red 10 ^{o}, Green 0^{o}, Blue 10^{o}*

*CPU: Rotate Red –10 ^{o}, Green 10^{o}, Blue 0^{o}*

*CPU: Rotate Red 30 ^{o}, Green –30^{o}, Blue 0^{o}*

*CPU: Rotate Red 40 ^{o}, Green 20^{o}, Blue 0^{o}*

*CPU: Rotate Red 40 ^{o}, Green 20^{o}, Blue 0^{o}*

### Related Articles and Feedback

Feedback and questions are always encouraged. If you know of an alternative implementation or have ideas on a more efficient implementation please share in the comments section.

I’ve published a number of articles related to imaging and images of which you can find URL links here:

- C# How to: Image filtering by directly manipulating Pixel ARGB values
- C# How to: Image filtering implemented using a ColorMatrix
- C# How to: Blending Bitmap images using colour filters
- C# How to: Bitmap Colour Substitution implementing thresholds
- C# How to: Generating Icons from Images
- C# How to: Swapping Bitmap ARGB Colour Channels
- C# How to: Bitmap Pixel manipulation using LINQ Queries
- C# How to: Linq to Bitmaps – Partial Colour Inversion
- C# How to: Bitmap Colour Balance
- C# How to: Bi-tonal Bitmaps
- C# How to: Bitmap Colour Tint
- C# How to: Bitmap Colour Shading
- C# How to: Image Solarise
- C# How to: Image Contrast
- C# How to: Bitwise Bitmap Blending
- C# How to: Image Arithmetic
- C# How to: Image Convolution
- C# How to: Image Edge Detection
- C# How to: Difference Of Gaussians
- C# How to: Image Median Filter
- C# How to: Image Unsharp Mask
- C# How to: Image Colour Average
- C# How to: Image Erosion and Dilation
- C# How to: Morphological Edge Detection
- C# How to: Boolean Edge Detection
- C# How to: Gradient Based Edge Detection
- C# How to: Sharpen Edge Detection
- C# How to: Calculating Gaussian Kernels
- C# How to: Image Blur
- C# How to: Image Transform Shear
- C# How to: Compass Edge Detection
- C# How to: Oil Painting and Cartoon Filter
- C# How to: Stained Glass Image Filter

## 29 Responses to “C# How to: Image Transform Rotate”