通用视频模块(GVM)

注册到VIM

GVM通过代理程序发送请求,注册以下VIM参数:

  • name (Id): 如果没有其它模块使用这个名称订阅,就可以把它用作识别符。否则,名称会带有一些附加字符(例如"_bis")。由于这可能是一个编程错误造成的,因此只允许该模块有8个实例。
  • resolution (size) 分辨率(大小):

    - VGA (640 * 480 )

    - QVGA (320 * 240)

    - QQVGA (160 * 120)

  • color space (色彩空间):

    - YUV422(摄像头的原格式)

    - YUV (24位)

    - Y (8位)

    - RGB (24位)

    - BGR (24位)

    - HSY (24位,更多细节请参见本指导结尾部分 的附录)

  • frames per second (帧率,fps): 这一参数不在VIM这一级进行管理,而是在应用程序一级。它会等待两个图像请求之间所需的时间。

在这一阶段,VIM可以查看数据库,了解应该向每个发送请求的GVM提供哪些数据。

下图中,您可以看到3个注册到VIM的GVM(见下图中蓝色的部分)。为了介绍VIM内部如何工作,假设前两个GVM要求的是同一个图像格式,而第三个GVM要求的则与视频源器件的原格式相同。

vision system

vision system

在VIM的线程区域里(绿色部分),您可以看到由VIM创建的ALImage容器,用来管理此后来自GVM的请求。

位于左侧的第一套容器将只会收到一个驱动程序缓冲区的指针访问。它只是图像格式的封装,没有任何内存分配,用来设定只包含原始数据的缓冲区的不同属性(如宽度、高度、分辨率、色彩空间、locker等)。

位于右侧的第二套容器拥有其自身的分配内存,因为它们将收到根据GVM的要求而转换了分辨率和色彩空间的图像。

注释:

右侧一套里所有的缓冲区会分配分辨率和色彩空间组合能允许的最大内存量。因此,改变分辨率或色彩空间无需任何耗时的内存再分配,而只是改变参数。

设定及要求参数

  • setResolution, setColorSpace, setFrameRate:可以随时给每个GVM的分辨率或色彩空间设定新值,这个新值将代替注册时使用的值。然后,VIM会自动检查新设定对视频源来说是否有必要。如果有必要,就应用这些新设定。
  • setParam: 同样,可以要求视频源器件进行新设定,如NAOCam启动/取消自动增益或白平衡等。
  • getGVMResolution, getGVMColorSpace, getGVMFrameRate:向一个GVM返回一个相应参数。
  • getVIMResolution, getVIMColorSpace, getVIMFrameRate:用来了解视频源器件以哪一种模式在运行(它会以最适当的模式运行,以满足每个GVM的需要)。
  • getParam: 返回某个特定视频源参数的值

请求一个图像

一个GVM可以通过两种方式请求图像:标准访问,可以进行图像转换;或直接访问原始数据,以便直接访问驱动程序的图像缓冲区。这两种方式都可以本地或远程使用。

  • 标准访问

    > 推荐模式。使用函数getImageLocal()时,VIM会按照GVM需要的格式提供图像。

    (1) 下图中,一个GVM向VIM以本地模式请求一个图像。

    (2) 假设这是第一次请求,或是近期没有过同样类型的请求。VIM将向驱动程序要求由视频源填入的最新缓冲区。

    (3) 与V4L驱动程序的"read"模式不同,"streaming"模式不会要求从内核空间到用户空间的数据备份,而只是重映射(作用于指针上而不是数据上)。由此,驱动程序在提供对其最新更新原始数据的访问时,会将这些数据从循环缓冲区队列里移出。该缓冲区可通过一个ALImage缓冲区进行访问-见VIM线程左侧。在这个例子中,驱动程序会由此临时有4个而不是开始时的5个缓冲区。

    (4) VIM会把更新的原始图像缓冲区转换为GVM所需的格式。这个图像将存储在相应格式的第一个过时的可用缓冲区里(不会被锁定,可以写入)。见下图中VIM线程的右侧。转换结束后,原始图像缓冲区将会自动重新进入驱动程序的循环缓冲区队列。

    (5) 由于GVM的请求是本地请求,因此,它会通过一个指针来访问这个转换过的ALImage缓冲区。ALImage缓冲区将被锁定,无法写入,直至这个GVM(及其它可能会访问的GVM)释放它为止。

