【发布时间】:2014-07-23 11:38:38
【问题描述】:
我目前正在用 C++ 开发一个跨平台应用程序,主要针对 Android 和 iOS。总体而言,它运行良好且性能令人难以置信,但在 iPhone 4 (S) 上运行非常缓慢(见下图)。
目标是使用特定算法处理约 5-10 fps 的视频流。
除其他外,该代码已成功测试(每秒处理 5 帧或更多帧)并在以下设备上进行了分析:
- 谷歌 Nexus 4
- 谷歌 Nexus 5
- 银河 S 迷你
- 银河 S3
- 索尼 XPeria Z
- Google Nexus one(是的,也可以在那里使用)
- 华为P1和P2
银河笔记
iPad2 迷你版
- iPhone 5
- iPhone 5s
但是,如上所述,它不在 iPhone 4 和 iPhone 4s 上运行。他们都每两秒处理 1 帧 => 0.5fps
当然,这似乎有点奇怪,因为它适用于像华为甚至 Nexus One (2fps) 这样的“较弱”设备,所以我开始使用 Instruments 进行性能和内存消耗分析。
内存消耗还可以,最多使用16MB(从图片可以看出)。但是,运行时的分析让我有点震惊。
和逆调用树:
现在,您可以看到 CPU 正忙于 cvtColor() 函数 (cv::RGB2RGB),占总运行时间的很大一部分。在内部使用了 parallel_for 实现 - 它可能与不适合运行该代码的 CPU 相关联。还是只是在 OpenCV 中实现的 cv::RGB2RGB 函数有点奇怪,因为 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 fps
我的问题 由于它在各种设备以及 iOS 设备上运行良好,因此我认为它必须与 iPhone 4(s) 的硬件或软件相关。
有人知道这里可能出了什么问题吗?有没有人遇到过类似的问题?我在互联网上找到了关于遇到相同性能问题的人的非常少的信息(即here 和here)。
我知道有不同的视频尺寸,但是对 1280x720 像素的图像进行两次“简单”颜色转换不应该消耗大约 2 秒,尤其是在 iPhone 4 等最近的设备上(S) 是!
非常感谢以这种方式提供的任何帮助、提示或经验!
进展和进一步发现
根据 remi 的评论,我尝试了其他解决方案。不幸的是,我不得不说以下(非常微不足道的)事情也不起作用:
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 秒!然后将蓝色通道作为灰色 Mat 再次快速,因为只创建了一个 Mat-header。
这再次表明循环实现有问题,因为 split() 复制数据,这显然是在循环中完成的。
【问题讨论】:
-
stackoverflow.com/questions/11219240/… 是我调查发现的。不确定是否对您有帮助。是的,每一代 i 设备都比旧设备快得多。我的 iPad3 比 4S 快得多,4S 比 iPad3 快得多,新的 iPad mini 似乎两者都击败了。
-
不是您的硬件相关问题的答案,但您可能会使用
cv::split和cv::marge函数而不是就地cv::cvtColor获得一些性能。我不确定它如何就地摆脱通道。或者尝试在与colorMat不同的矩阵上调用cv::cvtColor作为输入和输出,然后告诉我们。 -
感谢 cmets。我将始终编辑第一篇文章以保持一切清洁。我开始玩耍,偶然发现了一些更奇怪的事情,这与分析中的初步观察不符。不幸的是,我今天没有时间详细调查,明天我会打电话给你们,提供有关此问题的更多详细信息。在此感谢!