视频流的获取和处理可能在计算上非常昂贵。典型的图像处理应用程序将工作分成多个线程,一个获取图像,另一个运行实际算法。在MATLAB中,我们可以通过与其他语言交互来获得多线程,但是在结果语言障碍中交换数据会产生相当大的成本。在这篇博文中,我们比较了通过MATLAB Java接口获取数据的不同方法,并展示了如何以低开销实时获取高分辨率视频流。
动机
对于我们在ICRA 2014的展台,我们在MATLAB中组装了一个演示系统,该系统使用立体视觉跟踪彩色豆袋,并使用机器人手臂拾取它们。我们使用了两台通过RTSP流式传输H.264视频的IP摄像机。虽然开发图像处理和机器人控制部件按预期工作,但事实证明,从两个视频流中获取图像的速度足够快,这是一项挑战。
IP摄像机支持仅支持MJPEG了HTTP和当时根本不存在
USB网络摄像头支持仅支持USB摄像头
imread和webread仅限于HTTP,实时性太慢
由于我们不想切换到另一种语言,我们决定开发一个用于获取视频流的小型库。该项目后来作为HebiCam开源。
技术背景
为了节省带宽,大多数IP摄像机在通过网络发送视频之前压缩视频。由于所得到的解码步骤在计算上可能是昂贵的,因此通常的做法是将获取移动到单独的线程以减少主处理线程上的负载。
不幸的是,在MATLAB中执行此操作需要一些解决方法,因为语言具有单线程特性,即后台线程需要以另一种语言运行。开箱即用,有两个支持的接口:用于调用C / C ++代码的MEX和用于调用Java代码的Java接口。
虽然两个接口都有优点和缺点,但实际上所有用例都可以使用其中任何一个来解决。对于这个项目,我们选择了Java接口,以简化跨平台开发和二进制文件的部署。
启动后台线程并将视频流转换为Java相对简单。我们使用了JavaCV库,它是围绕OpenCV和FFMpeg的Java包装器,包括所有主要平台的预编译本机二进制文件。然而,将获得的图像数据从Java传递到MATLAB变得更具挑战性。
Java接口通过遵循一组规则自动在Java和MATLAB类型之间进行转换。这使得开发比MEX接口简单得多,但在调用Java函数时确实会产生额外的开销。大多数情况下,这种开销可以忽略不计。然而,对于某些类型的数据,例如大型和多维矩阵,默认规则效率非常低并且可能变得非常昂贵。例如,1080x1920x3MATLAB图像矩阵被转换为byte[1080][1920][3]Java,这意味着图像中的每个像素都有一个单独的数组对象。
作为一个额外的复杂功能,MATLAB将图像数据存储在与大多数其他库(例如OpenCV Mat或Java BufferedImage)不同的存储器布局中。虽然像素通常存储在行主要顺序([width][height][channels])中,但MATLAB存储转置的图像和按列主要顺序([channels][width][height])。例如,如果将a的红绿蓝像素BufferedImage布局为[RGB][RGB][RGB]…,则将[RRR…][GGG…][BBB…]在MATLAB中布置相同的图像。根据分辨率,此转换可能会变得相当昂贵。
为了以30 fps的帧速率实时处理图像,主MATLAB线程的总时间预算为每周期33ms。因此,施加在主线程上的获取开销需要足够低,即,毫秒数,以留出足够的时间用于实际处理。
数据翻译
我们基于五种不同的方法对从Java中获取图像数据到MATLAB进行了基准测试,并比较了它们在主MATLAB线程上的相应开销。我们省略了后台线程产生的开销,因为它对可用于图像处理的时间预算没有影响。