vision system

vision system

> 现在,假设另有一个需要同类图像的GVM向VIM发送了一个请求。

(1) 为了展示远程调用的不同之处,假设这个请求使用getImageRemote(),采用远程模式。本地模式与远程模式大同小异,只是在最后阶段访问缓冲区的方式上有所不同。

(2) VIM同样会询问驱动程序哪一个是最新更新的缓冲区,并将其时间戳与一个较新的、格式符合要求的ALImage时间戳进行比较。请注意,当我们开始采集一个新帧时,缓冲区总是在驱动程序一级被加盖时间戳,因此,他们的精确度高于1毫秒。

(3) 如果没有更新的原始图像缓冲区,VIM就会提供与第一个GVM相同的ALImage缓冲区。这样就可以通过共享进程来避免多余的转换。

(4) 由于请求采用的是远程模式,因此ALImage缓冲区会被转换为ALValue,并通过"soap"发送至远程的GVM。远程GVM通过"soap"接收到图像的一个副本,所以不再需要访问ALImage缓冲区。这样,它就可以释放出这个缓冲区。这一操作在getImageRemote()函数结束时自动完成。而本地GVM则需要显式释放ALImage缓冲区。所以,当本地GVM的任务完成时,每个getImageLocal()调用都应与一个releaseImage()搭配使用,否则,就会阻止GVM再次调用getImage来获得新图像。您可以像从本地GVM那样从远程GVM调用releaseImage(),这一方法不起任何作用。

一旦每个GVM都释放了一个缓冲区,这个缓冲区就可以重新被写入。而且,必要时,仍可读取这个缓冲区。

vision system

vision system

注释:

显而易见,GVM不应修改传入(incoming)图像,以保证让其它GVM也获得正确的数据。因此,如果GVM进程的结果是图像的话,强烈建议使用一个传出(outcoming)图像。

  • 直接原始访问

    > 在这一模式下,用户可以直接访问驱动程序的原始图像缓冲区。这表示GVM进程必须以视频源的原格式运行。在这种情况下,GVM进程不是从未映射的驱动程序缓冲区以正确格式把数据复制到一个ALImage缓冲区(箭头4)、然后提供一个指针(箭头5),而是会通过指针直接访问驱动程序最后更新的缓冲区(箭头4bis),这样做速度较快,而且占用的处理能力也较少。但是,使用这一模式有一定限制。

vision system

vision system

> 在这一模式里,只要有必要,一个GVM就会保留一个未映射的驱动程序原始缓冲区,因而,驱动程序的循环缓冲区会继续运行,但原始缓冲区数量减少。如果与驱动程序原始缓冲区数目一样多的GVM都保留一个原始缓冲区,而且保留的时间超过了摄像头写入一个图像所需的时间,那么在某一点上就没有可用的缓冲区来写入视频流的最后帧。在这种情况下,摄像头就会处于等待状态,直至一个原始缓冲区被释放出来才再次写入图像。

> 这就是为什么我们建议您首先确认原始缓冲区总是多于那些需要保留这一缓冲区超过25ms才会调用releaseDirectRawImage函数的GVM。目前,驱动程序一般会在NAO上设定4个缓冲区,而NAO的摄像头每33ms提供一个新帧。但是,从安全上考虑,您需要留出一些时间用来进行VIM管理及其它线程处理。

> 另外,使用这一模式时,还有一点需要提请您注意。如果驱动程序的任一原始缓冲区还可以被访问时,任何要求修改摄像头运行方式的操作(例如调整分辨率、切换摄像头等)都可能会引发问题。

> 与标准远程访问模式相同,直接原始访问模式在ALValue转换完成后就会自动释放原始缓冲区。

> 您可能已经注意到,标准远程访问模式内部使用的就是直接原始访问。





Copyright © 2010 Aldebaran-Robotics - 版权所有