Подтвердить что ты не робот

FindHomography, getPerspectiveTransform, & getAffineTransform

Этот вопрос посвящен функциям OpenCV findHomography, getPerspectiveTransform и getAffineTransform

  • В чем разница между findHomography и getPerspectiveTransform?. Мое понимание из документации заключается в том, что getPerspectiveTransform вычисляет преобразование с использованием 4 соответствий (что является минимальным требованием для вычисления преобразования гомографии/перспективы), где findHomography вычисляет преобразование, даже если вы предоставляете более 4 соответствий (предположительно, используя что-то как метод наименьших квадратов?). Это верно? (В этом случае единственная причина, по которой OpenCV по-прежнему продолжает поддерживать getPerspectiveTransform, должна быть старой?)

  • Моя следующая проблема заключается в том, что я хочу знать, есть ли эквивалент findHomography для вычисления Аффинного преобразования? то есть функцию, которая использует наименьшие квадраты или эквивалентный надежный метод для вычисления и аффинного преобразования. Согласно документации getAffineTransform принимает только 3 соответствия (которые являются минимальными, необходимыми для вычисления аффинного преобразования).

Бест,

4b9b3361

Ответ 1

Q # 1: справа, findHomography пытается найти лучшее преобразование между двумя наборами точек. Он использует что-то более умное, чем наименьшие квадраты, называемое RANSAC, которое имеет возможность отклонять выбросы - если по крайней мере 50% + 1 ваших точек данных в порядке, RANSAC сделает все возможное, чтобы найти их и построить надежное преобразование.

У getPerspectiveTransform есть много полезных причин оставаться - это база для findHomography, и она полезна во многих ситуациях, когда у вас всего 4 балла, и вы знаете, что они правильные. FindHomography обычно используется с множеством точек, обнаруженных автоматически - вы можете найти многие из них, но с низкой степенью уверенности. getPerspectiveTransform хорош, когда вы наверняка знаете 4 угла - например, ручную маркировку или автоматическое обнаружение прямоугольника.

Q # 2 Нет эквивалента для аффинных преобразований. Вы можете использовать findHomography, потому что аффинные преобразования являются подмножеством гомографий.

Ответ 2

Я согласен со всем, что написал @vasile. Я просто хочу добавить несколько замечаний:

getPerspectiveTransform() и getAffineTransform() предназначены для работы с 4 или 3 точками (соответственно), которые, как известно, являются правильными соответствиями. На реальных снимках, сделанных с реальной камерой, вы можете никогда получать соответствия, которые точны, а не с автоматической или ручной маркировкой соответствующих точек.

Всегда есть выбросы. Просто взгляните на простой случай, когда вам нужно подогнать кривую через точки (например, взять генеративное уравнение с шумом y1 = f(x) = 3.12x + gauss_noise или y2 = g(x) = 0.1x^2 + 3.1x + gauss_noise): гораздо проще найти хорошую квадратичную функцию для оценки точек в обоих случаях, чем хороший линейный. Квадратичный может быть излишним, но в большинстве случаев не будет (после удаления выбросов), и если вы хотите установить прямую линию там, вам лучше быть уверенным, что это правильная модель, иначе вы получите непригодные результаты.

Тем не менее, если вы твердо уверены, что аффинное преобразование является правильным, вот предложение:

  • используйте findHomography, у которого RANSAC включен в функциональность, чтобы избавиться от выбросов и получить начальную оценку преобразования изображения.
  • выберите 3 правильных соответствия соответствия (которые соответствуют найденной гомографии) или перепрограммируют 3 точки от 1-го изображения до второго (используя гомографию).
  • используйте эти 3 совпадения (которые как можно ближе к правилу, как вы можете получить) в getAffineTransform()
  • оберните все это в свой собственный findAffine(), если хотите - и voila!

Ответ 3

Re Q # 2, оценкаRigidTransform - это избыточный эквивалент getAffineTransform. Я не знаю, было ли это в OCV, когда это было впервые опубликовано, но доступно в 2.4.

Ответ 4

