首页 > 解决方案 > 在 C++ 中统一使用后台线程进行图像处理会导致崩溃

问题描述

我正在尝试在后台在 Unity 和 OpenCV 中进行一些图像处理,因为它需要大约 60 毫秒到 100 毫秒才能完成,并且在主线程上执行时会大大减慢应用程序的速度。

我在每秒执行 30 次的“相机帧可用”回调中执行此操作。我正在使用资产商店中的“Task Parallel”。

C# 代码

private const int numMaximumThreads = 3;
private volatile int currentNumberOfWorkingThreads = 0;

unsafe private void OnRawVideoFrameAvailableYUV(MLCameraResultExtras resultExtras, YUVFrameInfo frameInfo, MLCameraFrameMetadata frameMetadata)
{
    //only have a maximum of 3 threads
    if(currentNumberOfWorkingThreads < numMaximumThreads)
    {
        //run on background
        UnityTask.Run(() =>
        {
            currentNumberOfWorkingThreads++;
            MLCamera.GetFramePose(resultExtras.VcamTimestampUs * 1000, out translationMatrix);

            float x = 0, y = 0, z = 0, rx = 0, ry = 0, rz = 0;
            //fix the bytearray for OpenCV on c++ side
            fixed (byte* yBuffer = frameInfo.Y.Data)//camera uses YUV instead of RGB
            {
                fixed (byte* uBuffer = frameInfo.U.Data)
                {
                    fixed (byte* vBuffer = frameInfo.V.Data)
                    {   //call OpenCV / c++ function
                        Interop.Detect((IntPtr)yBuffer, (IntPtr)uBuffer, (IntPtr)vBuffer, camWidth, camHeight, ref x, ref y, ref z, ref rx, ref ry, ref rz);
                    }
                }
            }
            //r to rz are translation and rotation vectors that OpenCV returns
            return new float[6] { x, y, z, rx, ry, rz };
        //after completion, move gameobjects on unity main thread
        }).ContinueOnUIThread((r) =>
        {
            if (!(r.Result[0] == 0 && r.Result[3] == 0))//very probably not detected when x and rx are 0
            {
                Utils.UpdatePosition(r.Result[0], r.Result[1], r.Result[2]);
                Utils.UpdateRotation(r.Result[3], r.Result[4], r.Result[5]);
                Utils.PlaceArucoObject(markerCube, virtualCamera, translationMatrix);
            }
            currentNumberOfWorkingThreads--;
        });
    }
}

我的互操作功能如下:

C# 代码

[DllImport("ml_aruco_api")]
internal static extern void Detect(IntPtr yBuffer, IntPtr uBuffer, IntPtr vBuffer, int width, int height, ref float x, ref float y, ref float z, ref float rx, ref float ry, ref float rz);

最后,OpenCV C++端(缩短)

extern "C" void Detect(unsigned char* yBuffer, unsigned char* uBuffer, unsigned char* vBuffer, int width, int height, float& x, float& y, float& z, float& rx, float& ry, float& rz) {
    //(reconstruct image and detect markers on it...)

    if (detected) {
        x = m4.Tvec.at<float>(0, 0);
        y = m4.Tvec.at<float>(0, 1);
        z = m4.Tvec.at<float>(0, 2);
        rx = m4.Rvec.at<float>(0, 0);
        ry = m4.Rvec.at<float>(0, 1);
        rz = m4.Rvec.at<float>(0, 2);
    }
    else {
        x = y = z = rx = ry = rz = 0;
    }
}

这一切都工作了几秒钟,然后崩溃。而且它不是以 60fps 运行,而是在 15-30fps 左右剧烈波动。我不太了解 C# 和 C++ 之间的内存处理,所以这可能是这里的问题。我也不明白为什么应用程序应该在后台线程上运行时运行如此缓慢。我也尝试了 Unity 的工作系统,但无济于事,它工作时没有崩溃,但速度也很慢。

有人能指出我正确的方向吗?

编辑:我将最大线程数限制为 1,它停止了崩溃。FPS 现在大约 30-40,我想知道为什么它不是 60 fps。注释掉 Interop.Detect() 函数给我 60。我必须线程化 OpenCV 函数本身吗?

标签: c++multithreadingopencvunity3dbackground-thread

解决方案



推荐阅读