c++ - iPhone 4(S) 上的 OpenCV cvtColor() 性能问题

标签 c++ ios opencv

我目前正在使用 C++ 开发跨平台应用程序,主要针对 Android 和 iOS。总的来说它工作得很好并且具有令人难以置信的性能,但在 iPhone 4 (S) 上它运行非常非常慢(见下图)。

目标是使用特定算法处理约 5-10 fps 的视频流。

除其他外,代码已成功测试(每秒处理 5 个或更多帧)并在以下设备上进行分析:

  • 谷歌 Nexus 4
  • 谷歌 Nexus 5
  • 银河小号
  • 银河 S3
  • 索尼 Xperia Z
  • Google Nexus one(是的,也在那里工作)
  • 华为P1和P2
  • 银河笔记

  • iPad2 mini

  • iPhone 5
  • iPhone 5s

但是,如前所述,它不能在 iPhone 4 和 iPhone 4s 上运行。它们都每两秒处理 1 帧 => 0.5fps

当然,这看起来有点奇怪,因为它在“较弱”的设备上工作,例如华为甚至 Nexus One (2fps),所以我开始使用 Instruments 分析性能和内存消耗。

Memory usage of the app

内存消耗还可以,最多使用 16MB(如图所示)。然而,运行时的分析让我有点震惊。

Runtime Profiling

和逆调用树:

Runtime Profiling with inverse call tree

现在,如您所见,CPU 正忙于 cvtColor() 函数 (cv::RGB2RGB),占总运行时间的很大一部分。在内部使用了 parallel_for 实现——它是否可能链接到不适合运行该代码的 CPU。或者它只是 cv::RGB2RGB 函数,它在 OpenCV 中以某种奇怪的方式实现,因为 BGR2Gray 转换似乎运行得更快?

我使用的是最新的预编译版本OpenCV v2.4.9 for iOS .有问题的这段代码基本上只做从 BGRA 到灰度的颜色转换。看起来像:

Mat colorMat;
Mat gray;    

colorMat = Mat(vHeight,vWidth,CV_8UC4, rImageData); // no data is copied
cvtColor(colorMat,colorMat,CV_BGRA2BGR);
cvtColor(colorMat,gray,CV_BGR2GRAY);

请注意它分为两次转换,因为进一步处理需要 RGB 和灰色信息 - 这就是为什么不在一个转换步骤中。

另一边的评论: 我还测试了 OpenCV for iOS samples (第 12 章:处理视频),交付(以 30fps 捕获率开始时):

  • iPhone 4:5.6 帧/秒
  • iPad mini:30.4 帧/秒

我的问题 由于它在各种设备和 iOS 设备上运行良好,我断定它必须与 iPhone 4(s) 的硬件或软件相关。

有人知道这里可能出了什么问题吗?有人遇到过类似的问题吗?我在互联网上发现关于人们遇到相同性能问题(即 herehere )的信息非常少。

我知道有不同的视频尺寸,但是 1280x720 像素图像的两次“简单”颜色转换不应该消耗大约 2 秒,尤其是在像 iPhone 4 这样的最新设备上(S) 是!

非常感谢以这种方式提供的任何帮助、提示或经验!

进展和进一步发现

根据雷米的评论,我尝试了替代解决方案。不幸的是,我不得不说以下(非常微不足道的)事情也不起作用:

Mat colorMat, gray;
vector<Mat> channels;
AVDEBUG("starting", TAG,1);
colorMat = Mat(vHeight,vWidth,CV_8UC4, rImageData); // no data is copied
AVDEBUG("first", TAG, 1);
split(colorMat, channels);
AVDEBUG("intermediate " << colorMat.size(), TAG, 1);
// no BGRA2BGR conversion at all!!
gray = channels[0]; // take blue channel for gray
AVDEBUG("end", TAG, 1);

产生以下输出:

2014-07-24 09:07:41.763 CheckIfReal[604:3d03] AvCore-Debug: (Debug, Tag=CoreManager) Frame accepted (/Users/tbergmueller/Documents/dev/AvCore/avcore/CoreManager.cpp, line 591)

2014-07-24 09:07:41.765 CheckIfReal[604:3d03] AvCore-Debug: (Debug, Tag=CoreManager) starting (/Users/tbergmueller/Documents/dev/AvCore/avcore/CoreManager.cpp, line 636)

2014-07-24 09:07:41.771 CheckIfReal[604:3d03] AvCore-Debug: (Debug, Tag=CoreManager) first (/Users/tbergmueller/Documents/dev/AvCore/avcore/CoreManager.cpp, line 641)

2014-07-24 09:07:44.599 CheckIfReal[604:3d03] AvCore-Debug: (Debug, Tag=CoreManager) intermediate [720 x 1280] (/Users/tbergmueller/Documents/dev/AvCore/avcore/CoreManager.cpp, line 665)

2014-07-24 09:07:44.605 CheckIfReal[604:3d03] AvCore-Debug: (Debug, Tag=CoreManager) ending (/Users/tbergmueller/Documents/dev/AvCore/avcore/CoreManager.cpp, line 682)

因此 Mat 构造函数 Mat() 很快,因为没有数据被复制(引用 docs )。但是,split() 函数在这段代码示例中花费了将近 3 秒!!将蓝色 channel 作为灰色 Mat 再次快速,因为只创建了一个 Mat-header。

这再次表明循环实现有问题,因为 split() 复制数据,这显然是在循环中完成的。

最佳答案

我要解决这个问题,感谢您的评论,这将我推向了正确的方向!

正如预期的那样,也从评论中了解到,1280x720px 的数据太多,无法在 iPhone 4s 上处理,我必须找到一个解决方法。

大多数人可能都知道,图像处理主要是用灰度图像完成的。如果图像是从 iPhone 相机捕获的 BGRA,这意味着首先转换 CV_BGRA2GRAY(这可能与cv::cvtColor).

现在,从分析中可以看出,此转换花费的时间太长,因此我必须取消转换。在 iPhone 4(s) 上可能的一种选择是将相机配置为以 420YpCbCr 模式而非 BGRA 模式捕捉。有关如何正确配置相机的 StackOverflow 主题。对我来说尤其是 thisthis as well 很有帮助。

不幸的是,iPhone 4 只支持 3 种像素格式类型,即 420v、420f 和 BGRA。使用此信息和上面的链接,我决定使用 kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange(对应于 420v)。最大的好处是您在一个图像平面中拥有灰度图像 (​​luma),在另一个图像平面中拥有颜色信息 (chroma),并且可以分别访问它们。

关键思想是检测灰度图像中感兴趣的区域,然后仅将颜色空间转换应用于那些通常比完整图像少得多的感兴趣像素。通过避免从彩色图像实际转换为灰度,并且仅将色彩空间转换应用于感兴趣的小区域,我的算法在 iPhone 4 上的处理速度提高到每秒约 10 帧,这对于所需的应用程序来说是可以接受的。

关于c++ - iPhone 4(S) 上的 OpenCV cvtColor() 性能问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24909484/

相关文章:

c++ - 耳朵识别和上半身 haarcascade

java - 我可以使用TextureView同时显示相机预览和检测到的线吗?

c++ - 使用 Nvidia 的 Thrust 库规范化一堆 vector

c# - 从 C# 程序调用 c++ DLL,未处理的异常

ios - 如何在 WKWebView 上加载 URL?

ios - os.log 是做什么用的?

c++ - OpenGL 体素引擎人脸合并与逐顶点环境光遮挡

c++ - 在 COM 接口(interface)中访问子对象

ios - 无法将内容附加到数组

opencv - 如何为 GNAT 绑定(bind)到 OpenCV?