How to obtain the scale and rotation angle from Lo

2019-03-11 10:42发布

I'm trying to use LogPolar transform to obtain the scale and the rotation angle from two images. Below are two 300x300 sample images. The first rectangle is 100x100, and the second rectangle is 150x150, rotated by 45 degree.

enter image description here enter image description here

The algorithm:

  1. Convert both images to LogPolar.
  2. Find the translational shift using Phase Correlation.
  3. Convert the translational shift to scale and rotation angle (how to do this?).

My code:

#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/imgproc/imgproc_c.h>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>

int main()
{
    cv::Mat a = cv::imread("rect1.png", 0);
    cv::Mat b = cv::imread("rect2.png", 0);
    if (a.empty() || b.empty())
        return -1;

    cv::imshow("a", a);
    cv::imshow("b", b);

    cv::Mat pa = cv::Mat::zeros(a.size(), CV_8UC1);
    cv::Mat pb = cv::Mat::zeros(b.size(), CV_8UC1);
    IplImage ipl_a = a, ipl_pa = pa;
    IplImage ipl_b = b, ipl_pb = pb;
    cvLogPolar(&ipl_a, &ipl_pa, cvPoint2D32f(a.cols >> 1, a.rows >> 1), 40);
    cvLogPolar(&ipl_b, &ipl_pb, cvPoint2D32f(b.cols >> 1, b.rows >> 1), 40);

    cv::imshow("logpolar a", pa);
    cv::imshow("logpolar b", pb);

    cv::Mat pa_64f, pb_64f;
    pa.convertTo(pa_64f, CV_64F);
    pb.convertTo(pb_64f, CV_64F);

    cv::Point2d pt = cv::phaseCorrelate(pa_64f, pb_64f);

    std::cout << "Shift = " << pt 
              << "Rotation = " << cv::format("%.2f", pt.y*180/(a.cols >> 1)) 
              << std::endl;

    cv::waitKey(0);

    return 0;
}

The log polar images:

enter image description here enter image description here

For the sample image images above, the translational shift is (16.2986, 36.9105). I have successfully obtain the rotation angle, which is 44.29. But I have difficulty in calculating the scale. How to convert the given translational shift to obtain the scale?

标签: c++ opencv
5条回答
Evening l夕情丶
2楼-- · 2019-03-11 11:02

The value for the scale factor is indeed exp(pt.y). However, since you used a "magnitude scale parameter" of 40 for the cvLogPolar function, you now need to divide pt.x by 40 to get the correct value for the displacement:

Scale = exp( pt.x / 40) = exp(16.2986 / 40) = 1.503

The value of the "magnitude scale parameter" for the cvLogPolar function does not affect the displacement produced by the rotation angle pt.x, because according to the math, it cancels out. For that reason, your formula for the rotation gives the correct value.

On another note, I believe the formula for the rotation should actually be:

Rotation = pt.y*360/(a.cols)

But, for some strange reason, the ">> 1" that you added is causing the result to be multiplied by 2 (which I believe you compensated for by multiplying by 180 instead of 360?) Remove it, and you'll see what I mean.

Also, ">>1" is causing a division by 2 in:

cvPoint2D32f(a.cols >> 1, a.rows >> 1)

If to set the center parameter of the cvLogPolar function to the center of the image (which is what you want):

cvPoint2D32f(a.cols/2, a.rows/2)

and

cvPoint2D32f(b.cols/2, b.rows/2)

then, you'll also get the correct value for the rotation (i.e. the same value that you got), and for the scale.

查看更多
狗以群分
3楼-- · 2019-03-11 11:03

From the values by phase correlation, the coordinates are rectangular coordinates hence (16.2986, 36.9105) are (x,y). The scale is calculated as

scale = log((x^2 + y^ 2)^0.5) which is approximately 1.6(near to 1.5).

When we calculate angle by using formulae theta = arctan(y/x) = 66(approx). The theta value is way of the real value(45 in this case).

查看更多
叼着烟拽天下
4楼-- · 2019-03-11 11:08

here is python version

which tells

ir = abs(ifft2((f0 * f1.conjugate()) / r0))
    i0, i1 = numpy.unravel_index(numpy.argmax(ir), ir.shape)
    angle = 180.0 * i0 / ir.shape[0]
    scale = log_base ** i1
查看更多
啃猪蹄的小仙女
5楼-- · 2019-03-11 11:09

You have two Images f1, f2 with f1(m, n) = f2(m/a , n/a) That is f1 is scaled by factor a

In logarithmic notation that is equivalent to f1(log m, log n) = f2(logm − log a, log n − log a) where log a is the shift in your phasecorrelated image.

Compare B. S. Reddy, B. N. Chatterji: An FFT-Based Technique for Translation, Rotation and Scale-Invariant Image Registration, IEEE Transactions On Image Processing Vol. 5 No. 8, IEEE, 1996

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.185.4387&rep=rep1&type=pdf

查看更多
做自己的国王
6楼-- · 2019-03-11 11:19

This thread was helpful in getting me started on rotation-invariant phase correlation, so I hope my input will help resolve any lingering issues.

We aim to calculate the scale and rotation (which is incorrectly calculated in the code). Let's start by gathering the equations from the logPolar docs. There they state the following:

(1) I = (dx,dy) = (x-center.x, y-center.y)
(2) rho = M * ln(magnitude(I))
(3) phi = Ky * angle(I)_0..360

Note: rho is pt.x and phi is pt.y in the code above

We also know that

(4) M = src.cols/ln(maxRadius)
(5) Ky = src.rows/360

First, let's solve for scale. Solving for magnitude(I) (i.e. scale) in equation 2, we get

(6) magnitude(I) = scale = exp(rho/M)

Then we substitute for M and simplify to get

(7) magnitude(I) = scale = exp(rho*ln(maxRadius)/src.cols) = pow(maxRadius, rho/src.cols)

Now let's solve for rotation. Solving for angle(I) (i.e. rotation) in equation 3, we get

(8) angle(I) = rotation = phi/Ky

Then we substitute for Ky and simplify to get

(9) angle(I) = rotation = phi*360/src.rows

So, scale and rotation can be calculated using equations 7 and 9, respectively. It might be worth noting that you should use equation 4 for calculation M and Point2f center( (float)a.cols/2, (float)a.rows/2 ) for calculating center as opposed to what is in the code above. There are good bits of info in this logpolar example opencv code.

查看更多
登录 后发表回答