Оказывается, я был неправ в некоторых местах, так что я решил переписать этот ответ.
Вкратце - вы получаете странные результаты из-за неправильной внутренней матрицы параметров.
Использование терминологии из статьи «Малис, E и Варгас, М», «Более глубокое понимание разложения гомографии для управления на основе зрения» (на котором основано разложение гомографии в OpenCV), перспективное преобразование обозначается Н и называется евклидово гомография матрица, и результатом ее нормализации гайанских = к^-1 * Н * к (где к является калибровка матрицы камеры) называется матрица гомографии
И cv::findHomography()
cv::decomposeHomographyMat()
и работа с евклидовой гомографией матрицей. Но для того, чтобы разложить его на сдвиг и вращение, cv::decomposeHomographyMat()
нормализует Евклидовую гомографическую матрицу для получения гомографическая матрица. Он полагается на K, предоставленный от пользователя, для выполнения этой нормализации.
Что касается оценки K, я думаю, что это выходит за рамки этого вопроса. Эта проблема называется Camera auto-calibration, вот соответствующая цитата из этой вики статьи:
Таким образом, три вида является минимально необходимым для полной калибровки с фиксированными внутренними параметрами между видами. Современные датчики и оптические датчики качества также могут обеспечить дополнительные предварительные ограничения на калибровку, такие как нулевое отклонение (сетка ортогонального пикселя) и единичное соотношение сторон (квадратные пиксели). Интеграция этих приоритетов уменьшит минимальное количество изображений, необходимых для двух.
кажется, что вы можете извлечь K из Correspondances изображения в течение 2 кадров из одной и той же камеры при нулевой перекоса и квадратными допущений пикселей. Но я не знаком с этой темой, поэтому не могу дать вам больше предложений.
Итак, чтобы проверить правильность моей интерпретации, я сделал небольшой пример, который проектирует некоторые точки на плоскости в 3D на двух виртуальных камерах, находит гомографию, разлагает ее и позволяет сравнивать это разложение с земной истиной векторы вращения и трансляции. Это лучше, чем реальные входы, потому что таким образом мы точно знаем 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]
Как вы можете видеть, есть правильная оценка вектора вращения между гипотезой и есть вверх правильная оценка перевода.
Вы проверили, что вычисленная гомография не равна нулю? – SpamBot
@SpamBot Да, вычисленная гомография (с очень небольшим округлением): [1 0 -50; 0 1 0; 0 0 1]. – IlliteratePhD
Это всего лишь догадка, может быть, разложениеHomographyMat не обрабатывает специальный случай аффинной гомографии? – SpamBot