通过自上而下的相机确定多边形表面旋转的方法

时间:2018-07-31 17:00:34

标签: python opencv scikit-learn scikit-image

我有一个摄像头,该摄像头俯视围绕单轴旋转的表面。我希望能够测量表面的旋转角度。

相机的位置和表面的旋转轴都固定。该表面目前是一种独特的纯色,但我可以选择在表面上绘制特征(如果有帮助的话)。

这是一个在整个范围内移动的动画,显示了不同的外观形状:

enter image description here

到目前为止我的方法:

  1. 记录一系列“校准”图像,其中每个图像中的表面处于已知角度
  2. 为每个图像设置阈值以隔离表面。
  3. 使用cv2.approxPolyDP()查找四个角。我反复遍历各种epsilon值,直到找到一个恰好可以得出4分的值。
  4. 一致地排列点(左上,右上,右下,左下)
  5. 使用atan2计算每个点之间的角度。
  6. 使用角度拟合sklearn linear_model.linearRegression()

通过这种方法,仅使用3个训练图像(覆盖完整的正值,完整的负值和中间位置),我的预测就接近实际值的10%。我对opencv和sklearn都是新手。我应该考虑采取其他措施来提高预测的准确性吗? (可能增加训练图像的数量是一个很大的数目?)

我确实直接将cv2.moments作为模型特征进行了实验,然后进行了一些values derived from the moments的实验,但是它们的表现不及角度。我还尝试使用RidgeCV模型,但它的性能似乎与线性模型差不多。

3 个答案:

答案 0 :(得分:4)

如果我很清楚,您想估计多边形相对于相机的旋转。如果您知道3D对象的长度,则可以使用solvePnP来估计对象的姿态,从中可以获得对象的旋转度。

步骤:

  1. 校准您的网络摄像头,并获得固有矩阵和失真矩阵。

  2. 获取对象角的3D测量值并在2d中找到相应的点。让我假设一个矩形平面物体,并且3d中的角将为(0,0,0),(0、100、0),(100、100、0),(100、0、0)。

  3. 使用solvePnP获取对象的旋转和平移

旋转将是对象沿轴的旋转。 Here您可以找到一个示例来估算头部的姿势,可以对其进行修改以适合您的应用

答案 1 :(得分:1)

您的第一步很好-之后的一切都会变得比必要的复杂得多(如果我理解正确的话)。

不要将其视为“学习”,而应将其视为参考。每当您处于不知道角度的特定位置时,拍照并找到最像它的参考图片。猜猜是那个角度。你完成了! (它们可能是不确定的,也许这种关系不是双向的,但这就是我要开始的地方。)

如果愿意,可以将其视为“最近邻分类器”,但这只是为了使其听起来更好。测量不确定图片与所有参考图片之间的简单距离(欧几里德!为什么不!),这意味着在原始图像矢量之间没有任何花哨的地方,然后选择与观察到的已知距离之间的最小距离对应的角度

如果这不起作用-也许无论如何都要这样做-停止扔掉太多信息!您正在精简内容,然后尝试重新估计它们,到处传播错误,而没有明显的收益(对我而言)。因此,当您与最近的邻居一起时,请参考图片以及所有其他图片,为什么不只使用完整图片呢? (也许其他元素会改变吗?这是一个更复杂的问题,但是从根本上讲,应尽可能少扔掉它-以后在准确选择“最近邻居”时都应该有用))

答案 2 :(得分:1)

另一个很容易实现的选项,尤其是因为您已经完成了一部分工作(我用它来根据管旋转时获得的3张图像来计算圆柱零件的方向) :

  1. 为每个图像设置阈值以隔离表面。
  2. 使用cv2.approxPolyDP()查找四个角,或者使用LineSegmentDetector(可从OpenCV 3获得)找到零件的四个边。
  3. 计算角度α,如下图所示 compute alpha

当零件旋转时,此角度alpha将遵循正弦曲线。也就是说,您将测量alpha(theta)= A sin(theta + B)+C。在给定alpha的情况下,您想知道theta,但首先需要确定A,B和C。

  1. 您已经获得了许多“校准”或参考图像,可以使用所有这些图像来拟合正弦曲线并确定A,B和C。
  2. 完成此操作后,您可以从alpha中确定theta。

请注意,您必须处理sin(a + Pi / 2)= sin(a)。依次获取多个图像不是问题,如果只有一个静态图像,则必须使用额外的机制。

希望我已经很清楚了,考虑到您已经做过的事情,实现确实不是问题。