Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Anti Aliased Image Transformation (Aaform)

0.00/5 (No votes)
24 Feb 2006 4  
Optimal Image Transformation

Introduction

Aaform (Anti Aliased Image Transformation) is a technique I have developed for transforming a rectangular bitmap into any quadrilateral (including convex/complex quadrilaterals). I believe that this is the optimal way to transform images that exist. Aaform uses a lot of geometry concepts that will be mentioned in this article. You can read about them here (code samples are in VB.NET, but any programmer should be able to follow them).

Below is an arbitrary sample transformation of this Website's logo.

Sample Transformation

How It Works - Intro

Aaform includes two main functions, Transform and CreateTransform. Transform is used to transform one image into another. This is useful when you want to transform one image into another image while keeping the edges looking nice. CreateTransform simply creates a blank image large enough to hold the transformed image, then puts in a call to Transform. Below is the C++ prototype of the transform function:

transform(HBITMAP src, HBITMAP dst, std::vector<double> xcorner,
std::vector<double> ycorner, aaf_callback callbackfunc)
  • src - Bitmap to be transformed
  • dst - Bitmap to draw the transformed image onto
  • xcorner - Array of the x coordinates of the transformed image. xcorner.size() must equal 4
  • ycorner - Array of the y coordinates of the transformed image. ycorner.size() must equal 4
  • callbackfunc - The callback function serves two purposes. First, it allows the client code to be updated on the progress of transform, and secondly, it gives the client code an opportunity to cancel the transformation.

(xcorner[0], ycorner[0]) make up the top left corner of the transformed image, (xcorner[1], ycorner[1]) top right, (xcorner[2], ycorner[2]) bottom right, and (xcorner[3], ycorner[3]) bottom left.

How It Works - Make the Grid

The first thing transform does after checking some conditions and allocating memory is create a grid of the corners of every pixel in the transformed image. srcwidth is the width of the bitmap passed as src and srcheight is the height of the bitmap passed as src.

Looping from x = 0 to srcwidth, creategrid creates a line (in AX + BY = C form) from the point (x / srcwidth) percent down the line created by (xcorner[0], ycorner[0])-(xcorner[1],ycorner[1]) [the top edge] and then points the same percentage down the line created by (xcorner[3], ycorner[3])-(xcorner[2],ycorner[2]) [the bottom edge].

Next, a nested for loop is executed that goes from y = 0 to srcheight. It creates a line from the point(y / srcheight) percent down the line created by (xcorner[0], ycorner[0])-(xcorner[3],ycorner[3]) [the left edge] and then points the same percentage down the line created by (xcorner[1], ycorner[1])-(xcorner[2],ycorner[2]) [the right edge].

Finally, it finds where the two lines intersect and adds this point to our grid as the top right corner of the pixel located at (x, y). Since pixels share corners, there is no need to calculate all four corners for each pixel. For example, to get the top right corner of pixel (0, 0), you only need to find the top left corner of the pixel (1, 0).

How It Works - The Main Loop

Now that we have the coordinates of each corner of each transformed pixel, all we have to do is find the area of overlap over each destination pixel. Obviously we don't want to compare each transformed pixel with each destination pixel, so instead we will compare each transformed pixel with each destination pixel within the minimum floor of the transformed pixels x and y coordinates and the maximum ceil of the transformed pixels x and y coordinates. Then we will find the area of overlap of the transformed pixel's polygon over the destination pixel's square for each destination pixel within the scan area. Polygon overlap is fairly complicated, and if you are interested in knowing how it works, take a look here. (Polygon Overlap is covered in the Polygon section) Then the overlap of these two polygons can be used to determine how much representation the transformed pixel should receive in the destination pixel.

Each of the destination pixels are 1x1 squares that therefore have a maximum area of 1 square unit. So it follows that the maximum area of overlap is 1 in the case that the transformed pixel completely encloses the destination pixel. So therefore an overlap of 1.0 indicates that the transformed pixel has 100% representation in the destination pixel, thus they should be the same color. An overlap of 0.5 indicates 50% representation, and an overlap of 0.0 indicates no representation. And that's how Aaform works in a nutshell.

Aaform Demo

Extras

Aaform also includes a couple of functions that use CreateTransform to do more specific tasks:

  • Rotate: Rotates an image by the passed degrees
  • Stretch: Stretches an image by the passed ratios
  • SkewHorizontal: Skews the image horizontally by the passed degrees (-90, 90)
  • SkewVerticle: Skews the image vertically by the passed degrees (-90, 90)

Implementation

I have written Aaform in three languages (C++, VB6, and VB.NET). Because of this, I am not going to go over how to use the algorithm in each language. Please look at the sample project listed above for details on each function's uses.

Conclusion

I believe that Aaform produces the best quality image transformations possible in terms of data representation (it has the least data loss). I am not an expert in how the eye interprets light, so it is hard for me to say how well it represents the transformed image visually (but obviously, it does this pretty well).

History

  • 24th February, 2006: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here