You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 12:36:04