改善OpenCV在Android上的性能 - 快速物体跟踪

8
我正在尝试在Android上实现一个快速的物体跟踪应用程序。
我的逻辑如下:
  1. 除了所需颜色范围之外,删除所有颜色。
  2. 使用GaussianBlur平滑图像
  3. 使用HoughCircles查找最大半径的圆形
该应用程序基本上可以正常工作,但性能很差,我希望将性能提高至少5倍。我从这个链接中借用了许多逻辑。 快速物体跟踪示例
public void apply(Mat src, Mat dst) {
    Mat mIntermediateMat = new Mat(src.rows(), src.cols(), CvType.CV_8UC1);

    Mat mHsv = new Mat(src.size(), CvType.CV_8UC3);
    Mat mHsv2 = new Mat(src.size(), CvType.CV_8UC3);

    Imgproc.cvtColor(src, mHsv, Imgproc.COLOR_RGB2HSV, 3);

    Core.inRange(mHsv, new Scalar(0, 86, 72), new Scalar(39, 255, 255), mHsv); // red
    Core.inRange(mHsv, new Scalar(150, 125, 100), new Scalar(180,255,255), mHsv2); // red
    Core.bitwise_or(mHsv, mHsv2, mHsv);

    /// Reduce the noise so we avoid false circle detection
    Imgproc.GaussianBlur(mHsv, mHsv, new Size(7, 7), 2);
    Imgproc.HoughCircles(mHsv, mIntermediateMat, Imgproc.CV_HOUGH_GRADIENT,2.0,100);

    int maxRadious = 0;
    Point pt = new Point(0,0);
    if (mIntermediateMat.cols() > 0) {
        for (int x = 0; x < mIntermediateMat.cols(); x++)
        {
            double vCircle[] = mIntermediateMat.get(0,x);

            if (vCircle == null)
                break;

            int radius = (int)Math.round(vCircle[2]);
            if (radius > maxRadious) {
                maxRadious = radius;
                pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));
            }

        }
        int iLineThickness = 5;
        Scalar red = new Scalar(255, 0, 0);
        // draw the found circle
        Core.circle(dst, pt, maxRadious, red, iLineThickness);
    }

}

我一直在思考提高我的性能的方法,我想知道哪些是可行且显著的建议。

1) 使用多线程。我可以使用一个线程来从相机捕获图像,另一个线程来处理图像。从OpenCV Android发布说明中得知,“启用了对TBB的多线程支持(目前只优化了少量函数)。”但是我不理解这个。TBB仅适用于英特尔芯片吗?有哪些函数可用?是否有与Android和OpenCV相关的示例?

2) 使用更强大的Android设备。我目前在2012款Nexus 7上运行,使用前置摄像头。我并不了解哪些规格对我很重要。Nexus 7(2012年)配备1.3 GHz四核Nvidia Tegra 3 CPU和416 MHz Nvidia GeForce ULP GPU。

如果我在目前最快的Android手机上运行,会有多大差异?

哪些规格最相关于此类型的应用程序?

  1. CPU。
  2. GPU。
  3. 核心数。
  4. 相机的帧速率。

3) 使用本地C ++代码是否会对我的性能产生积极影响?

4) 是否有替代OpenCV的选择?

2个回答

7

0)我建议你为使用的所有函数进行剖析(或测量运行时间),以检查需要优化的内容,然后再计划进一步的优化。

1)多线程可以提高帧率,但不能消除延迟(一个核心处理器在x毫秒内处理一个帧,你有N个核心,所以你会非常快地获得N帧,然后又要等待x毫秒)。我不确定OpenCV是否支持多核心,但据我所知,高斯模糊和霍夫变换并不适用于多核心。

2)Intel TBB不仅适用于英特尔芯片,人们也将其用于ARM和AMD芯片。参见OpenCV configure with TBB for ARM (Ubuntu, 3.0.63)

3-4)你使用的算法相当简单,所有这些算法都可以自己实现,而不需使用OpenCV。而OpenCV的霍夫变换或高斯模糊速度相当快。在整个程序运行时方面,C++比Python更快,但是Python OpenCV只是C++库的封装,因此它们的性能“单独”来看是类似的。


3
此外,我认为对于当前基于OpenCV的程序来说,CPU速度和芯片组是最重要的因素(目前还没有太多基于多核、GPU计算的OpenCV-Android应用)。如果你无法解决问题,可以尝试降低预览分辨率。 - flankechen
谢谢您的回答,我尝试了多线程,但没有看到任何显著的改进。也许我的实现有问题。我将提出一个新问题。我将不得不尝试找到更多关于TBB的资源,并像您建议的那样进行分析。我认为您的答案连同flankechen的意见 - 解决了我大部分的问题。顺便说一下,这是Java而不是Python。 - Ryan Heitner

3

首先,正如之前所说的那样,对你的代码进行剖析。Android SDK剖析器非常棒,可能是我尝试过的几个中最好的。

以下是一些可以轻松让你看到一些改进的方法:

  • 不要在处理代码(每次捕获图像时调用的代码)中声明(实例化)那些数据结构(Mat、Scalar、Point)。尝试重复使用它们。

  • 你不需要使用完整的图像比例来进行对象跟踪,你可以调整(缩小)每个图像帧的大小,或者使用图像ROI:处理图像的较小区域。

  • 你的Nexus 7支持OpenCV NEON优化,这些优化由NVIDIA Tegra硬件支持,请查看相关文档。基本上,你需要使用支持NEON的OpenCV编译,如果你寻找相关文档,就会找到。

编辑:

因为你提到了高斯模糊存在问题,你可以尝试使用其他类型的模糊 (中值、归一化盒子) ,它们更快速,而且你还可以增加滑动窗口(也称为内核)大小(第三个参数),内核越大,处理图像的速度越快。

http://docs.opencv.org/doc/tutorials/imgproc/gausian_median_blur_bilateral_filter/gausian_median_blur_bilateral_filter.html


谢谢,我已经意识到你的第一个观点是至关重要的,如果我在循环中实例化它们,可能会导致缓冲错误。我将尝试实施你的另外两个建议。目前我正在尝试使用NDK在C++中做更多工作,看看是否可以提高我的帧率。 - Ryan Heitner
瓶颈似乎在于高斯模糊。我尝试使用定制的快速模糊解决方案,但似乎没有任何区别,可能是因为我首先进行了位图转换。我将继续尝试寻找更快的模糊解决方案。 - Ryan Heitner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接