opencv-mobile 现已支持 milkv-duo cvi-mmf 硬件加速 JPG 解码

TL;DR

  1. opencv-mobile highgui 模块在运行时动态加载 cvi 库,JPG 硬件解码
  2. 无需修改代码,cv::imread()cv::imdecode() 自动支持
  3. 支持EXIF自动旋转,支持直接解码为grayscale
  4. 因为只测试验证了 milkv-duo/milkv-duo-256m,白名单暂时只有 milkv-duo/milkv-duo-256m
  5. 加速了5~11倍!

下载新版本 opencv-mobile 预编译包

解压到项目目录中,cmake 中设置 OpenCV_DIR 路径,find_package 找到

project(opencv-mobile-test)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_STANDARD 11)

set(OpenCV_DIR "${CMAKE_CURRENT_SOURCE_DIR}/opencv-mobile-4.8.1-milkv-duo/lib/cmake/opencv4")
find_package(OpenCV REQUIRED)

add_executable(opencv-mobile-test main.cpp)

target_link_libraries(opencv-mobile-test ${OpenCV_LIBS})

opencv-mobile

opencv-mobile 通过调整编译参数,删减部分opencv源码,来最小化编译的 opencv 库

提供了 opencv 常用的功能,如读写图片,处理,矩阵操作等等 版本与上游同步,无第三方依赖

在绝大多数情况下,以 1/10 的体积无痛替换官方 opencv,尤其适合对体积有特殊要求的移动端和嵌入式环境

milkv-duo / milkv-duo 256m

https://milkv.io/duo​

Milk-V Duo 是基于 CV1800B 芯片的超紧凑型嵌入式开发平台。Duo 256M 是以 SG2002 为主控制器设计的 Duo 的升级版,内存升级到 256M,支持标准的 Linux 系统和应用,可以满足大内存、大存储量的应用需求。Duo 256M 是以 SG2002 为主控制器设计的 Duo 的升级版,支持标准 Linux 系统和应用程序。

cvi-mmf

CVITEK所提供的多媒体软件架构(Multimedia Framework,简称MMF),用以缩短应用程序开发所需的时间。

此架构屏蔽了处理器端的复杂底层设计和差异,对应用程序提供统一且便捷的MMF Programming Interface编程接口。

一些实现细节和限制

运行时加载 cvi-mmf 动态库

为了减少编译耦合,opencv-mobile中采用运行时 dlopen/dlsym 方式加载 libsys libvdec libvpu,即便编译时候缺库依然兼容可用

这种方式也能自动适配后期系统库升级

吐嘈一下:cvi-mmf 的 so 库之间有相互依赖,还有 unresolved symbol,dlopen相当费劲(x

白名单

优化代码在 milkv-duo / milkv-duo 256m 上做了验证测试

加载cvi-mmf库时,额外判断 /proc/device-tree/model 是否为 milkv-duo 设备,在其他设备上能自动退回到无优化的版本

避免特殊分辨率

测试中发现对于超小(2x2)和超大(4096x4096)分辨率,经常发生图片损坏或内容错乱,编码错误,甚至内存不足被kill

因此针对以下特殊情况,会自动回退到无优化的版本

  • w 或 h 不是 2 倍数
  • w 或 h 小于 8

解码过程和vpss对齐的坑

  1. 读jpg文件到内存中
  2. 解析jpg头部,获得 w h 通道数 采样方法 EXIF 等信息
  3. cvi-mmf 准备3个 vbuffer,用于解码后的vb,旋转后的vb,转BGR后的vb
  4. vdec 解码到 yuv444/yuv422/yuv420/y
  5. vpss 做旋转并 yuv 转换到 nv12
  6. vpss 做 nv12 转换到 bgr

其中,测试发现 vpss 对数据对齐要求较高,会发生 vdec 解码的数据是 64bytes 对齐,而 vpss 需要数据是 128bytes 对齐

在一些非128倍数的尺寸下会发生解码失败或解码后图片数据错误的问题

于是在 vdec->vpss 中间做了 hack,在vdec解码后vpss处理前重新设置 phyaddr 值和重新 memmove UV通道数据,以便满足 vpss 的对齐需求

如果是解码到 grayscale,则vpss直接将yuv视作y处理,能加速旋转

总体看来,jpg解码过程比编码复杂很多,要考虑的情况也更多

8种旋转方向

vdec 只能配置输出 flip/mirror,搭配 vpss 只能做 90/180/270 的旋转,可以复合出8种旋转方向

由于 vpss 只能对 nv12 的数据旋转,yuv444 解码后的uv通道会无法避免的下采样,这对图片质量是有损的

不支持yuv422垂直和progressive

测试中发现 yuv422水平的jpg可以正常解码,而 yuv422 垂直的jpg,vdec 解码出的是错误的,这类jpg会自动退回到软件解码

此外,也不支持 progressive jpg

性能测试

测试预先读取图片,反复调用cv::imdecode()进行JPG解码,排除文件读写的干扰,统计最快耗时

测试分辨率为 720p 的 YUV444 YUV422 YUV420 GRAY 四种颜色空间的jpg文件,并联合测试依据EXIF旋转90度的解码过程

测试分别解码为 BGR 和 grayscale 的 cv::Mat

分别在 milkv-duo 和 milkv-duo 256m 上测试

测试结果表明 cvi-mmf 硬件加速 JPG 解码提升巨大

快去star下嘛…

https://github.com/nihui/opencv-mobile​

2 Likes

it’possible to save frames from camera with OpenCV? any example? thanks Luca