Существует простое решение для нахождения Аффинного преобразования для системы переопределенных уравнений.

  • Заметим, что в общем случае Аффинное преобразование находит решение для переопределенной системы линейных уравнений Ax = B с использованием псевдоинверсивного или аналогичного метода, поэтому

x = (A A t) -1 A t B

Кроме того, это обрабатывается в функциональности ядра openCV простым вызовом для решения (A, B, X).

  1. Ознакомьтесь с кодом Аффинного преобразования в opencv/modules/imgproc/src/imgwarp.cpp: он действительно выполняет только две вещи:

    а. перестраивает входы для создания системы Ax = B;

    б. затем вызывает решение (A, B, X);

ПРИМЕЧАНИЕ: игнорируйте комментарии к функциям в коде openCV - они запутывают и не отражают фактический порядок элементов в матрицах. Если вы решаете [u, v] = Affine * [x, y, 1], то перестановка состоит из:

         x1 y1 1 0  0  1
         0  0  0 x1 y1 1
         x2 y2 1 0  0  1
    A =  0  0  0 x2 y2 1
         x3 y3 1 0  0  1
         0  0  0 x3 y3 1

    X = [Affine11, Affine12, Affine13, Affine21, Affine22, Affine23]’

         u1 v1
    B =  u2 v2
         u3 v3 

Все, что вам нужно сделать, это добавить больше очков. Чтобы заставить Solve (A, B, X) работать над переопределенной системой, добавьте параметр DECOMP_SVD. Чтобы увидеть слайды powerpoint по этой теме, используйте ссылку . Если вам нравится больше узнать о псевдо-обратном в контексте компьютерного видения, лучшим источником является "ComputerVision" , см. Главу 15 и приложение C.

Если вы все еще не уверены, как добавить больше очков, см. мой код ниже:

// extension for n points;
cv::Mat getAffineTransformOverdetermined( const Point2f src[], const Point2f dst[], int n )
{
    Mat M(2, 3, CV_64F), X(6, 1, CV_64F, M.data); // output
    double* a = (double*)malloc(12*n*sizeof(double));
    double* b = (double*)malloc(2*n*sizeof(double));
    Mat A(2*n, 6, CV_64F, a), B(2*n, 1, CV_64F, b); // input

    for( int i = 0; i < n; i++ )
    {
        int j = i*12;   // 2 equations (in x, y) with 6 members: skip 12 elements
        int k = i*12+6; // second equation: skip extra 6 elements
        a[j] = a[k+3] = src[i].x;
        a[j+1] = a[k+4] = src[i].y;
        a[j+2] = a[k+5] = 1;
        a[j+3] = a[j+4] = a[j+5] = 0;
        a[k] = a[k+1] = a[k+2] = 0;
        b[i*2] = dst[i].x;
        b[i*2+1] = dst[i].y;
    }

    solve( A, B, X, DECOMP_SVD );
    delete a;
    delete b;
    return M;
}

// call original transform
vector<Point2f> src(3);
vector<Point2f> dst(3);
src[0] = Point2f(0.0, 0.0);src[1] = Point2f(1.0, 0.0);src[2] = Point2f(0.0, 1.0);
dst[0] = Point2f(0.0, 0.0);dst[1] = Point2f(1.0, 0.0);dst[2] = Point2f(0.0, 1.0);
Mat M = getAffineTransform(Mat(src), Mat(dst));
cout<<M<<endl;
// call new transform
src.resize(4); src[3] = Point2f(22, 2);
dst.resize(4); dst[3] = Point2f(22, 2);
Mat M2 = getAffineTransformOverdetermined(src.data(), dst.data(), src.size());
cout<<M2<<endl;

Ответ 5

getAffineTransform: аффинное преобразование представляет собой комбинацию перевода, масштабирования, сдвига и вращения https://www.mathworks.com/discovery/affine-transformation.html https://www.tutorialspoint.com/computer_graphics/2d_transformation.htm

getPerspectiveTransform : перспективное преобразование - отображение проекта, введите описание изображения здесь