### Article Purpose

This article is focussed on illustrating the steps required in performing an image Shear Transformation. All of the concepts explored have been implemented by means of raw pixel data processing, no conventional drawing methods, such as GDI, are required.

*Rabbit: Shear X 0.4, Y 0.4*

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

This article features a Windows Forms based sample application which is included as part of the accompanying sample source code. The concepts explored in this article can be illustrated in a practical implementation using the sample application.

The sample application enables a user to load source/input images from the local file system when clicking the ** Load Image** button. In addition users are also able to save output result images to the local file system by clicking the

**button.**

*Save Image*Image Shear Transformations can be applied to either ** X** or

**, or both**

*Y***and**

*X***pixel coordinates. When using the sample application the user has option of adjusting**

*Y***, as indicated on the user interface by the numeric up/down controls labelled**

*Shear factors***and**

*Shear X***.**

*Shear Y*The following image is a screenshot of the ** Image Transform Shear** Sample Application in action:

*Rabbit: Shear X -0.5, Y -0.25*

### Image Shear Transformation

A good definition of the term Shear Transformation can be found on the Wikipedia topic related article:

In plane geometry, a

shear mappingis a linear map that displaces each point in fixed direction, by an amount proportional to its signed distance from a line that is parallel to that direction.^{[1]}This type of mapping is also calledshear transformation,transvection, or justshearing

A Shear Transformation can be applied as a ** horizontal shear**, a

**or as both. The algorithms implemented when performing a Shear Transformation can be expressed as follows:**

*vertical shear**Horizontal Shear Algorithm*

*Vertical Shear Algorithm*

The algorithm description:

The result of a*Shear(x) :*Shear Transformation – The calculated*horizontal*representing a Shear Transform.*X-Coordinate*The result of a*Shear(y) :*Shear Transformation – The calculated*vertical*representing a Shear Transform.*Y-Coordinate*The lower case version of the Greek alphabet letter*σ :*– Represents the*Sigma*.*Shear Factor*The*x :*originating from the source/input image – The*X-Coordinate*coordinate value intended to be sheared.*horizontal*The*y :*originating from the source/input image – The*Y-Coordinate*coordinate value intended to be sheared.*vertical*Source image*H :*in pixels.*height*Source image*W :*in pixels.*width*

** Note:** When performing a Shear Transformation implementing both the

**and**

*horizontal***planes each coordinate plane can be calculated using a different shearing factor.**

*vertical*The algorithms have been adapted in order to implement a middle pixel offset by means of subtracting the product of the related image plane boundary and the specified ** Shearing Factor**, which will then be divided by a factor of two.

*Rabbit: Shear X 1.0, Y 0.1*

### Implementing a Shear Transformation

The sample source code performs Shear Transformations through the implementation of the extension methods ** ShearXY** and

**.**

*ShearImage*The ** ShearXY** extension method targets the Point structure. The algorithms discussed in the previous sections have been implemented in this function from a C# perspective. The definition as illustrated by the following code snippet:

public static Point ShearXY(this Point source, double shearX, double shearY, int offsetX, int offsetY) { Point result = new Point();

result.X = (int)(Math.Round(source.X + shearX * source.Y)); result.X -= offsetX;

result.Y = (int)(Math.Round(source.Y + shearY * source.X)); result.Y -= offsetY;

return result; }

*Rabbit: Shear X 0.0, Y 0.5*

The ** ShearImage** extension method targets the Bitmap class. This method expects as parameter values a

**and a**

*horizontal***. Providing a shearing factor of zero results in no image shearing being implemented in the corresponding direction. The definition as follows:**

*vertical shearing factor*public static Bitmap ShearImage(this Bitmap sourceBitmap, double shearX, double shearY) { 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);

int xOffset = (int )Math.Round(sourceBitmap.Width * shearX / 2.0);

int yOffset = (int )Math.Round(sourceBitmap.Height * shearY / 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) { resultPoint = sourcePoint.ShearXY(shearX, shearY, xOffset, yOffset);

resultXY = resultPoint.Y * sourceData.Stride + resultPoint.X * 4;

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

resultBuffer[resultXY + 5] = pixelBuffer[sourceXY + 1];

resultBuffer[resultXY + 6] = pixelBuffer[sourceXY + 2];

resultBuffer[resultXY + 7] = 255; }

if (resultXY - 3 >= 0) { resultBuffer[resultXY - 4] = pixelBuffer[sourceXY];

resultBuffer[resultXY - 3] = pixelBuffer[sourceXY + 1];

resultBuffer[resultXY - 2] = pixelBuffer[sourceXY + 2];

resultBuffer[resultXY - 1] = 255; }

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

resultBuffer[resultXY + 1] = pixelBuffer[sourceXY + 1];

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; }

*Rabbit: Shear X 0.5, Y 0.0*

### Sample Images

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

The sample images featuring the image of a ** Desert Cottontail Rabbit** is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from Wikipedia. The original author is attributed as

**.**

*Larry D. Moore*The sample images featuring the image of a ** Rabbit in Snow** is licensed under the Creative Commons Attribution-Share Alike 3.0 Unported license and can be downloaded from Wikipedia. The original author is attributed as

**.**

*George Tuli*The sample images featuring the image of an ** Eastern Cottontail Rabbit** has been released into the public domain by its author. The original image can be downloaded from Wikipedia.

The sample images featuring the image of a ** Mountain Cottontail Rabbit** is in the public domain in the United States because it is a work prepared by an officer or employee of the United States Government as part of that person’s official duties under the terms of Title 17, Chapter 1, Section 105 of the US Code. The original image can be downloaded from Wikipedia.

*Rabbit: Shear X 1.0, Y 0.0*

*Rabbit: Shear X 0.5, Y 0.1*

*Rabbit: Shear X -0.5, Y -0.25*

*Rabbit: Shear X -0.5, Y 0.0*

*Rabbit: Shear X 0.25, Y 0.0*

*Rabbit: Shear X 0.50, Y 0.0*

*Rabbit: Shear X 0.0, Y 0.5*

*Rabbit: Shear X 0.0, Y 0.25*

*Rabbit: Shear X 0.0, Y 1.0*

### 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 Rotate
- C# How to: Compass Edge Detection
- C# How to: Oil Painting and Cartoon Filter
- C# How to: Stained Glass Image Filter