1

Я пытаюсь найти евклидово преобразования между двумя камерами (или на самом деле, одна двигающейся камерой), захватив ту же сцену, где данные калибровок K (внутренний PARAMS) и d (коэффициенты искажения). Я делаю это путем извлечения точек отличия, сопоставления их и использования лучших совпадений в качестве соответствий.undistort против undistortPoints для сопоставления характеристик калиброванных изображений

Перед изменением размера/обнаружением признаков/и т.д. Я undistort оба изображения

undistort(img_1, img_1_undist, K, d); 
undistort(img_2, img_2_undist, K, d); 

, где img_. являются входами в Mat форме, полученные imread. Но на самом деле мне нужны только неискаженные координаты функций, которые я в конечном итоге использую в качестве соответствий, а не для всех пикселей изображения, поэтому было бы более эффективным, а не undistort всего изображения, а только ключевые точки. Я думал, что смогу сделать это с помощью undistortPoints, однако оба подхода приведут к разным результатам.

изменить размер изображения

resize(img_1_undist, img_1_undist, Size(img_1_undist.cols/resize_factor, 
      img_1_undist.rows/args.resize_factor)); 
resize(img_2_undist, img_2_undist, Size(img_2_undist.cols/resize_factor, 
      img_2_undist.rows/args.resize_factor)); 
// scale matrix down according to changed resolution 
camera_matrix = camera_matrix/resize_factor; 
camera_matrix.at<double>(2,2) = 1; 

После получения лучших матчей в matches я строю std::vector с для координат указанных матчей,

// Convert correspondences to vectors 
    vector<Point2f>imgpts1,imgpts2; 
    cout << "Number of matches " << matches.size() << endl; 
    for(unsigned int i = 0; i < matches.size(); i++) 
    { 
     imgpts1.push_back(KeyPoints_1[matches[i].queryIdx].pt); 
     imgpts2.push_back(KeyPoints_2[matches[i].trainIdx].pt); 
    } 

который я затем использовать для нахождения существенной матрицы.

Mat mask; // inlier mask 
    vector<Point2f> imgpts1_undist, imgpts2_undist; 
    imgpts1_undist = imgpts1; 
    imgpts2_undist = imgpts2; 
    /* undistortPoints(imgpts1, imgpts1_undist, camera_matrix, dist_coefficients,Mat(),camera_matrix); // this doesn't work */ 
    /* undistortPoints(imgpts2, imgpts2_undist, camera_matrix, dist_coefficients,Mat(),camera_matrix); */ 
    Mat E = findEssentialMat(imgpts1_undist, imgpts2_undist, 1, Point2d(0,0), RANSAC, 0.999, 8, mask); 

Когда я удалить вызовы undistort и вместо того, чтобы позвонить undistortPoints на ключевые точки, она не производит тот же результат (который я бы ожидать). Различия иногда незначительны, но всегда там.

Я прочитал в документации по

Функция аналогична сортом :: undistort и резюме :: initUndistortRectifyMap, но она работает на разреженное множестве точек вместо растрового изображения.

такой, что функция должна делать то, что я ожидаю. Что я делаю неправильно?

ответ

5

Вы видите несоответствие, потому что неискаженное изображение и неискаженное множество точек работают по-разному.

Изображения неиспочитываются, используя inverse mapping, который является тем же самым методом, который обычно используется для всех преобразований геометрического изображения, таких как вращение. Сначала вы создаете сетку выходных изображений, а затем преобразуете каждый пиксель в выходное изображение обратно во входное изображение и получаете значение путем интерполяции.

Поскольку ваше выходное изображение содержит «правильные» точки, вы должны «исказить» их, чтобы преобразовать их в исходное изображение. Другими словами, вы просто применяете уравнения искажения.

С другой стороны, если вы берете точки со своего входного изображения и пытаетесь устранить искажения, вам нужно будет инвертировать уравнения искажения. Это очень сложно сделать, потому что эти уравнения являются многочленами 4-й или 6-й степени. Таким образом, undistortPoints делает это численно, используя градиентный спуск, который будет иметь некоторую ошибку.

Подводя итог: функция undistort неисказывает все изображение, которое может быть излишним, но оно делает это довольно точно. Если вас интересует только небольшой набор точек, то undistortPoints, скорее всего, будет быстрее, но, скорее всего, будет иметь более высокую ошибку.

+0

* найти исходную точку с искаженной * - Как эта проблема отличается от того, что 'undistort' должно делать со всеми точками изображения? – oarfish

+2

Когда вы искажаете изображение, вы итеративно делаете это: «Я нахожусь в позиции пикселя (i, j) неискаженного изображения: на каком пикселе (i_d, j_d) искаженного изображения мне нужно выбрать цвет, который мне нужно заполнить (ij)? Ответ (i_d, j_d) = distortion_function (i, j) «Как писал Дима, это легко вычислить: пару полиномиальных оценок. Чтобы не исказить точку (i_d, j_d) для восстановления (i, j), вместо этого вам необходимо оценить обратное значение функции distortion_function, что включает в себя решение уравнения многочлена. –

+0

@oarfish, я отредактировал ответ, чтобы уточнить. – Dima

Смежные вопросы