返回专辑
·Johan·3 分钟阅读

OpenCV 流水线:先剖面再优化

重复 Mat 拷贝、cvtColor 来回和每帧 undistort 吃 CPU;getTickCount 剖面找热点,再谈换 SOTA 模型。

OpenCV 流水线:先剖面再优化

1. 换模型前先量流水线

五十毫秒端到端里三十毫秒是不必要的色彩来回转换和矩阵拷贝,换检测版本只省两毫秒——这种优化顺序在产线很常见。OpenCV 流水线优化是工程测量问题:没有剖面的优化,常优化错地方。规则很简单:先计时剖面,找第一热点,动刀,再剖面——循环直到预算满足或热点是输入输出 bound。我见过团队直接上 tensor 运行时,热点其实在每帧去畸变和 Python 非极大值抑制循环。

2. 阶段剖面

每阶段用计时函数,报中位数和百分之九十九分位。典型链:采集、重映射、缩放、色彩、推理、后处理。机器人中间件压缩图像解码、GStreamer 转矩阵都可能是隐藏热点——它们不在前向推理里,但在端到端预算里。剖面表要含最坏输入:最大分辨率、最多检测框,不只平均图像。

python
freq = cv2.getTickFrequency()
t0 = cv2.getTickCount()
# capture → remap → resize → blobFromImage → forward → NMS
t1 = cv2.getTickCount()
ms = (t1 - t0) / freq * 1000

3. 避免多余拷贝

感兴趣区域是视图不拷贝。连续内存有利于 simd,非连续要先转成连续数组。色彩转换每次分配新缓冲——训练用红绿蓝、相机用蓝绿红、神经网络预处理交换红蓝参数要对齐,统一一处转换。GStreamer 包装缓冲可零拷贝,但注意缓冲生命周期,矩阵指向已释放内存是经典崩溃来源。Python 侧数组有时拷贝有时视图,剖面时用连续性标志检查。

4. 常见热点与修复

热点修复
每帧完整去畸变预计算映射加重映射
缩放过大的输入感兴趣区域或合理输入尺寸
Python 非极大值抑制循环C++ 或向量化
调试显示生产关闭
采集缓冲堆满缓冲大小为一加取最新帧

机器人要低延迟常取最新帧丢弃旧帧,而不是队列堆满等输入输出。OpenCV 线程数与外层流水线线程配合——嵌套并行会过度订阅,外层已并行时常设单线程。

5. 并行与缓冲策略

采集线程加推理线程双缓冲;别多线程无锁写同一矩阵。统一内存或 OpenCL 对部分操作加速;嵌入式先看 neon 和线程数,别盲目上图形处理器。构建信息里的 simd 和运行时优化开关影响基线——对比前后保持一致。

6. 案例:剖面改顺序

某嵌入式流水线剖面:去畸变四点二毫秒、色彩转换两次三点一毫秒、推理八毫秒、Python 非极大值抑制二点八毫秒。先换重映射、合并色彩转换、非极大值抑制改 C++,端到端十八到九毫秒——没换模型。若直接换 tensor 运行时,推理八到六毫秒,总改善远小于剖面驱动优化。这案例我用来挡「先换大模型」的需求。

7. 与录包和部署

生产环境关闭调试可视化路径;录包时剖面开销也要关,否则测的不是产线路径。部署清单写清 OpenCV 线程数、缓冲策略、色彩转换次数,换机器时逐项核对。

8. 验收

  • 前后阶段毫秒表(中位数与百分之九十九)
  • 端到端帧率加处理器利用率
  • 确认热点不是输入输出 bound 再换算法
  • 生产关闭调试可视化
  • 最坏输入剖面

没有剖面就换最新模型,多半是在噪声上作画。剖面是契约,优化是证据。

← 全部文章

johan's blog