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



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

我在每秒执行 30 次的"相机帧可用"回调中执行此操作。我正在使用资源商店中的"任务并行"。

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);

最后,OpenCVC++侧(缩短)

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函数本身吗?

在 .net 中使用跨度和内存在托管或非托管之间共享数据

裁判:

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

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

最新更新