
做了几年嵌入式视觉说实话以前在ARM板子上做图像缩放我基本就是cv::resize一把梭从不关心什么GPU加速。直到有次在RK3588上跑视频拼接1080P缩到720PCPU占用直接飙到快满CPU吃紧连带后面AI推理的帧率也掉了才意识到缩放这种基础操作也能成为瓶颈。后来陆陆续续把OpenCV的几种缩放算法在RK3588上测了个底朝天又把OpenCL、RGA硬件加速的路子都试了一遍。这篇文章就把我实测的数据、选型思路和踩过的坑一次性整理出来给做RK3588视觉项目的朋友一个参考。1. 为什么在RK3588上做图像缩放还要专门谈GPU加速1.1 从一次视频拼接线上问题说起当时项目背景是4路摄像头画面在RK3588上做拼接预览每路都是1920x1080的帧需要先把画面缩到960x540再拼成一个大画面。照理说cv::resize是个再简单不过的API但问题恰恰出在这里四路并发每帧要缩四次主频再高也扛不住。我测了一下单路1080P缩到960x540INTER_LINEAR大概要2.8~3.5ms四路就是12ms左右。看起来还好但如果再加上色彩空间转换、画框、编码、AI推理整个pipeline全挤在CPU上帧率就是上不去。这里的关键在于缩放本身不贵但它占住的CPU时间片会挤压其他更需要CPU算力的任务。如果能把缩放挪到GPU或专用2D硬件上CPU就被释放出来了。RK3588这颗芯片CPU是四核Cortex-A76加四核A55GPU是Mali-G610 MP4NPU算力6 TOPS还内置了RGA3硬件缩放模块。这么多计算部件如果你只用CPU跑OpenCV等于买了个多功能工具箱只用里面的螺丝刀。1.2 RK3588的算力底牌Mali-G610与RGA3先说GPUMali-G610 MP4支持OpenCL 1.2和2.0完整规格这意味着OpenCV的OpenCL后端UMat路线可以在上面跑。理论浮点性能大概在1TFLOPS上下虽然比不上独显但做图像缩放、滤波这类并行度极高的2D操作效率还是很可观的。再说RGA3这是Rockchip特有的2D图形加速硬件支持缩放、旋转、格式转换、裁剪等操作。RGA的好处是它不走GPU的OpenCL驱动栈而是直接由内核驱动提交任务给硬件延迟更低稳定性更好。在RK3588上RGA支持的输入输出格式覆盖RGB888、NV12、NV16等常用格式缩放能力在视频领域用得非常多。所以你在RK3588上谈“GPU加速图像缩放”实际有三条路OpenCV OpenCLUMat改动最小代码友好OpenCV RGA需要封装性能上限高NEON手写优化这个是最后的兜底方案一般用不到。这篇文章主要聚焦前两条路因为它们在工程上最实用。至于NEON优化后面我会提一嘴原理但它不适合作为通用方案推荐。2. 环境准备OpenCV的GPU能力编译与验证2.1 OpenCV编译时哪些开关必须打开很多人在RK3588上用的OpenCV是apt直接装的libopencv-dev这个版本最大的问题是没有启用OpenCL后端或者启用了但缺少Mali的ICDInstallable Client Driver支持。你费半天劲写完UMat代码一跑发现全在CPU上兜底性能毫无变化就是这里埋的坑。我的编译建议是自己从源码编一遍OpenCV版本选4.8.0或4.9.04.5以下的版本对Mali-G610的支持不太行。CMake关键选项如下cmake -DCMAKE_BUILD_TYPERelease \ -DCMAKE_TOOLCHAIN_FILE../toolchain.cmake \ -DWITH_OPENCLON \ -DWITH_OPENCL_SVMON \ -DWITH_OPENCLAMDFFTOFF \ -DWITH_OPENCLAMDBLASOFF \ -DWITH_GTKOFF \ -DWITH_FFMPEGON \ -DWITH_JPEGON \ -DWITH_PNGON \ -DBUILD_opencv_python3OFF \ -DBUILD_TESTSOFF \ -DBUILD_PERF_TESTSOFF ..重点解释两个WITH_OPENCLON这是OpenCV使用OpenCL后端的总开关必须开。WITH_GTKOFF板端的GUI窗口用不到avoid在交叉编译时引入一堆X11依赖。编译完成后建议写个小程序验证OpenCL设备能否正常初始化。我习惯用cv::ocl::haveOpenCL()和cv::ocl::Device::getDefault()来看#include opencv2/core/ocl.hpp #include iostream int main() { if (!cv::ocl::haveOpenCL()) { std::cout OpenCL is not available std::endl; return -1; } cv::ocl::Device dev cv::ocl::Device::getDefault(); std::cout OpenCL Device: dev.name() std::endl; std::cout OpenCL Vendor: dev.vendorName() std::endl; std::cout OpenCL Version: dev.OpenCLVersion() std::endl; return 0; }正常输出应该类似OpenCL Device: Mali-G610 OpenCL Vendor: ARM OpenCL Version: OpenCL 2.0如果输出的是pthread或者类似名字说明OpenCL初始化失败OpenCV在fallback到CPU那就得回头查Mali驱动和ICD了。2.2 RGA硬件加速的调用方式RGA不是OpenCV自带的需要单独装librga库。Rockchip官方有对应的源码和头文件一般系统镜像里会预装librga.so如果没有就手动编译一份。RGA的调用方式分两步先配置rga_info_t结构体再调用c_RkRgaBlit提交任务。下面是个NV12格式缩放的示例骨架#include im2d.h #include rga.h void rga_resize_nv12(int src_fd, int src_w, int src_h, int dst_fd, int dst_w, int dst_h) { rga_info_t src {}; rga_info_t dst {}; src.fd src_fd; src.mmuFlag 1; dst.fd dst_fd; dst.mmuFlag 1; IM::Rect src_rect(0, 0, src_w, src_h); IM::Rect dst_rect(0, 0, dst_w, dst_h); IM::PixelFormat fmt IM::NV12; bool ret IM::Im2d::Resize(src, dst, dst_rect, src_rect, fmt, 0); if (ret ! IM::IM_STATUS_SUCCESS) { printf(RGA resize failed\n); } }如果你用DMA-BUF方式导入bufferRGA可以实现零拷贝操作直接从摄像头驱动拿到buffer缩放后交给编码器省掉CPU搬运。不过这套链路对新手不太友好需要理解DMA-BUF的dma_buf_fd机制。后面我会说几种实际场景下怎么选。2.3 值得多看一眼的#include和依赖问题这个必须单独提出来。librga编译好后头文件要放到交叉编译器的include路径里。很多人在板子上编译成功但交叉编译时找不到im2d.h就是因为没把librga的include目录加进去。按我的习惯会把librga安装到统一目录# 板端或者交叉编译环境安装 sudo make install INSTALL_PREFIX/usr/local export CPLUS_INCLUDE_PATH$CPLUS_INCLUDE_PATH:/usr/local/include/librga export LIBRARY_PATH$LIBRARY_PATH:/usr/local/lib export LD_LIBRARY_PATH$LD_LIBRARY_PATH:/usr/local/lib这样无论是写CMake还是Makefile引用头文件和库文件都会顺很多。3. 五种缩放算法逐一实测from CPU到GPU的对比3.1 测试方案说明本轮实测只针对图像缩放这个单一操作分为两组CPU组Mat数据结构OpenCV直接调用resizeGPU组UMat数据结构OpenCV通过OpenCL后端调用。测试图像采用1080P1920x1080和4K3840x2160两种输入分别缩放到小尺寸480x270约1/4面积等比例缩放1280x7201080P转720P放大2560x14401080P升到2.5K五种缩放算法分别为INTER_NEAREST最近邻插值INTER_LINEAR双线性插值INTER_CUBIC4x4邻域双三次插值INTER_AREA像素区域关系重采样INTER_LANCZOS48x8邻域Lanczos插值需要说明的是每轮测试跑200帧取平均值避免单帧波动影响结论。毕竟是精确到毫秒级的性能对比数据不能拍脑袋。3.2 NEAREST速度之王但学术上叫“像素复制”INTER_NEAREST的原理最简单目标像素的灰度值直接取原图中最近邻像素的值。没有加权计算没有插值公式本质就是个坐标映射再加个round操作。实测数据1080P缩480x270CPU耗时约0.55msGPU耗时约0.32ms1080P缩1280x720CPU耗时约1.1msGPU耗时约0.48ms1080P放大2560x1440CPU耗时约1.9msGPU耗时约0.7ms可见即使是最快的CPU算法GPU依然有1.7到2.7倍的提升。但说句实话NEAREST在CPU上已经不慢如果你的场景对画质没有要求、只追求速度CPU跑NEAREST完全够用没必要上GPU。可一旦做视频墙、九宫格之类的场景动辄几十路视频同时缩放GPU的优势就体现出来了。NEAREST最大的问题就是画质放大后马赛克感非常严重边缘呈锯齿状。适合图标处理、像素风滤镜、缩略图预览这些对“边缘锐利”有偏好的场景。3.3 LINEAR工程默认选择的背后逻辑INTER_LINEAR是绝大多数项目的默认选择。原理是取目标像素周围2x2个邻近像素按距离做两次线性插值。计算量小、画质平衡OpenCV也把它作为resize的默认参数。实测数据1080P缩480x270CPU耗时约2.7msGPU耗时约0.45ms1080P缩1280x720CPU耗时约3.8msGPU耗时约0.62ms1080P放大2560x1440CPU耗时约5.1msGPU耗时约0.9ms这里有意思了GPU加速比从NEAREST的1.7倍直接拉到了6倍。原因在于LINEAR的计算模式发生了质变CPU上每个输出像素要执行4次乘法加法和若干次取整操作而GPU上这些操作在SIMD架构下是天然并行的几乎不增加延迟。如果你的项目目前用的是默认cv::resize没有任何参数也就是LINEAR那在RK3588上转成UMat几乎是无痛的性能提升改动极小收益巨大。3.4 CUBIC高画质需求者的首选但GPU提升更明显INTER_CUBIC采用4x4邻域16个像素做三次卷积插值输出图像比LINEAR更平滑边缘过渡更自然适合图像放大场景。实测数据1080P缩480x270CPU耗时约5.8msGPU耗时约0.85ms1080P缩1280x720CPU耗时约7.9msGPU耗时约1.1ms1080P放大2560x1440CPU耗时约10.2msGPU耗时约1.5ms可以看到CPU耗时已经非常可观了单帧10ms意味着帧率上限只有100FPS如果同时处理多路就撑不住。而GPU端它只比LINEAR多了大约0.3到0.6ms完全在可接受范围内。所以这里有个结论在GPU上CUBIC和LINEAR的速度差距远小于CPU上的差距。如果画质要求高在RK3588上放心大胆用CUBICGPU完全扛得住。前提是你的OpenCL版本对CUBIC有实现这个问题我放在避坑部分详细说。3.5 AREA缩小图像时容易被低估的选项INTER_AREA的原理和前面的插值法完全不同它基于像素区域关系做重采样。图像缩小时它相当于对源图像中一个区域内的像素做均值滤波再抽取。这种处理方式能有效抑制摩尔纹和锯齿所以在缩小时画质反而往往更好。实测数据1080P缩480x270CPU耗时约3.2msGPU耗时约1.2ms1080P缩1280x720CPU耗时约4.5msGPU耗时约1.5ms1080P放大2560x1440这种方式不推荐CPU耗时约5.5msGPU耗时约1.8ms缩小场景下的最佳实践缩小场景下AREA在CPU端的耗时和LINEAR差不多但画质明显更好尤其是图像中有密集纹理或者细线条时LINEAR容易出现混叠AREA则能保持干净。所以我个人在缩小时的推荐顺序是画质最优先AREA速度和画质均衡LINEAR速度最优先NEAREST但有一点要注意AREA放大时效果一般甚至可能引入不自然的块状感。OpenCV官方文档也明确说了.resize用AREA做缩小时效果最好。除非你做的是缩略图类应用否则别用AREA放大。GPU上AREA的提升不如LINEAR显著主要是OpenCL后端对AREA的实现效率没有LINEAR优化得好。实测加速比大约在2.7倍左右够用但不够惊艳。3.6 LANCZOS4画质天花板但门槛也高INTER_LANCZOS4是这五种算法里计算量最大的它基于8x8邻域的Lanczos核函数插值能保留非常多的高频细节放大后的图像边缘几乎没有锯齿同时也没有CUBIC那种轻微的过冲现象。实测数据1080P缩480x270CPU耗时约8.7msGPU耗时约2.1ms1080P缩1280x720CPU耗时约11.5msGPU耗时约2.8ms1080P放大2560x1440CPU耗时约16.3msGPU耗时约3.5msCPU端管它叫“性能杀手”一点不为过4K放大到8K级别的操作基本只能拿PPT级别帧率去跑。GPU端的加速比在4到5倍左右但因为基础耗时就高最终耗时的绝对值依然不低。LANCZOS4适合的场景离线处理图片、印刷输出、医学影像、卫星图像等对细节极度敏感的应用。实时视频流除非你是做演示DEMO否则不建议用。3.7 对五种算法的横向总结先给结论性对比表格1080P缩到720P数值为200帧均值算法CPU耗时(ms)GPU耗时(ms)加速比画质等级适用场景NEAREST1.10.482.3x差缩略图、预览、像素风LINEAR3.80.626.1x中通用、视频流、缺省选项CUBIC7.91.17.2x良放大、高质量显示AREA4.51.53.0x良缩小缩小时专用LANCZOS411.52.84.1x优离线、医学影像从这个表能读出很多信息首先GPU加速对任何算法都有效但加速比差异很大LINEAR和CUBIC是收益最明显的其次算法复杂度越高CPU耗时增长越剧烈但GPU端的增幅比较平缓说明GPU并行架构天然适合这类计算密集但逻辑简单的操作。4. 实操过程CUDA、OpenCL与RGA在同一条代码里的配合4.1 核心代码从Mat到UMat的一步迁移很多OpenCV老手第一次转GPU加速时第一反应是想去改resize的内部实现其实不用的。OpenCV的透明API设计已经替你考虑好了这一点——你只需要把数据容器从cv::Mat换成cv::UMat后续的cv::resize调用会自动路由到OpenCL后端。下面是我在RK3588上验证过的迁移代码#include opencv2/opencv.hpp #include opencv2/core/ocl.hpp #include chrono using namespace cv; using namespace std::chrono; int main() { // 检查OpenCL if (!cv::ocl::haveOpenCL()) { std::cerr No OpenCL available std::endl; return -1; } cv::ocl::setUseOpenCL(true); // 读取图像转成UMat Mat src_cpu imread(input.jpg, IMREAD_COLOR); UMat src src_cpu.getUMat(ACCESS_READ); // 目标尺寸 Size dsize(1280, 720); std::vectordouble cost_list; for (int i 0; i 200; i) { UMat dst; auto start high_resolution_clock::now(); // 这行调用会自动走OpenCL后端 cv::resize(src, dst, dsize, 0, 0, INTER_LINEAR); auto end high_resolution_clock::now(); cost_list.push_back(duration_castmicroseconds(end - start).count() / 1000.0); } // 计算平均耗时 double sum 0; for (auto v : cost_list) sum v; std::cout Average resize time: sum / cost_list.size() ms std::endl; // 回传CPU数据用于显示或后续处理 Mat dst_cpu dst.getMat(ACCESS_READ); imwrite(output.jpg, dst_cpu); return 0; }这里有一个关键点值得展开讲src_cpu.getUMat(ACCESS_READ)这一步如果用默认的ACCESS_RW或者不做内存策略优化OpenCV可能会频繁做map/unmap操作导致实际速度不升反降。我的建议是在深度学习pipeline等场景中尽量让数据全程保持在UMat状态下只在最必要的时候回读CPU。比如摄像头帧从videocapture读进来后先转成UMat再做resize之后直接传给NPU推理全程避免CPU和GPU之间的数据来回搬。4.2 UMat上内存模型与数据回读的一个细节// 错误示范每帧来回拷 Mat frame; cap.read(frame); UMat gpu_frame frame.getUMat(ACCESS_READ); // ... resizing ... Mat out gpu_frame.getMat(ACCESS_READ); // 正确示范如果后续处理仍然是GPU侧就保持UMat UMat frame_um; cap.read(frame_um); UMat resized; cv::resize(frame_um, resized, dsize, 0, 0, INTER_LINEAR); // ... 后续直接基于 resized 操作 ...为什么这个细节重要因为在ARM平台上CPU和GPU是共享物理内存的统一内存架构理论上数据拷贝开销不大。但OpenCL驱动在做map/unmap时会有缓存同步、TLB刷新等额外开销。实测下来每帧做一次来回拷贝大约会增加0.3~0.5ms的损耗。对于4K60fps的实时任务这个损耗直接把你的帧间隔从16.7ms逼到了17.2ms刚好卡在60FPS的及格线外。4.3 RGA和OpenCL怎么选按场景不按情怀在RK3588上RGA和OpenCL各有自己的优势区间下面这张表是我个人长期测试后的心得维度OpenCLRGA集成成本极低改UMat即可中等需要额外封装格式覆盖依赖OpenCV实现NV12/NV16等视频格式原生支持缩放质量算法丰富5种可选硬件线性、双线性为主稳定性偶有驱动兼容问题内核驱动非常稳多路并发取决于OpenCL调度硬件队列轻松多路我现在的经验是纯图像应用、算法调试优先OpenCL因为它改动小基本白嫖。视频流处理pipeline如果涉及NV12转码、送编码器优先RGA它能直接处理视频格式省掉RGB转换。多路视频墙RGA的多路并发能力更强我用RGA同时跑了8路1080P缩放CPU占用接近0。4.4 双路加速的混合编程思路有时候单一加速方式不够比如你需要缩放后的图像继续做NPU推理那就要考虑混合流程RGA先把NV12的摄像头帧缩到NPU输入尺寸然后通过零拷贝转成OpenCV UMat做预处理最终提交给RKNN。这个流程的关键在于缓存共享。Rockchip的rga_buffer_t可以直接用DMA-BUF fd封装而OpenCV的UMat支持cv::UMatDataHandle机制挂自定义内存。更简单的方案是走一条“绕远路”// 从RGA转成UMat的实用方案 // rga_output 是 RGA 输出 buffer可能是 NV12 或 RGB888 Mat rga_mat(rga_h, rga_w, CV_8UC3, rga_ptr); UMat rga_um rga_mat.getUMat(ACCESS_READ); // 后续统一走OpenCV这种方式虽然多了一次内存映射但对工程稳定性和可维护性的提升远大于性能损耗。新手建议先从这里入手等整体pipeline跑通了再考虑dma-buf零拷贝优化。5. 避坑指南RK3588上跑OpenCV GPU加速的几个典型问题5.1 OpenCL设备初始化失败怎么办这是我被问得最多的一个问题。症状是cv::ocl::haveOpenCL()返回true但是Device::getDefault().name()输出异常或者resize耗时和CPU没区别。排查步骤按顺序执行确认Mali GPU驱动在运行ls /dev/mali*如果没有重新安装Mali驱动。确认OpenCL ICD文件存在ls /etc/OpenCL/vendors/里面应该有一个.icd文件内容指向libmali的OpenCL库路径。用官方clinfo工具测试clinfo | grep Device Name如果能列出Mali-G610说明驱动OK。一个容易被忽略的点是部分RK3588的开发板系统镜像里GPU驱动默认没装全尤其是用Ubuntu桌面版时可能只有基础的fbdev驱动没有完整的OpenCL用户态库。建议先到Rockchip官方wiki下载对应的GPU驱动包重装一遍。5.2 INTER_CUBIC和INTER_LANCZOS4在UMat上失效我在RK3588上遇到过这种情况resize用LINEAR正常走GPU换成CUBIC后耗时暴增到和CPU一样甚至更慢。查了OpenCV源码才发现OpenCL后端对CUBIC和LANCZOS4的支持在部分版本里是缺失的会静默fallback回CPU。解决方案有三个升级OpenCV到4.8新增了对Mali OpenCL后端的算法支持强制使用cv::UMat的ocl::resize显式调用在某些版本中有效如果确定需要CUBIC/LANCZOS4的GPU加速而且版本升不上去建议直接用RGA缩放再用OpenCV的filter2D做一次锐化视觉上几乎等效。这里给一个快速检测方法执行resize前后分别测耗时如果GPU组耗时约等于CPU组耗时说明在执行CPU fallback。5.3 多线程并发resize导致的内存暴涨RK3588是8核CPU很多人拿到板子后第一反应就是多线程跑多路视频。但如果你在OpenCL的UMat模式下对每路视频各开一个线程调resize大概率会遇到内存暴涨甚至OOM。原因在于每路线程都会初始化一个独立的OpenCL command queue和上下文Mali GPU驱动的内存池没给够导致频繁申请和释放。我的做法是给多路视频共用一个cv::ocl::Context不要每路新建控制每路UMat的缓存上限用cv::ocl::setUseOpenCL(false)临时关闭某几路的OpenCL改为CPU处理统一平衡负载。5.4 分辨率不是16对齐时RGA产生绿色花屏这个坑我在调试摄像头预览时踩过。RGA的硬件设计对宽高有对齐要求常见的有16像素对齐的约束。如果你的源图宽是1920没问题但目标宽如果是1000RGA处理完可能右边出现一条绿色或黑色的条纹。解决办法最直接的是将目标分辨率向上对齐到16的倍数比如1000调整为1008缩放完成后再用OpenCV裁剪掉多余部分。增加的计算量可忽略但为了那一个裁切步骤你得保证内存分配时多留几个像素的余量不然越界访问会直接崩。5.5 OpenCV版本差异4.2、4.6与4.8之间的性能落差我分别用OpenCV 4.2.0、4.6.0、4.8.0做过对比测试同样条件下跑1080P的resize4.8.0比4.2.0快了大约30%。这主要归功于OpenCV 4.6之后对ARM NEON优化和OpenCL调度器的持续改进。如果你发现自己装的OpenCV版本很老建议升级之前先看一下边框光晕、锯齿这些基础效果是否有改善。很多时候一个升级带来的“免费性能”比费劲优化代码要划算得多。5.6 不要在-Ofast下编译OpenCV这条可能很多人没意识到。我用-Ofast编译OpenCV时resize的结果出现了轻微的像素值偏差。虽然对于缩放来说不算严重但对后续做图像比对或算法评估的场景不可接受。原因很简单-Ofast会启用不安全的浮点优化包括向量化时对浮点运算顺序的重排。OpenCV官方推荐的Release编译等级是-O3我也强烈建议保持-O3别为了那百分之几的收益给自己埋坑。6. 性能提升后的扩展思考缩放算法只是OpenCV GPU加速的冰山一角把resize的GPU加速打通之后你会发现OpenCV的UMat路线在RK3588上还有更多可以迁移的操作cvtColor色彩空间转换、GaussianBlur高斯滤波、Canny边缘检测、warpPerspective透视变换等都有对应的OpenCL实现。尤其在视频处理的pipeline里这些操作往往比resize更耗时如果在你的工程里逐个迁移到UMatCPU占用率会明显下降整体帧率提升非常可观。我自己在完成resize加速后把色彩转换和画框叠加都改成了UMat四路1080P视频的处理总耗时从原来的60ms降到了38ms左右带来的帧率提升立竿见影。这是优化完单一算子之后最自然的下一步延伸。但也要泼一盆冷水不要指望所有OpenCV函数都能在UMat下获得正向加速。比如某些形态学操作、轮廓查找函数在ARM的OpenCL实现并不成熟实际跑起来不比CPU快甚至更慢。所以迁移要讲究策略建议先对项目的热点函数逐个做profiling再用本文档里类似的方法逐一对比测试挑选出真正值得GPU加速的部分。如果一上来就把整个项目全改成UMat可能反而被个别慢速的OpenCL实现拖累整体性能。7. 关于RK3588图像处理后续还能怎么玩写到最后再说几个我觉得值得尝试的方向。第一是RGA与RKNN NPU的深度协同。RK3588的NPU做目标检测时输入图像一般需要缩放到640x640或320x320。目前大部分项目是CPU先把图缩好再拷贝给NPU这中间有显著浪费。如果直接用RGA缩放到目标尺寸并通过dma-buf传给NPU可以省掉两三次内存拷贝整个AI推理的端到端延迟能降低不少。第二是多路视频流的RGA并发优化。RK3588的RGA是有独立硬件队列的多路并发时调度开销远小于CPU多线程。我目前已经在做一些实验尝试把4到8路1080P视频同时送给RGA做缩放然后进入H.264编码器目标是把CPU占用降到20%以内。第三是OpenCV的OpenCL后端替换成Vulkan后端。Mali-G610对Vulkan的支持非常成熟而OpenCV社区也在探索Vulkan后端。Vulkan在驱动稳定性上可能比OpenCL更好值得关注。如果你也在RK3588上做图像处理建议动手之前先想清楚自己的瓶颈在哪是CPU不够是内存带宽不够还是IO延迟把问题定位准确再选择适合的加速方式。不要一上来就OpenCL、RGA全家桶那样只会把简单问题复杂化。按我实际操刀的经验先测出baseline找出真正吃CPU的算子再针对性地迁移到GPU或RGA收益最大也最小风险。希望这篇实测记录能帮你少走一些弯路。