unity在C++中使用后台线程进行图像处理导致崩溃

Using background threads for image processing in C++ in unity leads to a crash

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

我在每秒执行 30 次的 "camera frame available" 回调中执行此操作。我正在使用资产商店的 "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--;
        });
    }
}

我的Interop函数如下:

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的job系统我也试过了,没用,虽然没有崩溃,但是也很慢。

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

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

在 .net 中使用 Span 和 Memory 在托管或非托管之间共享数据

参考:

https://docs.microsoft.com/en-us/dotnet/standard/memory-and-spans/memory-t-usage-guidelines

https://medium.com/@antao.almada/p-invoking-using-span-t-a398b86f95d3