Opencv: устранить ошибку PNP, сбой EPNP и P3P

#opencv #p-np

#opencv #p-np

Вопрос:

Я пытаюсь сравнить точность и время, затрачиваемые на каждую возможность solvePnP: CV_ITERATIVE, CV_EPNP и CV_P3P

Я также сравнил свой результат с Matlab EPNP.

И похоже, что EPNP и P3P потерпели неудачу :

 std::vector<cv::Point2f> imgPoints;
imgPoints.push_back(cv::Point2f(400,188));
imgPoints.push_back(cv::Point2f(400,300));
imgPoints.push_back(cv::Point2f(512,300));
imgPoints.push_back(cv::Point2f(512,188));

double size = 80.0;
std::vector<cv::Point3f> objPoints;
objPoints.push_back(cv::Point3f(0,0,0));
objPoints.push_back(cv::Point3f(0,size,0));
objPoints.push_back(cv::Point3f(size,size,0));
objPoints.push_back(cv::Point3f(size,0,0));

cv::Mat rvec0 = cv::Mat::zeros(3, 1, CV_64FC1);
cv::Mat tvec0 = cv::Mat::zeros(3, 1, CV_64FC1);

cv::Mat rvec1 = cv::Mat::zeros(3, 1, CV_64FC1);
cv::Mat tvec1 = cv::Mat::zeros(3, 1, CV_64FC1);

cv::Mat rvec2 = cv::Mat::zeros(3, 1, CV_64FC1);
cv::Mat tvec2 = cv::Mat::zeros(3, 1, CV_64FC1);

cv::Mat cam, coeff;
cam = (cv::Mat_<double>(3,3) << 700,0,300,0,700,400,0,0,1);
cv::solvePnP(objPoints,imgPoints,cam,coeff,rvec0,tvec0,CV_ITERATIVE);
cv::solvePnP(objPoints,imgPoints,cam,coeff,rvec1,tvec1,CV_P3P);
cv::solvePnP(objPoints,imgPoints,cam,coeff,rvec2,tvec2,CV_EPNP);

cv::Mat rmat0,rmat1,rmat2;
cv::Rodrigues(rvec0,rmat0);
cv::Rodrigues(rvec1,rmat1);
cv::Rodrigues(rvec2,rmat2);

std::cout << "ITERATIVE : Rotation matrix : " << std::endl << rmat0 << std::endl;
std::cout << "ITERATIVE : Tranlation vector : " << std::endl << tvec0 << std::endl << std::endl;

std::cout << "P3P : Rotation matrix : " << std::endl << rmat1 << std::endl;
std::cout << "P3P : Tranlation vector : " << std::endl << tvec1 << std::endl << std::endl;

std::cout << "EPNP : Rotation matrix : " << std::endl << rmat2 << std::endl;
std::cout << "EPNP : Tranlation vector : " << std::endl << tvec2  << std::endl << std::endl;
  

Дайте мне :

ИТЕРАТИВНАЯ: матрица вращения: [1, -2.196885546074445e-016, 9.692430825310778e-016; 2.196885546074445e-016, 1, 1.012059558506939e-015; -9.692430825310778e-016, -1.012059558506939e-015 , 1]

ИТЕРАТИВНЫЙ: вектор перевода: [71.42857142857143; -151.4285714285714; 500]

P3P: матрица вращения : [1, 0, 0; 0, 1, 0; 0, 0, 1]

P3P: вектор перевода: [-3.97771428571427e-015; -4.022285714285698e-015; 9.989999999999962e-017]

EPNP: матрица вращения : [1, 0, 0; 0, 1, 0; 0, 0, 1]

EPNP: вектор перевода: [-3.97771428571427e-015; -4.022285714285698e-015; 9.989999999999962e-017]

Есть предложения?

Александр Корнманн

Комментарии:

1. Вы пробовали другие точки данных и больше (4>) данных?

2. Я пробовал другие точки данных, иногда это работает успешно, иногда нет. Но для моего приложения мне нужно: оно всегда работает успешно… Я пробовал также с 16 точками, иногда это работает успешно, иногда нет…

Ответ №1:

У меня есть подсказки для вас, некоторые вещи кажутся мне странными :

  1. Вы даете (300 400) для центральной точки в матрице cam, поэтому ваше изображение имеет размер 600 * 800 (по вертикали)?
  2. Для положения проекции ваших 2D-точек убедитесь, что вы разместили их способом OpenCV: точка (0,0) на изображении — это верхний левый угол.
  3. Ваши точки копланарны (плоскость z = 0), и, возможно, solvePnP чувствителен к этому.

Комментарии:

1. 1: Верно, это ошибка, но использование 400,300 исправляет только итеративную ошибку, которая у меня была, когда я проверял свой результат с помощью Matlab. EPNP и P3P по-прежнему нестабильны. 2. Порядок OpenCV = верхний / левый -> нижний-> левый -> нижний / правый -> верхний правый? (400,188) -> (400,300) -> (512,300) -> (512,188) => (0,0,0) -> (0,1,0) -> (1,1,0) -> (1,0,0) 3. Да, я слышал о чувствительности PnP для копланарной точки. Но для AR мой маркер плоский…

2. Другой подсказкой от службы поддержки OpenCV было использование 3D-координаты точки в диапазоне [-1;1] вместо [0;80]. При этом CV_ITERATIVE, CV_P3p, CV_EPNP дают отличные результаты, но на самом деле это не совсем интуитивный способ использования координат в реальном пространстве… Но это работает для следующего, кто застрял, как я 🙂

Ответ №2:

P3P — не очень хороший метод, его точность очень низкая.EPNP кажется лучшим выбором по точности.Но вы не должны использовать только EPNP, с алгоритмом Ransac будет лучше.