OpenCV:C++和C性能比较

OpenCV: C++ and C performance comparison

本文关键字:性能 性能比 比较 C++ OpenCV      更新时间:2023-10-16

现在我正在使用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
  1. 接口 (IplImage) 在直接访问像素而不是使用 Mat.at(x,y) 方法时速度快了许多倍,当我将C++应用程序转换为 C 时,我的 blob 检测例程的性能提高了 3 倍

  2. 当从外部应用程序(例如LabView)调用时,C++接口在某些例程中崩溃,而在C中调用相同的例程时,它工作

  3. C语言与嵌入式设备的兼容性要高得多。但是,我还没有在这个领域做任何事情。

我在IOS设备上遇到了类似的问题,并讨论了IOS/iPad/iPhone的最大速度也包括一些适用于其他移动平台的提示。