我在Android和优化方面做了很多工作(我写了一个视频处理应用程序,可以在4毫秒内处理一帧),因此我希望我能给你提供一些相关的答案。
OpenCV中的C和C++接口之间没有太大的区别。部分代码是用C编写的,并有C++包装器,反之亦然。根据Shervin Emami的测量,两者之间的任何显着差异都是回归、错误修复或质量改进。您应该使用最新的OpenCV版本。
为什么不重写?
您将花费大量时间,而这些时间可以更好地利用。C接口很麻烦,引入错误或内存泄漏的机会很高。在我看来,您应该避免使用它。
优化建议
A. 开启优化。
编译器优化和缺少调试断言都可以在运行时产生很大的差异。
B. 对您的应用程序进行性能分析。
首先在电脑上进行操作,因为这样更容易。使用Visual Studio Profiler来识别缓慢的部分。对它们进行优化。不要因为你认为它很慢就进行优化,而是因为你测量了它的速度。从最慢的函数开始,尽可能地进行优化,然后再处理第二慢的函数。测量您的更改以确保它确实更快。
C. 关注算法。
更快的算法可以使性能提高数个数量级(100倍)。C++技巧可能会让您的性能提高2倍。
经典技术:
将视频帧调整为较小的尺寸。通常情况下,您可以从200x300像素图像中提取信息,而不是1024x768像素的图像。第一种图像的面积要小10倍。
使用简单的操作代替复杂的操作。使用整数而不是浮点数。在执行数千次的矩阵或for循环中永远不要使用double
。
尽可能少地计算。您能否仅在图像的特定区域跟踪对象,而不是为所有帧处理它?您能否对非常小的图像进行粗略/近似检测,然后在完整帧中的ROI上进行细化?
D. 在关键部分使用C语言
在循环中,使用C语言风格而不是C ++可能更有意义。数据矩阵或浮点数组的指针比mat.at或std :: vector<>快得多。通常瓶颈在于嵌套循环。专注于此。没有必要在代码中到处替换vector<>并使其变得混乱。
E. 避免隐藏成本
一些OpenCV函数会将数据转换为double类型进行处理,然后再转换回输入格式。这些函数会严重影响移动设备的性能,如:warping、scaling和类型转换等。此外,色彩空间转换也会导致性能下降。建议使用从本机YUV直接获取的灰度图像。
使用向量化技术可以提高ARM处理器的性能,其中NEON是一种常用的技术。学习并掌握它,它非常强大!
以下是一个小例子:
float* a, *b, *c;
// init a and b to 1000001 elements
for(int i=0;i<1000001;i++)
c[i] = a[i]*b[i];
可以改写为以下形式。这种方式更冗长,但速度更快。
float* a, *b, *c;
float32x4_t _a, _b, _c;
int i;
for(i=0;i<1000001;i+=4)
{
a_ = vld1q_f32( &a[i] );
b_ = vld1q_f32( &b[i] );
c_ = vmulq_f32(a_, b_);
vst1q_f32( &c[i], c_);
}
for(;i<1000001;i++)
c[i] = a[i]*b[i];
纯粹主义者
认为你必须用汇编语言编写,但对于普通程序员来说,这有点令人生畏。我使用
gcc内置函数获得了良好的结果,就像上面的例子一样。
另一个快速启动的方法是将手写的SSE优化代码转换为NEON。 SSE是英特尔处理器中NEON的等效物,并且许多OpenCV函数使用它,例如
这里。这是uchar矩阵(常规图像格式)的图像过滤代码。您不应该盲目地逐个转换指令,而是以此作为开始的示例。
您可以在
这个博客和以下帖子中了解更多关于NEON的信息。
G.注意图像捕获。
在移动设备上,速度可能会非常慢。优化需要根据设备和操作系统进行。