1
\$\begingroup\$

I've just figured out on my own how to scale a portion of a bitmap using PutPixel. I would like to know the mathematical theory behind rotating a bitmap on my own, using per-pixel operations like PutPixel.

I am not interested in using OpenGL or Direct3D to accomplish this, I'd like to know what the fundamental math and programming technique behind the operation is?

\$\endgroup\$
5
  • 2
    \$\begingroup\$ en.wikipedia.org/wiki/Rotation_(mathematics) \$\endgroup\$
    – bcrist
    Dec 19 '13 at 16:39
  • \$\begingroup\$ The topic of speeding up software rasterization (which is essentially what you are doing when you aren't using GL or D3D) is broad enough to be several questions in its own right, so I've removed it. \$\endgroup\$
    – user1430
    Dec 19 '13 at 17:24
  • 2
    \$\begingroup\$ Please explain why you rolled back my edit to your post, because the point of the edit was to make the question more in-line with what is considered a good, on-topic question here. \$\endgroup\$
    – user1430
    Dec 19 '13 at 18:16
  • \$\begingroup\$ Because I don't want people changing my words to suit some kind of stereotypical standard. \$\endgroup\$ Dec 19 '13 at 18:17
  • 1
    \$\begingroup\$ Then I'm afraid you shouldn't post on a StackExchange site, because this is a collaboratively-edited Q&A site. Please see the help center for more details. Your question in its current form is asking at least two different questions, has several misspellings, and includes lots of redundant information making it harder to read and parse. Users are capable of and encouraged to correct these issues. If you are not okay with that, you should seek another venue to ask your questions. The help center has a list of a few of them. \$\endgroup\$
    – user1430
    Dec 19 '13 at 18:21
4
\$\begingroup\$

Simple linear algebra will provide you the equations needed to rotate any given point p by some angle about the origin:

new_p.x = p.x * cos(angle) - p.y * sin(angle)
new_p.y = p.x * sin(angle) + p.y * cos(angle)

To instead rotate around some point other than the origin, say the point q, you first translate your point so as to shift the coordinate frame and make q the origin:

p.x = p.x - q.x
p.y = p.y - q.y

Then you perform the rotation as before:

new_p.x = p.x * cos(angle) - p.y * sin(angle)
new_p.y = p.x * sin(angle) + p.y * cos(angle)

Then you "undo" the translation:

new_p.x = new_p.x + q.x
new_p.y = new_p.y + q.y

Given a region (typically a rectangular one) of pixels that you want to rotate, and a location you want to rotate about (often the center of that region), you can apply the above process to every pixel in that region to find it's new, rotated location and use PutPixel or whatever equivalent to write the appropriate color value from the original location.

The typical way to do this is to represent the transformations as transformation matrices, which will allow you to easily compose the "translate, rotate, translate-back" idiom into a single matrix you can apply to many points.

Do note that you should perform the rotation into a temporary buffer of some sort first and only write back to the original bitmap until you've completed the computation of the new pixel locations and colors. If you do the operation directly onto the final bitmap, and your angle of rotation is small enough, you may end up with a "smeared" image because you wrote some of the earlier pixels over some of the later pixels and lost the original data of those later pixels.

\$\endgroup\$
3
\$\begingroup\$

First, I would like to point out that doing rotation for a bitmap image is slightly different from doing it in OpenGL or DirectX because the rendering API will usually take care of a lot of the details. Two reasons why this is the case

  • Using a rotation matrix that have a sin/cos will often result in fractions that cannot be indexed directly in the buffer. So some kind of interpolation is needed to determine the final pixel position. Otherwise the final image will have black spots.

  • The rotation image will often have a bigger rectangular buffer than the original image. This is because a bitmap image is represented as an array of pixels. Otherwise, if you use the same buffer size you may end up with a cropped image.

So you need an algorithm to address those problems. The approach is often called Image Rotation via Inverse mapping.

  1. The algorithm starts with the destination image buffer, by taking the destination image pixels and getting their value from the original image. This is done by transforming each destination pixel back by the inverse rotation, and then looking up the original value. Keep in mind that rotation matrix inverse equals its transpose so you don't actually need to calculate the inverse.

  2. Next the resulted pixel position might not have a direct pixel position corrosponding to it in the original image. You need to interpolate the result value/index in the original image to make sure that the destination pixel have a value, for example if the result index is (5.5,6.5) one possibility is to take the nearest neighbor to that pixel.

enter image description here

This image is taken from this slide show

foreach destPixel in DestImage:    
ApproxOriginaPixel = Rotate(destPixel, inverseAngle);    
value = Interpolate( OriginalImage, ApproxOriginaPixel );
destPixel  = value;

Now regarding the buffer size you can use the same original buffer size, or calculate the new buffer size so you don't get a cropped image.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.