【问题标题】:OpenCV Android Program Bottle-necked by Morphological FunctionsOpenCV Android 程序被形态函数瓶颈
【发布时间】:2016-07-18 19:40:59
【问题描述】:

我有一个对二进制矩阵执行腐蚀和膨胀的函数:

void Detector::morphOps(Mat& binFrame) {
    Mat erodeElement = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    Mat dilateElement = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));

    erode(binFrame, binFrame, erodeElement);
    dilate(binFrame, binFrame, dilateElement);
    dilate(binFrame, binFrame, dilateElement);
}

这使我的程序在检测我想要跟踪的对象方面更加健壮。但是,这段代码对我的程序的其余部分来说是一个巨大的瓶颈。启用该功能后,我从 25-30 fps 降至

我也在考虑多线程,但我不确定如何在这里实现它,因为我对 android 和 opencv 还很陌生。上面的代码是我程序的原生 (jni) 部分。

编辑:到目前为止我尝试过的替代方案:

morphologyEx() 打开 + 关闭 - 效果不佳,因为扩张尺寸需要大于侵蚀尺寸。

morphologyEx() 关闭 + dilate() - 在 Android 上没有显着的性能提升。

将 MORPH_ELLIPSE 更改为 MORPH_RECT。我现在得到了 ~8fps,但这仍然很慢。

【问题讨论】:

    标签: java android c++ multithreading opencv


    【解决方案1】:

    我在 Zenfone 2 上对其进行了测试,没有太多性能问题,它从 30fps 到 23fps,但我使用的是 640x360 分辨率。

    尝试降低图像分辨率:

    javaCameraView.setMaxFrameSize(size.width, size.height);
    

    您还可以创建全局变量,这样就不必一直初始化它:

    Mat erodeElement = getStructuringElement(MORPH_ELLIPSE, Size(3, 3));
    Mat dilateElement = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
    
    void morphOps(Mat& binFrame) {
        erode(binFrame, binFrame, erodeElement);
        dilate(binFrame, binFrame, dilateElement);
        dilate(binFrame, binFrame, dilateElement);
    }
    

    你的框架来自 javaCameraView 吗?如何将数据从 Java 传递到 C++ 也很重要,像这样使用:

    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame)
    {
        _imgBgrTemp = inputFrame.rgba();
        jniFrame(_imgBgrTemp.nativeObj);
        return _imgBgrTemp;
    }
    

    .nativeObj 传递指针而不重新复制数据。

    关于线程,这可能是一个好主意,但让它安全地工作非常复杂,我还有一个关于“Android 上的 OpenCV 多线程”的问题。 Here

    在写这篇文章的时候,那里还没有答案,但你可以跟我来。

    【讨论】:

    • 谢谢!我也会看看你的问题。我的分辨率是 640 x 480,但有时它从 1920 x 1080 开始,我不知道如何解决。您提到制作全局变量..这是否意味着将 img 尺寸设置为全局?除非我理解不正确,否则我不确定这会有什么帮助。
    • 另外,忘了提一下,我在不同的二进制 mat 对象上调用 morphOps() 7 或 8 次,因为我正在寻找不同 hsv 阈值的彩色对象。这就是让我慢下来的原因,这就是我考虑并行处理的原因。
    • 你应该调用:javaCameraView.setMaxFrameSize(size.width, size.height);在启用视图之前,如下所示: javaCameraView = (JavaCameraView)findViewById(R.id.cameraView); javaCameraView.setMaxFrameSize(size.width, size.height); javaCameraView.setVisibility(SurfaceView.VISIBLE); javaCameraView.setCvCameraViewListener(this); javaCameraView.enableView(); javaCameraView.enableFpsMeter();
    • 关于使 var 全局化,在这种情况下只是一个好习惯,因为每次初始化这些 var 时,它都会消耗一些处理,而且它们总是相同的,这是一个好主意只初始化一次并在每次调用函数时重用它们,而不必再次初始化它们
    • 您在寻找什么样的对象?也许会有更好的方法......
    【解决方案2】:

    利用距离变换,您可以模拟形态学运算,尤其是那些具有磁盘结构元素的运算,并且运行速度更快。

    代替:

    int closeDiam = 2 * closeRadius + 1;
    Mat strel = Imgproc.getStructuringElement(Imgproc.MORPH_ELLIPSE, new Size(closeDiam, closeDiam));
    Mat dst = new Mat();
    Imgproc.morphologyEx(src, dst, Imgproc.MORPH_CLOSE, strel);
    

    尝试:

    Mat negSrc = new Mat();
    Core.bitwise_not(src, negSrc);
    Mat negSrcDT = new Mat();
    Imgproc.distanceTransform(negSrc, negSrcDT, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_PRECISE);
    Mat dilated = new Mat();
    Core.compare(negSrcDT, new Scalar(closeRadius), dilated, Core.CMP_LE);
    Mat dilatedDT = new Mat();
    Imgproc.distanceTransform(dilated, dilatedDT, Imgproc.CV_DIST_L2, Imgproc.CV_DIST_MASK_PRECISE);
    Mat dst = new Mat();
    Core.compare(dilatedDT, new Scalar(closeRadius), dst, Core.CMP_GT);
    

    运行时间约为半径 = 10 的 1/3、半径 = 20 的 1/8、半径 = 30 的 1/11、半径 = 40 的 1/21 和半径 = 50 的 1/29。

    由于某种原因,这两种方法的结果并不完全等效(对于半径 = 10 几乎无法辨别,但随着半径的增加,它们的差异更大)。但从概念上讲,它们是相同的:膨胀+腐蚀。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多