BlockingCollections,Tasks和OpenCV随着时间的推移性能下降

时间:2017-04-18 19:25:24

标签: c# android opencv blockingcollection

我正在使用Xamarin for Android和OpenCV C#绑定库编写一个简单的光学测量应用程序。

为了将帧抓取器与处理分开,我创建了一些阻塞集合来传递raw,然后处理不同线程之间的图像。我有一个问题,在大约30秒的时间内,GUI显示精美流畅的处理视频(15秒)到波涛汹涌的视频(10秒),然后崩溃。

下面的代码显示了集合的定义。 OnCameraFrame(代码底部)将每个新帧推送到camframes集合中。在OnCreate中,我运行一个名为CamProcessor的任务,它接受框架,执行许多操作,并将其填充到outframes集合中。然后OnCameraFrame获取该处理过的帧并将其显示给GUI。出于本文和测试的目的,我已经完全注释掉了我的所有处理,因此只需将原始数据传递到集合中就可以解决这个问题。

另一个注意事项是我的收藏品似乎运行得非常快。在任何时候我都没有超过1帧,所以这不是溢出问题(我认为)。

任何人都可以指出为什么这种策略效果不佳?

BlockingCollection<Mat> camframes = new BlockingCollection<Mat>(10);
BlockingCollection<Mat> outframes = new BlockingCollection<Mat>(10);
public CameraBridgeViewBase mOpenCvCameraView { get; private set; }

    protected override void OnCreate(Bundle savedInstanceState)
    {
        //LayoutStuff

        mOpenCvCameraView = FindViewById<CameraBridgeViewBase>(Resource.Id.squish_cam);

        Task.Run(() => camProcessor());
    }

    public void camProcessor()
    {
        while (!camframes.IsCompleted)
        {
            Mat frame = new Mat();
            try
            {
                frame = camframes.Take();
            }
            catch (InvalidOperationException) { }

            Mat frameT = frame.T();
            Core.Flip(frame.T(), frameT, 1);
            Imgproc.Resize(frameT, frameT, frame.Size());
            outframes.Add(frameT);
         }
     }

    public Mat OnCameraFrame(CameraBridgeViewBase.ICvCameraViewFrame inputFrame)
    {
        mRgba = inputFrame.Rgba();
        Mat frame = new Mat();
        Task.Run(() => camframes.Add(mRgba));
        try
        {
            frame = outframes.Take();
        }
        catch (InvalidOperationException) { }

        return frame;
    }

1 个答案:

答案 0 :(得分:0)

在查看Android SDK monitor.bat输出后,我发现这是一个内存泄漏。事实证明它是Java openCV包装器的常见问题,并且是OpenCV的mat堆远大于C#所期望的结果,因此它不会被垃圾收集。

解决方案是在每个帧抓取时附加这些:

             GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
             GC.Collect();
             GC.WaitForPendingFinalizers();