У меня есть приложение на c ++, которое использует фидуциальные маркеры Apriltags3.
Они кажутся быстрыми и стабильными, за исключением случая, когда маркер направлен горизонтально к камере или около нее.
в этих случаях поза значительно меняется, делая данные позы непригодными для использования. Как я понимаю, это переворот - известная проблема с квадратными маркерами, поскольку есть два возможных решения для оценки позы.
Как я могу улучшить это переворот? Я попытался:
1 - Используя SolvePnp с флагом IPPE_SQUARE, я могу вернуть оба решения.
std::vector<cv::Vec3d> rvecsVec, tvecsVec;
std::vector<double> errs;
solvePnPGeneric(markerObjPoints, marker.corners2d, K, D, rvecsVec, tvecsVec, false, cv::SOLVEPNP_IPPE_SQUARE, cv::noArray(), cv::noArray(),errs);
, затем я выбираю позу, ближайшую к предыдущей. это работает хорошо до тех пор, пока вращение позы не пройдет ноль (от положительного к отрицательному значению), а затем ось вращения перевернется.
2 - сохранение предыдущих нескольких поз и выполнение регулировки связки скользящего окна на 3-х точках, 2d углы и позы. Это, кажется, не имеет никакого эффекта, и я все еще вижу тот же переворот.
3 - Использование следующего:
cv::Mat R1;
cv::Rodrigues(rvecsVec[0], R1);
R1 = R1.t();
cv::Mat t1 = -R1 * tvecsVec[0];
cv::Mat R2;
cv::Rodrigues(rvecsVec[1], R2);
R2 = R2.t();
cv::Mat t2 = -R2 * tvecsVec[1];
Чтобы получить позы камеры относительно маркеров. Я бы предположил, что поза камеры с положительным значением X (перед маркером) будет правильной, однако, когда я использую эту позу:
if (t1.at<double>(0, 0) < 0)
{
marker.rvec = rvecsVec[0];
marker.tvec = tvecsVec[0];
std::cout << "using pose 0" << std::endl;
}
if (t2.at<double>(0, 0) < 0)
{
marker.rvec = rvecsVec[1];
marker.tvec = tvecsVec[1];
std::cout << "using pose 1" << std::endl;
}
Я вижу ту же проблему, что и с решение 1.
4 - используя стереокамеру, найдите маркеры в каждом кадре, триангулируйте точки и затем используйте функцию Eigen SVD, чтобы найти жесткое преобразование между этими точками и набором точек, созданных из длины маркера в ноль.
PointsType p1s, p2s;
p1s.push_back(Eigen::Vector3d(-markerLength / 2.f, markerLength / 2.f, 0));
p1s.push_back(Eigen::Vector3d(markerLength / 2.f, markerLength / 2.f, 0));
p1s.push_back(Eigen::Vector3d(markerLength / 2.f, -markerLength / 2.f, 0));
p1s.push_back(Eigen::Vector3d(-markerLength / 2.f, -markerLength / 2.f, 0));
Это прекрасно работает для перевода, но вращение, кажется, переворачивается еще больше!
Есть ли ответ для этого? Что еще я могу попробовать?
Примечание: я проверил с маркерами Aruco, той же камерой и калибровкой, и я не вижу этой проблемы с переворотом, это похоже на проблему с Apriltags3.