Как получить масштаб и угол поворота от преобразования LogPolar

Я пытаюсь использовать преобразование LogPolar, чтобы получить масштаб и угол поворота от двух изображений. Ниже приведены два образца образца 300x300. Первый прямоугольник равен 100x100, а второй прямоугольник - 150x150, повернутый на 45 градусов.

enter image description hereenter image description here

Алгоритм:

  • Преобразуйте оба изображения в LogPolar.
  • Найти трансляционный сдвиг с использованием фазовой корреляции.
  • Преобразование сдвига трансляции в масштаб и угол поворота (как это сделать?).

Мой код:

#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;
}

Лог-полярные изображения:

enter image description hereenter image description here

Для изображений образцовых изображений выше трансляционный сдвиг (16.2986, 36.9105). Я успешно получил угол поворота, который равен 44.29. Но мне сложно вычислить масштаб. Как преобразовать заданный сдвиг трансляции для получения шкалы?

Ответ 1

У вас есть два изображения f1, f2 с f1 (m, n) = f2 (m/a, n/a) То есть f1 масштабируется с коэффициентом a

В логарифмической записи, эквивалентной f1 (log m, log n) = f2 (logm - log a, log n - log a), где log a - это сдвиг в вашем фазокорреляционном изображении.

Сравнить Б. С. Редди, Б. Н. Чаттерджи: метод БПФ для перевода, вращения и Масштаб-инвариантная регистрация изображений, транзакции IEEE при обработке изображений. 5 № 8, IEEE, 1996

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

Ответ 2

здесь версия python

который сообщает

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

Ответ 3

Значение масштабного коэффициента действительно exp(pt.y). Однако, поскольку вы использовали параметр "масштабный масштаб" 40 для функции cvLogPolar, теперь вам нужно разделить pt.x на 40, чтобы получить правильное значение для перемещения:

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

Значение параметра масштаба шкалы для функции cvLogPolar не влияет на смещение, создаваемое углом поворота pt.x, потому что согласно математике оно отменяется. По этой причине ваша формула для вращения дает правильное значение.

В другой заметке, я считаю, что формула для вращения должна быть:

Вращение = pt.y * 360/(a.cols)

Но по какой-то странной причине добавленный вами " → 1" приводит к умножению результата на 2 (что, я считаю, вы компенсировали умножением на 180 вместо 360?) Удалите его, Посмотрю, что я имею в виду.

Кроме того, " → 1" вызывает деление на 2 в:

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

Если установить центральный параметр функции cvLogPolar в центр изображения (это то, что вы хотите):

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

и

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

тогда вы также получите правильное значение для вращения (т.е. того же значения, что и у вас), и для шкалы.

Ответ 4

Из значений по фазовой корреляции координаты являются прямоугольными координатами, поэтому (16.2986, 36.9105) являются (x, y). Масштаб рассчитывается как

scale = log ((x ^ 2 + y ^ 2) ^ 0,5), что примерно 1,6 (около 1,5).

Когда мы вычисляем угол, используя формулы: theta = arctan (y/x) = 66 (приблизительно). Значение theta - это реальное значение (в данном случае - 45).

Ответ 5

Этот поток был полезен, когда я начал работать с вращением-инвариантной фазовой корреляцией, поэтому я надеюсь, что мой вклад поможет решить любые затяжные проблемы.

Мы стремимся рассчитать масштаб и поворот (который неправильно вычисляется в коде). Начнем с сбора уравнений из logPolar docs. Там они заявляют следующее:

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

Примечание: rho - pt.x, а phi - pt.y в коде выше

Мы также знаем, что

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

Во-первых, разрешите масштаб. Решая для величины (I) (т.е. Масштаб) в уравнении 2, получим

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

Тогда подставим M и упростим, чтобы получить

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

Теперь разрешите для вращения. Решая для угла (I) (т.е. Вращения) в уравнении 3, получим

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

Тогда подставим для Ky и упростим, чтобы получить

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

Таким образом, масштаб и вращение могут быть рассчитаны с использованием уравнений 7 и 9 соответственно. Возможно, стоит отметить, что для расчета M и Point2f center( (float)a.cols/2, (float)a.rows/2 ) следует использовать уравнение 4 для вычисления центра в отличие от того, что находится в коде выше. Есть хорошие фрагменты информации в этом logpolar example opencv code.