## Posts Tagged 'Image Rotate'

### Article Purpose

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

Daisy: Rotate Red 0o, Green 10o, Blue 20o

### 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 15o, Green 5o, Blue 10o

When using the sample application users are able to load source/input from the local 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, Green and Red respectively. Each control represents the degree to which the related colour component should be rotated. Possible input values range from –360 to 360. Positive values result in clockwise rotation, whereas negative values result in counter clockwise rotation. The sample application enables users to save result to the local file system by clicking the Save Image button.

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

### Image Rotation Transformation

A applied to an from a theoretical point of view is based in . From we learn the following :

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

Rose: Rotate Red –20o, Green 0o, Blue 20o

In this article rotation is implemented through applying a set algorithm to the coordinates of each pixel forming part of a source/input . In the corresponding result 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:

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

Butterfly: Rotate Red 10o, Green 0o, Blue 0o

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

The pixel coordinates located at exactly the middle of an can be calculated through dividing the width with a factor of two in regards to the X-coordinate. The Y-coordinate can be calculated through dividing the height also with a factor of two. The algorithms calculate the coordinates of the middle pixel and implements the coordinates as offsets. Implementing the pixel offsets  results in being rotated around the ’s middle, as opposed to the the top left pixel (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, Green and Blue. 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.

Daisy: Rotate Red 30o, Green 0o, Blue 180o

### Implementing a Rotation Transformation

The sample source code implements a through the of two : RotateXY and RotateImage.

The RotateXY targets the 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 –60o, Green 0o, Blue 60o

The RotateImage targets the 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),
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);

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 15o, Green 5o, Blue 5o

### Sample Images

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

The Original Image

CPU: Rotate Red 90o, Green 0o, Blue –30o

CPU: Rotate Red 0o, Green 10o, Blue 0o

CPU: Rotate Red –4o, Green 4o, Blue 6o

CPU: Rotate Red 10o, Green 0o, Blue 0o

CPU: Rotate Red 10o, Green –5o, Blue 0o

CPU: Rotate Red 10o, Green 0o, Blue 10o

CPU: Rotate Red –10o, Green 10o, Blue 0o

CPU: Rotate Red 30o, Green –30o, Blue 0o

CPU: Rotate Red 40o, Green 20o, Blue 0o

CPU: Rotate Red 40o, Green 20o, Blue 0o

### 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:

• 825,925 hits