У меня довольно простая задача: получить углы Эйлера от плоского треугольника. Шаблон выглядит этот
Итак, алгоритм:
1) получить изображение с веб-камеры — готово
2) конвертировать в гряскале, фильтровать и т. Д. — сделано
3) получить центры масс всех подключенных компонентов и отфильтровать их — готово. Похоже этот. Красные круги описывают центры масс вершин треугольников.
Код довольно прост, но вот он:
QMap<int, QVector<double> > massCenters(const cv::Mat& image)
{
cv::Mat output(IMAGE_WIDTH, IMAGE_HEIGHT, CV_32S);
cv::connectedComponents(image, output, 8);
QMap<int, QVector<double> > result;
for (int y = 0; y < IMAGE_HEIGHT; ++y)
{
for (int x = 0; x < IMAGE_WIDTH; ++x)
{
int label = output.at<int>(y, x);
if (label)
{
QVector<double> vec = result.value(label, QVector<double>());
if (vec.isEmpty())
{
vec.resize(3);
vec.fill(0);
}
vec[0] += x;
vec[1] += y;
vec[2] += 1;
result[label] = vec;
}
}
}
return result;
}
4) затем я вызываю решениеPNP, чтобы получить ротацию & векторы перевода
cv::solvePnP(m_origin, m_imagePoints, m_cameraMatrix, m_distMatrix, m_rvec, m_tvec);
//this code is for drawing rvec & tvec on a screen
std::vector<cv::Point3f> axis;
vector<cv::Point2f> axis2D;
axis.push_back(Point3f(0.0f, 0.0f, 0.0f));
axis.push_back(Point3f(30.0f, 0.0f, 0.0f));
axis.push_back(Point3f(0.0f, 30.0f, 0.0f));
axis.push_back(Point3f(0.0f, 0.0f, 30.0f));
cv::projectPoints(axis, m_rvec, m_tvec, m_cameraMatrix, m_distMatrix, axis2D);
cv::line(m_orig, axis2D[0], axis2D[1], cv::Scalar(255, 0, 0), 2);
cv::line(m_orig, axis2D[0], axis2D[2], cv::Scalar(0, 255, 0), 2);
cv::line(m_orig, axis2D[0], axis2D[3], cv::Scalar(0, 0, 255), 2);
m_origin объявлен как std::vector<cv::Point3f> m_origin;
и заполняется значениями (измеряется в мм)
m_origin.push_back(cv::Point3f( 0.0f, 51.0f, 0.0f));
m_origin.push_back(cv::Point3f(-56.0f, -26.0f, 0.0f));
m_origin.push_back(cv::Point3f( 56.0f, -26.0f, 0.0f));
m_imagePoints объявлен как std::vector<cv::Point2f> m_imagePoints;
и содержит пиксельные координаты центров масс (красные кружки на втором экране).
И я получаю довольно странные результаты: от этот в тот
Что я пробовал, и это не помогло мне:
1) использовали типы double и float в m_cameraMatrix, m_distMatrix, m_rvec, m_tvec
2) переставить точки в м_оригине
3) поиграл с solvePnPRansac и его входными параметрами
4) играется с помощью методов pnp: итеративный и epnp
5) useExtrinsicGuess = true — это помогает, но иногда решение «застревает» и дает совершенно неправильные значения (тысяча градусов в векторе вращения)
И у меня есть несколько вопросов:
1) имеет ли значение пункт происхождения и точки изображения? Как уже упоминалось Вот, иногда это происходит, но это было год назад.
2) может ли моя задача быть решена не так, как с помощью solvePnP?
Благодарю. Буду признателен за любую помощь!
solvePnPRansac
не подходит в вашем случае, так как вам не нужно иметь дело с данными выбросов.
Я предполагаю, что проблема, которую вы наблюдаете, проистекает из выбранной вами схемы:
Но, на мой взгляд, это более или менее похоже, так как использование только 3-х точек, так как 4-я точка, которую вы добавляете, является барицентром треугольника и не должна давать никакой дополнительной информации в задаче оценки позы.
Что касается задачи оценки позы из 3-х точек (P3P), существует до четырех возможных решений, и неоднозначность может быть устранена с помощью 4-й точки. Некоторые упоминания об этом:
Я рекомендую вместо этого использовать квадратную форму из 4 точек и проверить, наблюдаете ли вы ту же проблему (P3P
флаг должен быть в порядке). Если да, то проблема в коде или в калибровке.
Здесь статья, на мой взгляд, более или менее связана с этой проблемой: Почему Цилиндр Опасности Опасен в Проблеме P3P?. Цифра на случай, если ссылка станет недоступной:
Других решений пока нет …