Search code examples
cmatrixcastingrotationpixel

Rotating a bitmap and transform the resulting coordinates in float format back to integer x,y values for pixel array


I am implementing a function which gets a input pixel array containing a bitmap, rotate the bitmap by 50 degrees and writes the result into an output pixel array. The output pixel array is shown on screen. I am using a rotation matrix to transform every pixel of the input to the output.

The function which rotates the pixels is implemented the following way:

void rotatePixel(int x, int y, float *new_x, float *new_y)
{
    float f_x, f_y;
    UWORD i;
    f_x = (float)x;
    f_y = (float)y;

    i = currentDegree / DEGREE_RESOLUTION - 1;
    *new_x = (f_x * cosLookup[i] - f_y * sinLookup[i]);
    *new_y = (f_x * sinLookup[i] + f_y * cosLookup[i]);
}

The function is invoked for every pixel of the input array. cosLookup and sinLookup are lookup tables to speed up calculation. The result for a red square looks like this:

enter image description here

So, the rotation in general is working but there are lots of free spots where no pixel was written to. To find out whats going wrong, I adjusted my program to mark pixels with green and blue colors, if a pixel is projected at coordinates where already a pixel resides. The result looks like this:

enter image description here

I assume this is because of:

  • the result of my rotation matrix are pixel coordinates in float format
  • the target coordinates in my output array are integers
  • Simply applying round() leads to the problem from above: Pixels are written on the same x/y coordinate two or more times, while other coordinates in my output array remain empty

My question is: How can I resolve this issue? I think tools like gimp, Photoshop etc. rotate objects without this problem. I thought about an internal upscaling to be capable of writing the resulting pixels more precisely to their destination. Or maybe applying a filter which smooths the result after transformation?


Solution

  • What if you invert the rotation and calculate backwards

    new_x, new_x -> old_x, old_y

    That would resolve the rounding errors.

    for new_pixel_coordinates:
        old_pixel_coordinates = inverse_rotate(new_pixel_coordinates)
        color = lookup_color(old_bitmap, old_pixel_coordinates)
        color_new_picture(new_bitmap, new_pixel_coordinates, color)