c++ - 在 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 函数本身吗?
解决方案
使用 .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
推荐阅读
- javascript - 如何使用 javascript/jquery 在 fa、far、fad 或 fas of font-awesome 之间更改/切换
- amazon-web-services - 如何在 Fluentd 中按命名空间过滤
- c# - 将 POCO / Entity 添加到 DbContext 以进行自定义查询 / 过程,而无需先在实体框架代码中创建表
- django - 找不到页面 (404) 请求方法:POST 请求 URL:http://127.0.0.1:8000/reg_done
- python - 如何在if语句python中停止两个函数同时运行
- android-studio - 无法在颤振依赖中安装 engish_words
- python - Django 中的 Forloop.counter
- php - Adlap2 - 更新“批量修改:访问不足”
- sql - 将不同格式列的String数据类型的日期转换为PostgreSQL中的日期数据类型
- flutter - 是否可以在颤振应用程序中嵌入离子应用程序?