Pollen-Vision:机器人零样本视觉模型的统一接口
这是 Pollen Robotics 团队的客座博客文章。我们是 Reachy 的创建者,Reachy 是一款开源人形机器人,专为真实世界的操作而设计。
在自主行为的背景下,机器人可用性的本质在于其理解和与环境交互的能力。这种理解主要来自于视觉感知,它使机器人能够识别物体、识别人、导航空间等等。
我们很高兴地宣布我们的开源 pollen-vision
库的首次发布,这是赋予我们的机器人抓取未知物体自主能力的第一步。该库是精挑细选的视觉模型集合,因其在机器人领域的直接适用性而被选中。 Pollen-vision
的设计易于安装和使用,由独立模块组成,可以组合起来创建 3D 对象检测管道,获取物体在 3D 空间中的位置(x、y、z)。
我们专注于选择零样本模型,消除了任何训练的需要,使这些工具开箱即用。
我们的初始版本专注于 3D 对象检测——通过提供可靠的物体空间坐标估计,为机器人抓取等任务奠定基础。目前仅限于 3D 空间内的定位(不扩展到完整的 6D 姿态估计),此功能为基本的机器人操作任务奠定了坚实的基础。
Pollen-Vision 的核心模型
该库包含几个关键模型。我们希望我们使用的模型是零样本且多功能的,允许检测各种物体而无需重新训练。这些模型还必须具有“实时能力”,这意味着它们应该在消费级 GPU 上至少以每秒几帧的速度运行。我们选择的第一个模型是
- OWL-VIT (Open World Localization - Vision Transformer,由 Google Research 开发):此模型在 RGB 图像中执行文本条件零样本 2D 对象定位。它输出边界框(如 YOLO)
- Mobile Sam:Meta AI 的 Segment Anything Model (SAM) 的轻量级版本。SAM 是一种零样本图像分割模型。它可以通过边界框或点进行提示。
- RAM (Recognize Anything Model,由 OPPO 研究院开发):RAM 专为零样本图像标注而设计,可以根据文本描述确定图像中是否存在物体,为进一步分析奠定基础。
只需几行代码即可开始!
下面是使用 pollen-vision 构建一个简单的对象检测和分割管道的示例,该管道仅将图像和文本作为输入。
from pollen_vision.vision_models.object_detection import OwlVitWrapper
from pollen_vision.vision_models.object_segmentation import MobileSamWrapper
from pollen_vision.vision_models.utils import Annotator, get_bboxes
owl = OwlVitWrapper()
sam = MobileSamWrapper()
annotator = Annotator()
im = ...
predictions = owl.infer(im, ["paper cups"]) # zero-shot object detection
bboxes = get_bboxes(predictions)
masks = sam.infer(im, bboxes=bboxes) # zero-shot object segmentation
annotated_im = annotator.annotate(im, predictions, masks=masks)
OWL-VIT 的推理时间取决于提供的提示数量(即要检测的对象数量)。在配备 RTX 3070 GPU 的笔记本电脑上
1 prompt : ~75ms per frame
2 prompts : ~130ms per frame
3 prompts : ~180ms per frame
4 prompts : ~240ms per frame
5 prompts : ~330ms per frame
10 prompts : ~650ms per frame
因此,从性能角度来看,仅使用图像中已知的对象来提示 OWL-VIT 很有趣。这就是 RAM 的用武之地,因为它速度快,并且能提供准确的信息。
一个机器人应用案例:在无约束环境中抓取未知物体
有了对象的分割掩码,我们可以通过计算二值掩码的质心来估计其在像素空间中的 (u, v) 位置。在这里,拥有分割掩码非常有用,因为它允许我们平均掩码内的深度值,而不是整个边界框内的深度值,因为边界框也包含会使平均值倾斜的背景。
一种方法是平均掩码中非零像素的 u 和 v 坐标
def get_centroid(mask):
x_center, y_center = np.argwhere(mask == 1).sum(0) / np.count_nonzero(mask)
return int(y_center), int(x_center)
我们现在可以引入深度信息,以估计对象的 z 坐标。深度值已经以米为单位,但 (u, v) 坐标以像素表示。我们可以使用相机的内参矩阵 (K) 获取对象质心的 (x, y, z) 位置(以米为单位)
def uv_to_xyz(z, u, v, K):
cx = K[0, 2]
cy = K[1, 2]
fx = K[0, 0]
fy = K[1, 1]
x = (u - cx) * z / fx
y = (v - cy) * z / fy
return np.array([x, y, z])
我们现在已经估算出了物体在相机参考系中的 3D 位置。
如果我们知道相机相对于机器人原点框架的位置,我们可以执行一个简单的变换来获取物体在机器人框架中的 3D 位置。这意味着我们可以将机器人的末端执行器移动到物体所在的位置,然后抓取它!🥳
接下来是什么?
我们在本文中介绍的是实现我们的目标的第一步,即在野外自主抓取未知物体。还有一些问题需要解决
- OWL-Vit 并非每次都能检测到所有物体,并且可能存在不一致性。我们正在寻找更好的替代方案。
- 目前没有时间或空间一致性。所有内容都是每帧重新计算的
- 我们目前正在努力整合点跟踪解决方案,以增强检测的一致性
- 抓取技术(目前仅限正面抓取)不是这项工作的重点。我们将研究不同的方法,以提高抓取能力,包括感知(6D 检测)和抓取姿态生成。
- 整体速度有待提高
尝试 pollen-vision
想尝试 pollen-vision 吗?请查看我们的 Github 仓库!