平面三角形的 solvePNP
solvePNP for planar triangle
我有一个很简单的任务:得到平面三角形的欧拉角。模式看起来像 this
所以,算法:
1) 从网络摄像头获取图像 -- 完成
2) 转换为灰阶、过滤器等 -- 完成
3) 获取所有连接组件的质量中心,并过滤它们——完成。看起来像 this。红色圆圈表示三角形顶点的质心。
代码很简单,但这里是:
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) 然后我调用 solvePNP 来获取旋转和平移向量
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) 在 m_cameraMatrix、m_distMatrix、m_rvec、m_tvec
中使用了 double 和 float 类型
2) m_origin
中重新排列的点
3) 使用 solvePnPRansac 及其输入参数
4) 使用 pnp 方法:迭代和 epnp
5) useExtrinsicGuess=true -- 它有帮助,但有时解决方案是 "stuck" 并给出完全错误的值(旋转向量中的千度)
我有几个问题:
1) 原点顺序和图像点重要吗?如前所述 here,有时会,但那是一年前的事了。
2) 除了使用 solvePnP,我的任务是否可以通过其他方式解决?
谢谢。非常感谢任何帮助!
solvePnPRansac
不适用于您的情况,因为您不必处理异常数据。
我的猜测是您观察到的问题来自您选择的模式:
- 是3分
- 然后添加三角形的质心
但在我看来,它或多或少类似于仅使用 3 个点,因为您添加的第 4 个点是三角形的重心,不应在姿势估计问题中提供任何额外信息。
关于3点姿态估计问题(P3P),最多有4种可能的解,使用第4点可以去除歧义。关于此的一些参考资料:
- 3D Pose Estimation by Sebastian Grembowietz
- The Perspective View of 3 Points
- Pose from Point Correspondences P3P
- [math] – The P3P (Perspective-Three-Point) Principle
我的建议是改用 4 点正方形并测试是否观察到相同的问题(P3P
标志应该没问题)。如果是,则代码或校准有问题。
我认为这里有一篇论文或多或少与这个问题有关:Why is the Danger Cylinder Dangerous in the P3P Problem?。 link不可用时的数字:
我有一个很简单的任务:得到平面三角形的欧拉角。模式看起来像 this
所以,算法:
1) 从网络摄像头获取图像 -- 完成
2) 转换为灰阶、过滤器等 -- 完成
3) 获取所有连接组件的质量中心,并过滤它们——完成。看起来像 this。红色圆圈表示三角形顶点的质心。
代码很简单,但这里是:
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) 然后我调用 solvePNP 来获取旋转和平移向量
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) 在 m_cameraMatrix、m_distMatrix、m_rvec、m_tvec
中使用了 double 和 float 类型2) m_origin
中重新排列的点3) 使用 solvePnPRansac 及其输入参数
4) 使用 pnp 方法:迭代和 epnp
5) useExtrinsicGuess=true -- 它有帮助,但有时解决方案是 "stuck" 并给出完全错误的值(旋转向量中的千度)
我有几个问题:
1) 原点顺序和图像点重要吗?如前所述 here,有时会,但那是一年前的事了。
2) 除了使用 solvePnP,我的任务是否可以通过其他方式解决?
谢谢。非常感谢任何帮助!
solvePnPRansac
不适用于您的情况,因为您不必处理异常数据。
我的猜测是您观察到的问题来自您选择的模式:
- 是3分
- 然后添加三角形的质心
但在我看来,它或多或少类似于仅使用 3 个点,因为您添加的第 4 个点是三角形的重心,不应在姿势估计问题中提供任何额外信息。
关于3点姿态估计问题(P3P),最多有4种可能的解,使用第4点可以去除歧义。关于此的一些参考资料:
- 3D Pose Estimation by Sebastian Grembowietz
- The Perspective View of 3 Points
- Pose from Point Correspondences P3P
- [math] – The P3P (Perspective-Three-Point) Principle
我的建议是改用 4 点正方形并测试是否观察到相同的问题(P3P
标志应该没问题)。如果是,则代码或校准有问题。
我认为这里有一篇论文或多或少与这个问题有关:Why is the Danger Cylinder Dangerous in the P3P Problem?。 link不可用时的数字: