NXP

Gstreamer + OpenCV - www.deltavision.io

2019-07-12 13:13发布

Gstreamer

首先,要先讨论下为什么需要在OpenCV上用上Gstreamer. 比如直接一个摄像头 v4l2 图像传给 OpenCV 不行吗? Gstreamer是嵌入式平台处理Media的首选组件, 像Nvdia/TI/NXP/Rockchip平台, 都是使用Gstreamer来整合Media应用. 在Rockchip平台上, 已经有为Gstreamer开发了像Decode/Encode/ISP-Camera/2D加速器/DRM-Display-sink这些的Plugin. 所以OpenCV如果链接上Gstreamer, 输入源就不仅仅是摄像头, 还可以是RTSP/本地视频;输出显示的代码可以不用写, 让Gstreamer来显示; 转换格式让Gstreamer来转, 利用硬件加速; 处理的图像送回Gstreamer编码. ARM 在ARM系统上做Media的开发, 有一个原则要很重要, 就是 : 避免拷贝.
如果你手边正好有一块ARM板子和Linux PC, 可以尝试在上面跑一些memcpy的Test. 一般来说, 测试的性能会相差5,6倍. 即时是DDR同频的两个系统, 性能也会差到3-4倍(不过也可能是DDR其他参数有影响?). 内存操作速度的劣势是RISC天生的, ARM也不列外. (虽然也没有研究过对应微处理器结构,道听途说 :-P) 还有一个更影响速度的就是, 这些Buffer一般都是uncached的DMA Buffer, 为了保证cpu和其他ip的内存一致性, 所以CPU读写速度就更慢了.. 在开发OpenCV + Gstreamer的过程中, 一定要尽量避免拷贝的发生, 如果一定要有, 也不能是由CPU来做. (替代可以是2D加速器, GPU) (当然这里用2D加速拷出来后buffer,默认还是uncached的,还是不适合CPU直接在上面处理,就算改成cache的,cache刷新的时间也要10ms+。。不过如果你的算法需要CPU去实时处理每帧的话,一般的ARM CPU都做不到吧)

OpenCV

之前只在X86上使用过OpenCV, 其实不太了解OpenCV在ARM Device需要怎么开发. (怀疑其他ARM平台上到底能不能用OpenCV, 因为像TI/NXP这种, CPU/GPU太弱, 估计只能内部的DSP跑算法; 像全志, 基本没有Linux平台的组件支持; 唯一能搞的估计也就是Nvdia的terga了, cuda还是厉害. ;) ) 根据上面ARM的原则, 开发的时候要避免调用到OpenCv的cvtcolor和clone这些函数, 因为每次拷贝都会消耗大量的CPU资源. OpenCV也支持OpenCL加速, 当然..其实没什么卵用, 尤其你是在处理实时的图像的时候, 因为GPU处理数据的时候, 需要加载Texture到GPU内存上, 放OpenCL上, 就是你要处理的帧, 全部要拷一份到新的内存地址上….虽然在嵌入式设备上, GPU并没有和CPU使用分离的内存, 完全没必要这么做; 在图形应用的框架上, GPU处理dmabuf都是zero-copy的, 也就是要处理的帧, 只要让GPU MMAP一下就可以了, 而OpenCV, OpenCL, 暂时没找到方法…(所以GPU通用计算还是要靠Vulkan了..)
当然在算法的处理耗时有好几秒的时候, 加载纹理消耗10毫秒也是可以忽视的 : 这种场合才建议使用OpenCL. 才发现这个好像是ARM上特有的问题, opencv已经是用了CL_MEM_USE_HOST_PTR, 理论上不应该有拷贝. 但是ARM上这个flag却会导致拷贝, ARM上需要使用特殊的api来做zero-copy.
嗯…这样你得去修改OpenCV才能用起来…
这几天尝试添加了一下异步处理, 这样来看拷贝的耗时反而不重要了, 比如一秒里可能就处理了2,3张图片, 拷贝这一帧的30ms,opencl减少耗时500ms。而且拷贝后的buffer是cached的normal内存, cpu处理起来速度会更快. 所以拷贝是不是个问题, 得看相应的应用场景和算法需求.