Pages: 1 2
Image warps and other distortions are significantly more complicated than simple image processing techniques such as convolution. This tutorial will cover how to twist an image in the center. This exact code can be modified to do twists or other types of image warps.
UV mapping
Before getting started, lets talk briefly about UV mapping. Image bitmaps typically have the upper left hand pixel at coordinate (0,0) and the lower right pixel at (width-1, height-1). Because we are going to be performing an image distortion, we are going to be using a UV map which effectively provides an alternate coordinate system for our image. We have full control of how our alternate, imaginary coordinate system will map to the original pixels. For the purposes of this tutorial, the center point of our UV map will be at (0,0). The map will rotate pixels more toward the center of the image, and quickly decrease the rotation effect the farther the pixel is away from the center of the center of the map. For the purposes of twisting an image in the center, our UV map will have it’s origin at the center of the image.
Basic steps
- Create a copy of the original bitmap. Because the pixels we alter earlier on may be used for the calculation of pixels later, we must copy the original bitmap so we don’t accidentally corrupt our final image.
- For each pixel, perform steps 3 through 9
- Transform pixel into UV space
- Determine the distance to the center of the UV map
- Use that distance and an input factor to determine how many radians to rotate the pixel by
- Rotate the pixel coordinates in UV space around the center of the UV map using trigonometric functions sin and cos.
- Transform UV coordinates back into bitmap coordinates.
- Clamp the x and y values such that they lie in a valid region in your bitmap.
- This final calculated pixel will act as the source color for the current pixel selected in the for loop. Set the color of the current selected pixel to the color of the calculated pixel coordinate in the copy of the original bitmap.
Precision
These steps may seem complicated, but as you can see in the source code, it’s fairly straightforward. There are a couple things to point out here. Note that 64-bit floating point math is used to perform the transformation computations. This is necessary to avoid an abundance of 1-off errors due to bad floating point accuracy. For this algorithm to work effectively, everything must be very precise. One way to check for accuracy problems is simply set the newAngle to the originalAngle (no transformation at all) and check to see if the calculated srcX and srcY are ever not equal to j and i respectively. For images of 1024×768, this works fine. However, I tested a 4923×4122 image (provided here), in which some pixels were 1 off. So very large images may require 128-bit floating point to be perfectly accurate.
Rounding
Care must be taken whenever rounding from a floating point UV space back to integer coordinates. Note here, that we round from a double to an int with this code:
Image clipping and quality
The code may be used as an example for performing simple image warps such as twist, rotate, scale, etc. Notice that when rotating an image, we actually may require to use pixels off the side of an image. Because we clamp the source X and Y coordinates to valid pixels, we see some solid color streaking effects off the four corners of an image. There is no way to get rid of that since the data isn’t available outside the original bitmap. It’s just something you should be aware of.
If you’re looking for ultra high quality, you may want to tweak this a bit. Notice here, we ultimately use the color of exactly 1 source pixel for every 1 destination pixel, because the source pixel coordinates are converted to integers. To achieve higher quality, you will need to sample the source pixel and it’s surrounding pixels, and weight the colors accordingly in order to achieve smoother results. For more information on how to do this, you may want to take a look at the bilinear interpolation tutorial to achieve high quality results after any sort of image transform.
Be sure to visit the second page for the C++ code and performance characteristics with multiple CPUs!
Pages: 1 2