关于作者
Ricardo Antunes 是里斯本高等技术学院计算机科学与工程专业的四年级本科生。虽然他还是一名本科生,但他从 9 岁起就将编程作为爱好。他仍在努力寻找自己的主要研究兴趣。
最近,我通过 **GSoC** 项目为 **highgui** 模块做出了贡献,增加了 **viz3d 命名空间**。那么,新功能是什么,如何使用它们呢?
介绍
3D 视觉一直是计算机视觉学科中非常重要的组成部分。如今,随着机器人技术、自动驾驶汽车、虚拟与增强现实等领域的快速发展,它比以往任何时候都更加重要。因此,能够方便地使用 3D 算法并快速构建原型解决方案是一个非常重要且理想的功能,而 OpenCV 作为一种便捷的原型解决方案,应该提供必要的工具来实现这一点。
3D 可视化模块(称为 viz)已经成为 OpenCV 的一部分已有数年之久,但不幸的是,它依赖于相当大的第三方 VTK 库,这在某些平台上可能难以获取/构建。因此,决定创建一个轻量级的替代解决方案,该方案仅使用 OpenGL 以及本地 GUI 工具包(例如 Windows 上的 Win UI 或 Linux 上的 GTK+)来显示一些常见的 3D 对象,例如点云、网格、规范形状、相机轨迹等。这是本项目的目标。已经实现的功能包括渲染简单的基本图形,如立方体和球体,显示三角形网格、点云和 RGB-D 图像。
如何构建它
与之前位于 opencv_contrib 中的专用“viz”模块中的 3D 可视化实现相反,这个新的轻量级 API 是现有模块“highgui”的一部分。它已在 Windows 上进行了测试,也应该在大多数 Linux 发行版上运行,只要您安装了 GTK+2 和 GTKGLExt 即可。在 Ubuntu 上,使用新的 Viz3D 功能构建 OpenCV 需要以下软件包
- libgtkglext1-dev
- libgtk2.0-dev
OpenCV 应使用以下 CMake 选项进行配置
- WITH_GTK_2_X=ON(仅在 Linux 上)
- WITH_OPENGL=ON
您可以在“example_cpp_viz3d”示例中看到这些功能的实际应用。要构建它,您应该使用 BUILD_EXAMPLES=ON 配置 CMake。
功能
所有新功能都在 cv::viz3d 命名空间中实现。每个函数都将窗口名称作为第一个参数,该窗口将显示操作结果。作用于对象的函数始终将对象名称作为第二个参数。例如,如果我们想在坐标 (5, 5, 5) 处显示一个红色立方体,我们可以编写
cv::Vec3f red = { 1.0f, 0.0f, 0.0 }; cv::Vec3f green = { 0.0f, 1.0f, 0.0 }; cv::Vec3f blue = { 0.0f, 0.0f, 1.0 }; /* window object box size box color */ cv::viz3d::showBox("my window", "cube 1”, { 1.0f, 1.0f, 1.0f }, red); /* window object new position */ cv::viz3d::setObjectPosition("my window", "cube 1", { 5.0f, 0.0f, 5.0f }); /* There's also a setObjectRotation */
如果要显示阴影或线框立方体,可以将渲染模式设置为 RENDER_SHADING 或 RENDER_WIREFRAME(默认值为 RIf you want to show a shaded or wireframe cube, you can set the render mode to RENDER_SHADING or RENDER_WIREFRAME (the default is RENDER_SIMPLE),
cv::viz3d::showBox("my window", "cube 2", { 1.0f, 1.0f, 1.0f }, red, cv::viz3d::RENDER_SHADING); cv::viz3d::showBox("my window", "cube 3", { 1.0f, 1.0f, 1.0f }, red, cv::viz3d::RENDER_WIREFRAME); cv::viz3d::setObjectPosition("my window", "cube 2", { 0.0f, 0.0f, 5.0f }); cv::viz3d::setObjectPosition("my window", "cube 3", { -5.0f, 0.0f, 5.0f });
当然,我们不仅限于显示立方体,还可以显示球体
... cv::viz3d::showSphere("my window", "sphere 1", 1.0f, green); cv::viz3d::showSphere("my window", "sphere 2", 1.0f, green, cv::viz3d::RENDER_SHADING); cv::viz3d::showSphere("my window", "sphere 3", 1.0f, green, cv::viz3d::RENDER_WIREFRAME); cv::viz3d::setObjectPosition("my window", "sphere 1", { 5.0f, 0.0f, -5.0f }); cv::viz3d::setObjectPosition("my window", "sphere 2", { 0.0f, 0.0f, -5.0f }); cv::viz3d::setObjectPosition("my window", "sphere 3", { -5.0f, 0.0f, -5.0f });
以及平面
... cv::viz3d::showPlane("my window", "plane 1", { 1.0f, 1.0f }, blue); cv::viz3d::showPlane("my window", "plane 2", { 1.0f, 1.0f }, blue, cv::viz3d::RENDER_SHADING); cv::viz3d::showPlane("my window", "plane 3", { 1.0f, 1.0f }, blue, cv::viz3d::RENDER_WIREFRAME); cv::viz3d::setObjectPosition("my window", "plane 1", { 5.0f, 0.0f, 0.0f }); cv::viz3d::setObjectPosition("my window", "plane 2", { 0.0f, 0.0f, 0.0f }); cv::viz3d::setObjectPosition("my window", "plane 3", { -5.0f, 0.0f, 0.0f });
可以使用 showPoints 或 showRGBD 显示点云。第一个函数将 cv::Mat 作为参数,该参数包含点云。它必须是二维的,并且有 6 列,其中每一行代表一个点。前 3 行包含点的坐标,后 3 行包含点的颜色。以下是代码和使用 showPoints 显示的蜜蜂点云
cv::viz3d::showPoints(“my window”, “bee”, bee_mat);
第二个函数 showRGBD 将包含 RGB-D 图像(4 个通道)的 cv::Mat 和相机的内参矩阵作为参数,并将图像显示为点云。在本例中,我使用了 setGridVisible 来显示带有坐标系的网格,而不是十字准星。我还没有实现标签功能,但我正在努力。
cv::Matx33f intrinsic = { 529.5f, 0.0f, 365.0f, 0.0f, 529.5f, 265.0f, 0.0f, 0.0f, 1.0f, }; cv::viz3d::showRGBD(“rgbd”, “points”, rgbd_mat, intrinsic, 0.1f); cv::viz3d::setGridVisible(“rgbd”, true);
还有 showLines,它的作用与 showPoints 相同,但它将每对连续点都绘制为一条线。showMesh 遵循相同的逻辑,但使用三角形而不是点。在 showMesh 中,您可以选择使用索引来定义三角形或将顶点 3 个一组。您还可以选择向输入 cv::Mat 添加法线和颜色,以便显示的网格具有阴影。
最后,可以使用 setPerspective、setSun 和 setSky 配置相机、灯光和环境,并可以使用 destroyObject 销毁对象。
障碍
我遇到的主要问题之一是,尽管窗口系统已经支持 OpenGL 渲染,但它非常基础,并且使用旧版本的 OpenGL 设计。例如,虽然系统公开了 setOpenGlDrawCallback 函数,但没有 setOpenGlFreeCallback 函数来释放我需要为渲染分配的对象。我最终使用新的函数(如 setOpenGlFreeCallback、getOpenGlUserData)扩展了窗口系统。
这些新功能使我能够在现有系统之上构建 viz3d 功能。当第一次在窗口上调用 viz3d 函数时,会分配一个处理 3D 视图和窗口上所有对象的内部对象,并使用 setOpenGlDrawCallback 设置,稍后由新的 OpenGL 释放回调释放。
现在我面临着另一个问题:OpenCV OpenGL 包装器没有实现现代功能(例如,没有顶点数组和着色器)。因此,我还需要扩展 OpenCV 核心模块上的 OpenGL 包装器。我添加了 Attribute、VertexArray、Shader 和 Program 对象,并为一些未公开的功能添加了新函数。
结论
本项目的所有主要计划功能都已实现,目前唯一缺少的功能是在网格轴上显示坐标标签。这些功能使在 OpenCV 上可视化 3D 数据比以往任何时候都更容易。Google Summer of Code 是我接触开源开发的入门,我非常享受它。这是我第一次为像 OpenCV 这样庞大的代码库做出贡献,并且与来自世界各地的人们合作是一次很棒的体验。