Unity调用OpenCV C++ VideoCapture更新Texture2D后SpriteRenderer显示异常
问题根因
- OpenCV侧VideoCapture默认输出BGR三通道格式的帧,你直接写入RGBA四通道的Mat结构,内存数据长度不匹配,导致出现条纹、画面重复问题
- C#侧设置的纹理分辨率为640x240,和OpenCV默认输出的640x480摄像头分辨率不匹配,画面被挤压错位
- C#侧只在初始化阶段执行一次帧读取,无法实时更新画面,且提前释放了固定内存句柄,会引发后续内存访问异常
修复方案
C++端修改
首先在初始化阶段固定摄像头输出分辨率,和C#端保持一致;帧读取完成后先做通道转换,再写入传入的内存地址,去掉冗余的memcpy操作。
extern "C" void __declspec(dllexport) Init() { _capture.open(0); // 固定输出分辨率,需和C#端配置完全一致 _capture.set(CAP_PROP_FRAME_WIDTH, 640); _capture.set(CAP_PROP_FRAME_HEIGHT, 480); } extern "C" void __declspec(dllexport) NDVIStreamer(unsigned char* data, int width, int height) { Mat tempFrame; // 读取摄像头原生BGR三通道帧 _capture >> tempFrame; // 绑定输出内存为RGBA四通道格式 Mat _currentFrame(height, width, CV_8UC4, data); // BGR转RGBA,直接写入传入的内存地址 cvtColor(tempFrame, _currentFrame, COLOR_BGR2RGBA); imshow("lennart", tempFrame); }
C#端修改
修正纹理分辨率,将帧更新逻辑放到每帧执行的Update方法中,内存句柄等到组件销毁时再释放。
[RequireComponent(typeof(SpriteRenderer))] public class SpriteMaker : MonoBehaviour { SpriteRenderer rend; [DllImport("NDVIstreamer_dll2")] private static extern void NDVIStreamer(IntPtr data, int width, int height); [DllImport("NDVIstreamer_dll2")] private static extern void Init(); private Texture2D tex; private Color32[] pixel32; private GCHandle pixelHandle; private IntPtr pixelPtr; // 固定分辨率,需和C++端配置完全一致 private const int FrameWidth = 640; private const int FrameHeight = 480; void Start() { rend = GetComponent<SpriteRenderer>(); // 初始化匹配分辨率的纹理 tex = new Texture2D(FrameWidth, FrameHeight, TextureFormat.RGBA32, false); pixel32 = tex.GetPixels32(); // 固定像素数组内存地址,避免GC移动 pixelHandle = GCHandle.Alloc(pixel32, GCHandleType.Pinned); pixelPtr = pixelHandle.AddrOfPinnedObject(); Init(); // 创建渲染用Sprite Sprite newSprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.one * 0.5f); rend.sprite = newSprite; } // 每帧更新视频帧 void Update() { MatToTexture2D(); } void MatToTexture2D() { NDVIStreamer(pixelPtr, FrameWidth, FrameHeight); tex.SetPixels32(pixel32); tex.Apply(); } // 组件销毁时释放固定的内存句柄 void OnDestroy() { if (pixelHandle.IsAllocated) { pixelHandle.Free(); } } }
内容的提问来源于stack exchange,提问作者Lennart
相关产品推荐
相关产品推荐

