附加理论
视觉目标
FRC 比赛设计师经常在场地的战略位置放置反光的"视觉目标"。这些视觉目标通常由反光带制成。主要的得分元素通常都有可用于自动瞄准的视觉目标。下面你可以看到 2016 年和 2017 年 FRC 比赛中视觉目标的两个例子。
这些反光视觉目标具有一个非常有用的特性:当光线照射到它们时,光线会直接反射回光源。这就是为什么 Limelight 在其摄像头镜头周围有明亮的绿色 LED。通过在发射明亮的绿光toward目标的同时将摄像头曝光设置得很低,我们可以获得一个大部分为黑色且视觉目标呈明亮绿色的图像。这使得获取目标变得相对容易。
这里你可以看到理想图像的示例。注意由于低曝光设置,图像中几乎所有的细节都消失了,但反光带却非常突出。
阈值处理
阈值处理是大多数 FRC 视觉跟踪算法中的下一个关键组件。它是指获取图像,并丢弃不在特定颜色范围内的任何像素。阈值处理的结果通常是一个一维图像,其中像素要么"开"要么"关"。阈值处理在使用上述策略(低曝光,非常暗的图像与明亮照明的视觉目标)捕获的图像上效果很好。
Limelight 在 HSV(色相-饱和度-明度)颜色空间中进行阈值处理。你可能习惯于在 RGB(红-绿-蓝)颜色空间中思考颜色。HSV 只是另一种表示颜色的方式,类似于笛卡尔坐标或极坐标可以用来描述位置。我们使用 HSV 颜色空间的原因是色相可以用来非常精确地选择 Limelight LED 输出的绿色。
调整阈值设置以尽可能多地从图像中消除内容是至关重要的。如果在移动到下一阶段之前优化视觉管道的每个阶段,你将获得最佳结果。下图显示了不当和适当阈值处理之间的区别:
有时竞技场中的天花板灯或窗户等物体可能难以通过阈值处理从图像中移除,这就引出了下一个阶段。
轮廓过滤
阈值处理后,Limelight 的视觉管道会为图像生成一组轮廓。轮廓是围绕连续像素集的曲线。有时天花板灯、竞技场记分牌、窗户和其他物体可能通 过阈值处理步骤。这就是轮廓过滤变得有用的地方。目标是消除任何我们知道不是我们感兴趣的目标的轮廓。
第一个也是最简单的轮廓过滤是忽略任何小于我们从得分距离看到的视觉目标的轮廓。任何小于该尺寸的物体显然是更远的物体,应该被忽略。这称为面积过滤。
FRC 视觉目标通常具有一些可以用来帮助我们过滤轮廓的几何特性。例如,如果视觉目标具有宽的纵横比,我们可以过滤掉任何不宽的轮廓:
但是,请记住你的摄像头可能从一个奇怪的角度看目标。这可能会大大影响其轮廓的纵横比。请务必从各种角度测试你的设置,以确保你不会过度过滤并最终忽略视觉目标!
这个下一个图像目标非常有趣。它是 FRC 中设计最好的视觉目标之一(在我们看来)。Limelight 自动计算轮廓的充实度值。充实度是轮廓的像素面积与其凸面积之比。这种特殊形状的充实度非常低,你几乎从不会看到任何天花板灯、窗户等具有如此低的充实度。因此,如果你的视觉目标看起来像这个,你可以非常有效地过滤掉不需要的轮廓。
Limelight 有许多用于过滤轮廓的选项。你可以将这些选项与你所知道的特定视觉目标的几何特性结合使用。
目前,如果多个轮廓通过你的过滤选项,会选择最大的轮廓。此外,管道 倾向于使用滞后来"锁定"轮廓。这是一个有助于防止在相似目标之间闪烁的功能。
从像素到角度
视觉管道的最终结果是图像中最佳轮廓的像素位置。对于大多数比赛,我们可以只瞄准轮廓的中心。有时瞄准顶部中心或其他点也很有用,但本质上我们有一个我们想要瞄准的像素坐标。为了计算到这个目标的角度,我们需要使用一点三角学。
首先我们假设我们有一个完美的"针孔"相机。在实践中,这可能远非事实,但 limelight 的相机非常接近。(鱼眼镜头作为反例就远离这个理想。)
limelight 相机的水平视场为 54 度,垂直视场为 41 度。它以 320x240 分辨率捕获图像。我们假设图像的中心是相机的光轴(因此该位置的 x 和 y 角度为 0,0)。给定这些已知值,我们可以使用一点三角学来计算图像中任何像素的角度。
下图显示了一个我们想要计算角度的示例目标点。像素坐标从图像的左上角开始,向右和向下为正。
我们的第一步是将像素坐标转换为归一化的 2D 坐标,其中 0,0 是图像的中心和 1.0:
(px, py) = 像素坐标,0,0 在左上角,向下和向右为正
(nx, ny) = 归一化像素坐标,0,0 在中心,向右和向上为正
nx = (1/160) * (px - 159.5)
ny = (1/120) * (119.5 - py)
接下来我们定义一个虚拟视平面并计算其大小。为简单起见,我们可以选择将此平面放置在相机位置前 1.0 单 位处。这是俯视相机的视图。我们的目标是计算视平面宽度和高度,因为这些值将用于稍后计算角度:
给定 1.0 单位的距离和已知的水平和垂直视场,我们可以使用以下公式计算视平面矩形的大小:
vpw = 2.0*tan(horizontal_fov/2)
vph = 2.0*tan(vertical_fov/2)
使用这两个值,我们现在可以通过简单的乘法在归一化像素坐标和视平面坐标之间转换。
x = vpw/2 * nx;
y = vph/2 * ny;
记住我们选择将视平面放置在距离 1.0 的位置。现在我们有了计算目标点角度所需的一切。
tan(ax) = x / 1
tan(ay) = y / 1
ax = atan2(x, 1)
ay = atan2(y, 1)