在 Android 上使用 OpenCV 和 Unity

Using OpenCV with Unity on Android

本文关键字:OpenCV Unity Android      更新时间:2023-10-16

我在Android上使用OpenCV和Unity时遇到问题。我使用OpenCV库本机c ++插件(.so文件(我想检测魔方和立方体的颜色。

因此,我将数据从Unity的网络摄像头纹理传递给OpenCV。当网络摄像头纹理的宽度和高度较小(320x240(时,它很好用。但是当网络摄像头纹理的宽度和高度很大(480x640(时,它会遇到问题。当网络摄像头纹理的分辨率设置为全屏时(在本例中我设置为 800x1280(,应用程序将停止。

我尝试调试。当我使用Marshal.Copy函数将数据从OpenCV复制到Unity时,它停止了。我该如何解决这个问题?

在此处输入图像描述

(分辨率为320x240(

[案例1(分辨率为 320x240(]

using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System;
public class Controller : MonoBehaviour {
public float RotateSpeed = 0.5f;
public RawImage InImage;
public RawImage OutImage;
WebCamTexture wct;
Texture2D outTexture;
void Awake()
{
#if UNITY_EDITOR
int width = 1280;
int height = 720;
#else
int width = 320;
int height = 240;
#endif
NativeLibAdapter.InitCV(width, height);
outTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
wct = new WebCamTexture(width, height);
wct.Play();
// Ignore it.
Debug.LogWarning("Foo Value in C++ is " + NativeLibAdapter.FooTest());
}
void Update()
{
if (wct.width > 100 && wct.height > 100)
{
Color32[] pixels = wct.GetPixels32();
GCHandle pixelHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
IntPtr results = NativeLibAdapter.SubmitFrame(wct.width, wct.height, pixelHandle.AddrOfPinnedObject());
int bufferSize = wct.width * wct.height * 4;
byte[] rawData = new byte[bufferSize];
if (results != IntPtr.Zero)
{
Marshal.Copy(results, rawData, 0, bufferSize);
outTexture.LoadRawTextureData(rawData);
outTexture.Apply();
}
OutImage.texture = outTexture;
rawData = null;
pixelHandle.Free();
}
}
}

在此处输入图像描述 (其分辨率为 480x640。有很多噪音。

[案例2(分辨率为 480x640(]

using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System;
public class Controller : MonoBehaviour {
public float RotateSpeed = 0.5f;
public RawImage InImage;
public RawImage OutImage;
WebCamTexture wct;
Texture2D outTexture;
void Awake()
{
#if UNITY_EDITOR
int width = 1280;
int height = 720;
#else
int width = 480;
int height = 640;
#endif
NativeLibAdapter.InitCV(width, height);
outTexture = new Texture2D(width, height, TextureFormat.RGBA32, false);
wct = new WebCamTexture(width, height);
wct.Play();
// Ignore it.
Debug.LogWarning("Foo Value in C++ is " + NativeLibAdapter.FooTest());
}
void Update()
{
if (wct.width > 100 && wct.height > 100)
{
Color32[] pixels = wct.GetPixels32();
GCHandle pixelHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
IntPtr results = NativeLibAdapter.SubmitFrame(wct.width, wct.height, pixelHandle.AddrOfPinnedObject());
int bufferSize = wct.width * wct.height * 4;
byte[] rawData = new byte[bufferSize];
if (results != IntPtr.Zero)
{
Marshal.Copy(results, rawData, 0, bufferSize);
outTexture.LoadRawTextureData(rawData);
outTexture.Apply();
}
OutImage.texture = outTexture;
rawData = null;
pixelHandle.Free();
}
}
}

它只是改变宽度和高度变量。

[情况3(设备上的分辨率为全屏(]

using UnityEngine;
using UnityEngine.UI;
using System.Runtime.InteropServices;
using System;
public class Controller : MonoBehaviour {
public float RotateSpeed = 0.5f;
public RawImage InImage;
public RawImage OutImage;
WebCamTexture wct;
Texture2D outTexture;
void Awake()
{
#if UNITY_EDITOR
int width = 1280;
int height = 720;
#else
int width = 480;
int height = 640;
#endif
NativeLibAdapter.InitCV(Screen.width, Screen.height);
outTexture = new Texture2D(Screen.width, Screen.height, TextureFormat.RGBA32, false);
wct = new WebCamTexture(Screen.width, Screen.height);
wct.Play();
// Ignore it.
Debug.LogWarning("Foo Value in C++ is " + NativeLibAdapter.FooTest());
}
void Update()
{
if (wct.width > 100 && wct.height > 100)
{
Color32[] pixels = wct.GetPixels32();
GCHandle pixelHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
IntPtr results = NativeLibAdapter.SubmitFrame(wct.width, wct.height, pixelHandle.AddrOfPinnedObject());
int bufferSize = wct.width * wct.height * 4;
byte[] rawData = new byte[bufferSize];
if (results != IntPtr.Zero)
{
// here! App stops. I don't know why App stops.
Marshal.Copy(results, rawData, 0, bufferSize);
outTexture.LoadRawTextureData(rawData);
outTexture.Apply();
}
OutImage.texture = outTexture;
rawData = null;
pixelHandle.Free();
}
}
}

我正在使用:

  • 集成开发地址
  • 团结 2018.1.19f
  • 安卓工作室 3.4.2
  • OpenCV 3.4.3

您有以下代码初始化 CV 缓冲区:

#if UNITY_EDITOR
int width = 1280;
int height = 720;
#else
int width = 480;
int height = 640;
#endif
NativeLibAdapter.InitCV(Screen.width, Screen.height);

CV 缓冲区的初始化不足以处理 800x1280,因此内存可能不足。预计性能会随着大小的增加而下降,因为内存消耗更大(640x480 是 320x240 的 4 倍数据,因此每帧的垃圾收集和数据处理要多得多(。在将数据输入 CV 之前,您需要增加宽度和高度以包含最大分辨率,或限制从 GetPixels(( 检索的像素。