OpenCV:C++和C性能比较
OpenCV: C++ and C performance comparison
现在我正在使用OpenCV API开发一些应用程序(C++
)。此应用程序对视频进行处理。
在PC上,一切都运行得非常快。今天我决定在Android上移植这个应用程序(使用相机作为视频输入)。幸运的是,有适用于Android的OpenCV,所以我只是将我的本机代码添加到示例Android应用程序中。除了性能之外,一切都很好。我对我的应用程序进行了基准测试,发现该应用程序以 4-5 fps 的速度工作,这实际上是不可接受的(我的设备具有单核 1GHz 处理器) - 我希望它以大约 10 fps 的速度工作。
在C
上完全重写我的应用程序是否有意义?我知道使用std::vector
这样的东西对开发人员来说很舒服,但我不在乎它。
似乎OpenCV's C
界面具有与C++
接口相同的功能/方法。
我在谷歌上搜索了这个问题,但没有找到任何东西。
感谢您的任何建议。
我在Android和优化方面做了很多工作(我写了一个视频处理应用程序,可以在4ms内处理一帧),所以我希望我能给你一些相关的答案。
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 函数将数据转换为双精度,对其进行处理,然后转换回输入格式。当心它们,它们会扼杀移动设备的性能。示例:变形、缩放、类型转换。此外,众所周知,颜色空间转换是惰性的。首选直接从本机 YUV 获得的灰度。
F. 使用矢量化
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;
// init a and b to 1000001 elements
float32x4_t _a, _b, _c;
int i;
for(i=0;i<1000001;i+=4)
{
a_ = vld1q_f32( &a[i] ); // load 4 floats from a in a NEON register
b_ = vld1q_f32( &b[i] );
c_ = vmulq_f32(a_, b_); // perform 4 float multiplies in parrallel
vst1q_f32( &c[i], c_); // store the four results in c
}
// the vector size is not always multiple of 4 or 8 or 16.
// Process the remaining elements
for(;i<1000001;i++)
c[i] = a[i]*b[i];
纯粹主义者说你必须用汇编程序编写,但对于一个普通的程序员来说,这有点令人生畏。我使用 gcc 内联函数得到了很好的结果,就像上面的例子一样。
另一种快速入门的方法是将OpenCV中手工编码的SSE优化代码转换为NEON。SSE 是英特尔处理器中的 NEON 等价物,许多 OpenCV 函数都使用它,就像这里一样。这是 uchar 矩阵(常规图像格式)的图像过滤代码。您不应该盲目地逐个转换指令,而是以它为例开始。
您可以在此博客和以下文章中阅读有关NEON的更多信息。
G.注意图像捕捉
它在移动设备上可能会出奇地慢。优化它特定于设备和操作系统。
在做出任何这样的决定之前,您应该分析代码以找到代码中的热点。如果没有这些信息,您为加快速度所做的任何更改都将是猜测。你试过这个安卓NDK分析器吗?
Shervin imami在他的网站上进行了一些性能测试。您可以查看它以获得一些想法。
http://www.shervinemami.info/timingTests.html
希望对您有所帮助。
(而且,如果你有任何提高性能的方法,如果你在某个地方分享你自己的发现,那就太好了。
需要表述为:C比C++快吗?答案是否定的。两者都被编译为本机机器语言,C++被设计为与C一样快至于 STL(尤其是 ISO 标准)也经过精心设计和注意,它们与指针一样快 + 它们提供了灵活性。使用 C 的唯一原因是您的平台不支持C++在我谦虚的开场白中,不要将所有内容都转换为 C,因为您可能会获得几乎相同的性能。并尝试改进您的代码或使用OpenCV的其他功能来做您想做的事情。
不相信?好吧,然后写一个简单的函数,一次在C中,一次在C++中,并在1亿次循环中运行它并自己测量时间。也许这可以帮助您做出正确的决定
我从未在Android中使用过C或C++。但是在PC中,您可以获得与C代码一样快的C++运行速度(有时甚至更快)。C++大部分都是专门为允许更多功能而设计的,但不是以速度为代价的(模板在编译时解决)。大多数编译器都非常擅长优化代码,并且您的 std::vector 调用将被内联,代码将与使用本机 C 数组几乎相同。
我建议你寻找另一种提高表现的方法。也许Android中有一些多媒体硬件扩展,您可以访问并用于优化代码。
我在多个测试中注意到:
- C
接口 (IplImage) 在直接访问像素而不是使用 Mat.at(x,y) 方法时速度快了许多倍,当我将C++应用程序转换为 C 时,我的 blob 检测例程的性能提高了 3 倍
当从外部应用程序(例如LabView)调用时,C++接口在某些例程中崩溃,而在C中调用相同的例程时,它工作
。C语言与嵌入式设备的兼容性要高得多。但是,我还没有在这个领域做任何事情。
我在IOS设备上遇到了类似的问题,并讨论了IOS/iPad/iPhone的最大速度也包括一些适用于其他移动平台的提示。
- 为什么constexpr的性能比正常表达式差
- 在现代C++中,侵入式容器是否仍然比非侵入式容器具有性能优势?
- 每个编译器的C++性能,比C#慢200倍
- C++多线程性能比单线程代码慢
- 多线程功能性能比单线螺纹差
- localtime() 比 Linux 上的 gmtime() 性能问题多 24 倍
- 为什么这个普通的数组实现比STD ::向量实现性能慢
- C:pthread的性能,比单线程低
- 全局对象是否提供比多个本地实例更好的性能
- 为什么 std::make_shared<>() 的性能比 boost::make_shared() 好得多?
- 在OpenGL中为顶点、uvs和法线使用一个缓冲区是否比使用三个缓冲区性能更好
- 性能权衡-MATLAB何时比C/C++更好/更慢
- 为什么预分配的函数指针的性能比分支差
- 为什么 std::vector 比本机数组的性能更高
- C++特征库如何比专门的供应商库性能更好
- pthread_mutex锁是否提供比用户在代码中施加的内存屏障更高的性能
- c++ 11委托的函数是否比c++ 03调用init函数的函数性能差?
- 放炮的性能比先放炮后复核的性能差
- 为什么我的散点代码的性能比Vc SIMD更好
- 为什么 C++ fseek/fread 的性能比 C# FileStream 的 Seek/Read 高几倍