0

I'm trying to write this program that manipulates bmp images in C and so far i've managed to rotate it as such:

 for (row=0; row < rows; row++)
      for (col=0; col < cols; col++) 
        {
          (*new) + rows*col + (rows - row -1) = original + row*cols + col;
        }

Where: Original = original bmp, new = new bmp of proportionate size depending on the amount of rotations I want to apply. Both are Pointers to a bmp, and new is a pointer to a pointer. I've done the math several times and it rotates it counter-clockwise when it should infact rotate it clockwise.That's one problem, but i figure I can just flip it counter clockwise enough time to give it the appearance of it rotating clockwise. My question is: How would I go about doing the rotation several times from an original bmp image and having it end up on new bmp image I am creating. That is, to say, how can I perform the above operation several times and still only have 1 input and 1 output file of correct size. I'd like to do this with pointers because it'll make it easier for me to manipulate the output in other procedures. I hope this is enough detail.

Thank you.

user2824512
  • 105
  • 1
  • 9
  • I recommend you do a simple rectangle on squared paper, and fill in the squares in the rectangle with unique numbers. Then you "rotate" that rectangle. This way you will see that it's actually very simple. – Some programmer dude Oct 20 '13 at 19:27
  • Right, i've done that and I get how the rotation works. My issue isn't actually rotating it but rather how to do it several times. I'd have to create new pointers for every iteration, and I'm not exactly sure how to do it several times, i'd have to create a new pointer for both original and new several times if i wanted to achieve, say, a 270 degree rotation. – user2824512 Oct 20 '13 at 19:29
  • It's just the same. To rotate 180 degrees is actually simpler than doing a 90 degree rotation for example. So for a 270 degree rotation, do a 180 and one 90. And you only need two "pointers", the source and the destination bitmap, which will both be equally large (with the exception that for 90 and 270 degrees the width and height switches place). – Some programmer dude Oct 20 '13 at 19:37
  • I guess I just don't get it, I don't see how I would do the rotation several times in 1 sitting because I'd have the original bmp, the output bmp, that's 2 diff. locations in memory. I'd have to apply the rotation again but I can't do it from the original, I'd have to do it from the output because otherwise it'd just rotate the original image again. So I'd need a third place in memory to store the new output then do the rotation again with the already turned image into the new output. I'd have the original file, the output for 90 degrees and the next output. Continued below.. – user2824512 Oct 20 '13 at 19:52
  • Yes, I could do all rotations by adding up rotations of 90 and 180 but then I'd still need my third place in memory. I don't really see any other way around that and something tells me that's inefficient. – user2824512 Oct 20 '13 at 19:53
  • If you want to *experiment* with rotating, there is no need to be skimpy with memory. Make all the copies you need. If this is not experimental: 1. then don't rotate in steps -- if you want to rotate to 270° then do so in 1 step. 2. Rotating a bitmap in-place is a well-known exercise (although a BMP may need line padding, which makes it more complicated). – Jongware Oct 20 '13 at 20:10
  • The code above won't compile. `(*new) + rows*col + (rows - row -1)` is an int expression so it can't be a valid lvalue. OTOH the RHS is a pointer expression – phuclv Oct 21 '13 at 00:49
  • Btw, bmps are defined from bottom up, not top down like many other image formats. This might explain why your rotate seems to go the wrong way. – Max Nov 06 '13 at 21:56

3 Answers3

0

Use matrices. Pseudocode:

class Matrix {
    double m11,m12,m21,m22;
};

dest.x = matrix.m11*src.x + matrix.m12*src.y;
dest.y = matrix.m21*src.x + matrix.m22*src.y;

where x = x - image.width/2 and y = y - image.height/2

http://en.wikipedia.org/wiki/Rotation_matrix#Common_rotations

mugiseyebrows
  • 4,138
  • 1
  • 14
  • 15
0

The code below demonstrates rotation of a float array by multiples of 90 degrees. I later converted the float array to a byte array so that I could generate test images to verify the results; I didn't include that part of the code because it only clutters the main point, and wasn't really what you were asking about. If you need that part, let me know I will post it.

Note that I did the rotation "out-of-place" rather than "in-place." I believe the latter is what you are really interested in, but even so, the approach below should be a good start for you. Additional discussion on the in-place transformation can be found here, which centers around the use of a transpose-type operation (memory swap), but I didn't have time to sort through all of those details, I leave that part for you.

Recall that for a counter-clockwise rotation of n*90 degrees, the transformation is given by:

enter image description here

So then of course:

enter image description here

But in the actual code you will need to translate row' and col' by imageHeight/2 and imageWidth/2, respectively, as shown in the code below, to avoid passing negative indices to your arrays.

Denoting row_p and col_p as row' and col', the code looks like this:

// Note:  nX = pixels wide, nY = pixels tall
float *dataVector = // some data source, arbitrary

// Setup the array for the out-of-place transformation:
float *dataVector2 = new float[nX*nY]; 

int n = -2;  // Example: set n = -2 to rotate counter-clockwise 180 deg
for (int row = 0; row < nY; row++) {
    for (int col = 0; col < nX; col++) {
        int row_p = cosf(n*M_PI_2)*(row-nY/2) - sinf(n*M_PI_2)*(col-nX/2) + nY/2;
        int col_p = sinf(n*M_PI_2)*(row-nY/2) + cosf(n*M_PI_2)*(col-nX/2) + nX/2;
        dataVector2[row*nX + col] = dataVector[row_p*nX + col_p];
    }
}

// Later convert float array to image ...

Note that in the code above I am using the rotated coordinates to access elements of the original array, and then mapping these values back to the original row, col coordinates:

dataVector2[row*nX + col] = dataVector[row_p*nX + col_p]; 

The result of this is that +n values give a clockwise rotation; if you want counter-clockwise rotations, simply pass in negative value of n, i.e., -n, to your code, as shown in the example above. The effect of this is to just change signs for the off-diagonal terms of the rotation matrix above.

Hope this helps.

Community
  • 1
  • 1
Bruce Dean
  • 2,798
  • 2
  • 18
  • 30
0

One way to simplify your code is to define the two 2D bases you'll be walking along your loops :

original base :

  • x0 = 0
  • y0 = 0
  • dx = 1
  • dy = cols

new base

  • x0 = rows - 1
  • y0 = 0
  • dx = rows
  • dy = -1

Rewriting your code with those should be much easier. It also has the benefit of removing the multiplications from the inner loop.

PIXEL *source = original;
PIXEL *target = new + (rows - 1) + (0 * cols);

int source_di = 1;
int source_dj = cols;

int target_di = rows;
int target_dj = -1;

for (int j = 0; j < rows; ++j) {
    int saved_source = source;
    int saved_target = target;

    for (int i = 0; i < cols; ++i) {
        *target = *source;
        source += source_di;
        target += target_di;
    }

    source = saved_source + source_dj;
    target = saved_target + target_dj;
}
diapir
  • 2,872
  • 1
  • 19
  • 26