TL;DR
- opencv-mobile highgui 模块在运行时动态加载 cvi 库,JPG 硬件解码
- 无需修改代码,
cv::imread()
与cv::imdecode()
自动支持 - 支持EXIF自动旋转,支持直接解码为grayscale
- 因为只测试验证了 milkv-duo/milkv-duo-256m,白名单暂时只有 milkv-duo/milkv-duo-256m
- 加速了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
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对齐的坑
- 读jpg文件到内存中
- 解析jpg头部,获得 w h 通道数 采样方法 EXIF 等信息
- cvi-mmf 准备3个 vbuffer,用于解码后的vb,旋转后的vb,转BGR后的vb
- vdec 解码到 yuv444/yuv422/yuv420/y
- vpss 做旋转并 yuv 转换到 nv12
- 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 解码提升巨大