views:

330

answers:

4

sigh I'm sorry to say that I'm using Intel IPL (Image Processing Library) in some image processing code I'm working on. This is the tale of my struggle with getting my images to rotate correctly.

  1. I have a source image. It has a size (w, h) which is not necessarily square.
  2. It is going to be rotated by angle theta.
  3. I've calculated the output size required to fit an image of size (w, h) rotated by angle theta. This size is (dw, dh). I've allocated a destination buffer with that size.
  4. I want to rotate the source image by angle theta about the source image's center (w/2, h/2) and have that rotated image be centered in my destination buffer.

iplRotate() takes 2 shift parameters, xShift and yShift, which indicate the distance the image should be shifted along the x and y axis after the rotate is performed.

The problem is I cannot get iplRotate to center the rotated image in the destination image. It's always off center.

My best guess for what xShift and yShift should be is the following:

  • xShift = dw - w
  • yShift = dh - h

But this doesn't work, and I'm not sure what else to do to calculate xShift and yShift. Does anyone have any suggestions for how to use iplRotate to do what I want?

One last bit of info: I've attempted to use iplGetRotateShift() to calculate xShift and yShift, again, to no avail. I would imagine that this would work:

iplGetRotateShift(dw / 2.0, dh / 2.0, theta, &xShift, &yShift);

But it does not.


Edit: I rewrote the code using Intel IPP 6.0 instead of IPL and I'm seeing identical wrong results. I can't imagine that Intel got rotation wrong in 2 different libraries, so I must be doing something wrong.


Edit: I tried the following (IPP) code that Dani van der Meer suggested:

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);

Unfortunately, still no luck. That does not work either.

+1  A: 

I've never used (or heard of) IPL before, so I'm just merely guessing what the API does. But if iplRotate rotates about (0, 0) and if iplGetRotateShift does similarly, why not try rotating the other 3 corners of your original "box" (ignoring (0, 0) since that stays put): (w, 0), (0, h), and (w, h).

Your result will be a new box with some negative values. You want to "shift back" so whatever negative values you have will become zero, if you get what I mean.

Jim Buck
+1  A: 

Based on my reading of the documentation I think you're using iplGetRotateShift wrong. In particular, I think you need to specify the center of rotation in the source image, not the destination image, thus:

iplGetRotateShift( w / 2.0,  h / 2.0, angle, &xShift, &yShift );
Don Neufeld
I've tried that - however, since my destination image is the final size of the rotated image and not the size of the source, the final rotated image is off center.
unforgiven3
+3  A: 

When using iplGetRotateShift you need to specify the center of rotation in the source image. This will work well if the size of the source and destination image is the same.

In your case you want an extra shift to center the image in your destination image:

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;

To combine the two shift you need to use ippiAddRotateShift instead of ippiGetRotateShift.

Note: These functions refer to the IPP library version 5.3 (the version I have). I am not sure that AddRotateShift is available in IPL. But you mentioned in the question that you tried the same using IPP, so hopefully you can use IPP instead of IPL.

You get something like this

xShift = (dw - w) / 2.0;
yShift = (dh - h) / 2.0;
ippiAddRotateShift(w / 2.0, h / 2.0, angle, &xShift, &yShift);

If you use these shifts in the call to ippiRotate the image should be centered in the destination image.

I hope this helps.

EDIT: Here is the code I used to test (the change from w to dw and h to dh and the rotation angle are just random):

//Ipp8u* dst_p; Initialized somewhere else in the code
//Ipp8u* src_p; Initialized somewhere else in the code
int w = 1032;
int h = 778;
int dw = w - 40; // -40 is just a random change
int dh = h + 200; // 200 is just a random change
int src_step = w * 3;
int dst_step = dw * 3;
IppiSize src_size = { w, h };
IppiRect src_roi  = { 0, 0, w, h };
IppiRect dst_rect = { 0, 0, dw, dh };
double xShift = ((double)dw - (double)w) / 2.0;
double yShift = ((double)dh - (double)h) / 2.0;
ippiAddRotateShift((double)w / 2, (double)h / 2, 37.0, &xShift, &yShift);
ippiRotate_8u_C3R(src_p, src_size, src_step, src_roi, 
       dst_p, dst_step, dst_rect, 37.0, xShift, yShift, IPPI_INTER_NN);
Dani van der Meer
Thanks! I'll try this out right now!
unforgiven3
It was very close in IPL - since there is no iplAddRotateShift, I just added (dx - x) / 2.0 after I called iplGetRotateShift(x / 2.0, ...). It's still off by 10-15 pixels, though - I'll have to try with IPP and see what I get. Thanks!
unforgiven3
Sorry, this does not work either :-( I tried with IPP, and it gives me the same incorrect results as IPL.
unforgiven3
Very strange... I tested my code and it looks to work fine, the center of the image is the same in src and dst image. Just to be sure I posted the complete code block I used to test
Dani van der Meer
I'll give that a try - thanks for posting that! Just out of curiousity, why are you setting src_step to (w * 3)? src_p is of type Ipp8u* - wouldn't the step of the image just be w?
unforgiven3
I use RGB images. Every pixel is 3 bytes, so the step (in bytes) is w * 3.
Dani van der Meer
Ah, that makes sense. Unfortunately I still cannot get this to work. I have a few other ideas, but I'm still out of luck at this point. Thanks for your help, though!
unforgiven3
+1  A: 

If it's still not working for you then can we confirm that the assumptions are valid? In particular point 3. where you calculate dw and dh.

Mathematically

dw = w * |cos(theta)| + h * |sin(theta)|
dh = h * |cos(theta)| + w * |sin(theta)|

so if theta = pi/6 say, then if w = 100 and h = 150 then presumably dw = 162?

Does the incorrect position you're getting vary with theta? Presumably it works with theta=0? What about theta=pi/2 and theta=pi/4?

Troubadour
I don't have the code in front of me, but I'm fairly certain that is the equation I use to calculate the final destination size. Regardless, however, all I'm doing is calculating the size of the destination image. That size could be any size - all I want is the rotated image to be at the center of that destination rectangle.
unforgiven3