Оказывается, я был не прав в некоторых моментах, поэтому я решил переписать этот ответ.
Короче говоря, вы получаете странные результаты из-за неправильной матрицы внутренних параметров.
Используя терминологию из статьи «Малис, Э. и Варгас, М., «Углубленное понимание гомографической декомпозиции для управления на основе зрения» (на которой основана гомографическая декомпозиция в OpenCV), перспективное преобразование обозначается H и называется евклидовой матрицей гомографии, а результат ее нормализации G = K^-1 * H< /strong> * K (где K — калибровочная матрица камеры) называется матрицей гомографии
И cv::findHomography()
, и cv::decomposeHomographyMat()
работают с евклидовой матрицей гомографии. Но чтобы разложить его на перемещение и вращение, cv::decomposeHomographyMat()
нормализует евклидову матрицу гомографии, чтобы получить матрицу гомографии. Он использует K, предоставленный пользователем, для выполнения этой нормализации.
Что касается оценки K, я думаю, что это выходит за рамки данного вопроса. Эта проблема называется автокалибровкой камеры. Вот соответствующая цитата из этой вики-статьи:
Таким образом, три просмотра — это минимум, необходимый для полной калибровки с фиксированными внутренними параметрами между просмотрами. Качественные современные датчики изображения и оптика могут также обеспечивать дополнительные предварительные ограничения на калибровку, такие как нулевой перекос (ортогональная пиксельная сетка) и единичное соотношение сторон (квадратные пиксели). Интеграция этих априорных значений уменьшит минимальное количество необходимых изображений до двух.
Кажется, что вы можете извлечь K из соответствий изображений по двум кадрам с одной и той же камеры при нулевом перекосе и предположениях о квадратных пикселях. Но я не знаком с этой темой, поэтому не могу дать вам больше предложений.
Итак, чтобы проверить правильность моей интерпретации, я сделал небольшой пример, который проецирует некоторые точки на плоскости в 3D на 2 виртуальные камеры, находит гомографию, разлагает ее и позволяет сравнить это разложение с векторами вращения и переноса наземной истины. . Это лучше, чем реальные входные данные, потому что таким образом мы точно знаем K и можем отделить ошибку в его оценке от ошибки в R и t. . Для входных данных, которые я проверил, он смог правильно оценить векторы поворота и смещения, хотя по какой-то причине перевод всегда меньше, чем земная правда в 10 раз. Может быть, это разложение определено только до масштаба (сейчас я не уверен), но интересно, что оно связано с наземным значением истинности с фиксированным коэффициентом.
Вот источник:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
int main() {
// set up a virtual camera
float f = 100, w = 640, h = 480;
cv::Mat1f K = (cv::Mat1f(3, 3) <<
f, 0, w/2,
0, f, h/2,
0, 0, 1);
// set transformation from 1st to 2nd camera (assume K is unchanged)
cv::Mat1f rvecDeg = (cv::Mat1f(3, 1) << 45, 12, 66);
cv::Mat1f t = (cv::Mat1f(3, 1) << 100, 200, 300);
std::cout << "-------------------------------------------\n";
std::cout << "Ground truth:\n";
std::cout << "K = \n" << K << std::endl << std::endl;
std::cout << "rvec = \n" << rvecDeg << std::endl << std::endl;
std::cout << "t = \n" << t << std::endl << std::endl;
// set up points on a plane
std::vector<cv::Point3f> p3d{{0, 0, 10},
{100, 0, 10},
{0, 100, 10},
{100, 100, 10}};
// project on both cameras
std::vector<cv::Point2f> Q, P, S;
cv::projectPoints(p3d,
cv::Mat1d::zeros(3, 1),
cv::Mat1d::zeros(3, 1),
K,
cv::Mat(),
Q);
cv::projectPoints(p3d,
rvecDeg*CV_PI/180,
t,
K,
cv::Mat(),
P);
// find homography
cv::Mat H = cv::findHomography(Q, P);
std::cout << "-------------------------------------------\n";
std::cout << "Estimated H = \n" << H << std::endl << std::endl;
// check by reprojection
std::vector<cv::Point2f> P_(P.size());
cv::perspectiveTransform(Q, P_, H);
float sumError = 0;
for (size_t i = 0; i < P.size(); i++) {
sumError += cv::norm(P[i] - P_[i]);
}
std::cout << "-------------------------------------------\n";
std::cout << "Average reprojection error = "
<< sumError/P.size() << std::endl << std::endl;
// decompose using identity as internal parameters matrix
std::vector<cv::Mat> Rs, Ts;
cv::decomposeHomographyMat(H,
K,
Rs, Ts,
cv::noArray());
std::cout << "-------------------------------------------\n";
std::cout << "Estimated decomposition:\n\n";
std::cout << "rvec = " << std::endl;
for (auto R_ : Rs) {
cv::Mat1d rvec;
cv::Rodrigues(R_, rvec);
std::cout << rvec*180/CV_PI << std::endl << std::endl;
}
std::cout << std::endl;
std::cout << "t = " << std::endl;
for (auto t_ : Ts) {
std::cout << t_ << std::endl << std::endl;
}
return 0;
}
И вот вывод на моей машине:
-------------------------------------------
Ground truth:
K =
[100, 0, 320;
0, 100, 240;
0, 0, 1]
rvec =
[45;
12;
66]
t =
[100;
200;
300]
-------------------------------------------
Estimated H =
[0.04136041220427821, 0.04748763375951008, 358.5557917287962;
0.05074854454707714, 0.06137211243830468, 297.4585754092336;
8.294458769850147e-05, 0.0002294875562580223, 1]
-------------------------------------------
Average reprojection error = 0
-------------------------------------------
Estimated decomposition:
rvec =
[-73.21470385654712;
56.64668212487194;
82.09114210289061]
[-73.21470385654712;
56.64668212487194;
82.09114210289061]
[45.00005330430893;
12.00000697952995;
65.99998380038915]
[45.00005330430893;
12.00000697952995;
65.99998380038915]
t =
[10.76993852870029;
18.60689642878277;
30.62344129378435]
[-10.76993852870029;
-18.60689642878277;
-30.62344129378435]
[10.00001378255982;
20.00002581449634;
30.0000336510648]
[-10.00001378255982;
-20.00002581449634;
-30.0000336510648]
Как видите, среди гипотез есть правильная оценка вектора вращения, а в масштабе есть правильная оценка перевода.
person
alexisrozhkov
schedule
11.03.2016