繁体   English   中英

从C ++更新Texture2D像素

[英]Update Texture2D pixels from C++

在项目中,我正在通过DllImports使用Unity3D的C#脚本和C ++。 我的目标是游戏场景具有2个多维数据集(Cube & Cube2) ,其中一个多维数据集纹理通过我的便携式摄像机和Unity的webCamTexture.Play()展示实时视频,另一个多维数据集纹理通过外部C ++函数显示处理后的视频ProcessImage()

代码上下文:

在C ++中,我定义为

struct Color32
{
    unsigned char r;
    unsigned char g;
    unsigned char b;
    unsigned char a;
};

而功能是

extern "C"
{
    Color32* ProcessImage(Color32* raw, int width, int height);
}
...

Color32* ProcessImage(Color32* raw, int width, int height)
{
    for(int i=0; i<width*height ;i++)
    {
       raw[i].r = raw[i].r-2;
       raw[i].g = raw[i].g-2;
       raw[i].b = raw[i].b-2;
       raw[i].a = raw[i].a-2;
    }
    return raw;
}

C#:

声明和导入

public GameObject cube; 
public GameObject cube2;
private Texture2D tx2D;
private WebCamTexture webCamTexture;

[DllImport("test22")]   /*the name of Plugin is test22*/
private static extern Color32[] ProcessImage(Color32[] rawImg, 
                                                 int width, int height);

获取摄像头情况并设置cube1,cube2纹理

void Start()
{
    WebCamDevice[] wcd = WebCamTexture.devices;

    if(wcd.Length==0)
    {
        print("Cannot find a camera");
        Application.Quit();
    }
    else
    {
        webCamTexture = new WebCamTexture(wcd[0].name);
        cube.GetComponent<Renderer>().material.mainTexture = webCamTexture;

        tx2D = new Texture2D(webCamTexture.width, webCamTexture.height);
        cube2.GetComponent<Renderer>().material.mainTexture = tx2D;

        webCamTexture.Play();
    }
}

通过DllImports将数据发送到外部C ++函数,并使用Color32[] a接收处理后的数据。 最后,我使用Unity的SetPixels32设置tx2D (Cube2)纹理:

void Update()
{
    Color32[] rawImg = webCamTexture.GetPixels32();
    System.Array.Reverse(rawImg);

    Debug.Log("Test1");
    Color32[] a = ProcessImage(rawImg, webCamTexture.width, webCamTexture.height);
    Debug.Log("Test2");

    tx2D.SetPixels32(a);
    tx2D.Apply();
}

结果:

结果只是多维数据集1的纹理显示了实时视频,而无法显示使用多维数据集2的纹理处理的数据。

错误:

在数组UnityEngine.Texture2D:SetPixels32(Color32 [])Webcam:Update()中调用了无效像素数的SetPixels32(位于Assets / Scripts / Webcam.cs:45)

我不明白为什么在将数组a输入到SetPixels32时为什么数组中的像素数无效

有任何想法吗?


更新 (2018年10月10日)

感谢@Programmer,现在它可以通过引脚存储工作。

顺便说一句,我发现一些关于Unity Engine的小问题 当Unity Camera在0到1秒之间运行时,即使要求更大的图像(例如1280x720), webCamTexture.widthwebCamTexture.height始终返回16x16大小,然后它将在1秒后返回正确的大小。 (可能是几帧)因此,我引用了这篇文章,并延迟了2秒钟,以便在Update()函数中运行Process()并在Process()函数中重置Texture2D大小。 它将正常工作:

delaytime = 0;
void Update()
{
    delaytime = delaytime + Time.deltaTime;
    Debug.Log(webCamTexture.width);
    Debug.Log(webCamTexture.height);

    if (delaytime >= 2f)
        Process();
}
unsafe void Process()
{
    ...

    if ((Test.width != webCamTexture.width) || Test.height != webCamTexture.height)
    {
       Test = new Texture2D(webCamTexture.width, webCamTexture.height, TextureFormat.ARGB32, false, false);
       cube2.GetComponent<Renderer>().material.mainTexture = Test;
       Debug.Log("Fixed Texture dimension");
    }
    ...
}

C#不会返回您从C ++返回的Color32对象。 如果您将返回类型设置为unsigned char*然后在C#端使用Marshal.Copy将返回的数据复制到字节数组中,然后使用Texture2D.LoadRawTextureData将数组加载到Texture2D.LoadRawTextureData ,这将是Texture2D 是一个从C#返回字节数组的示例。


我不建议您返回数据,因为这很昂贵。 填充要传递给函数的数组,然后只需将该数组重新分配给Texture2D

C ++:

extern "C"
{
    void ProcessImage(unsigned char* raw, int width, int height);
}
...

void ProcessImage(unsigned char* raw, int width, int height)
{
    for(int y=0; y < height; y++)
    {
        for(int x=0; x < width; x++)
        {
            unsigned char* pixel = raw + (y * width * 4 + x * 4);
            pixel[0] = pixel[0]-(unsigned char)2; //R
            pixel[1] = pixel[1]-(unsigned char)2; //G
            pixel[2] = pixel[2]-(unsigned char)2; //B
            pixel[3] = pixel[3]-(unsigned char)2; //Alpha
        }
    }
}

C#:

[DllImport("test22")]
private static extern void ProcessImage(IntPtr texData, int width, int height);

unsafe void ProcessImage(Texture2D texData)
{
    Color32[] texDataColor = texData.GetPixels32();
    System.Array.Reverse(texDataColor);

    //Pin Memory
    fixed (Color32* p = texDataColor)
    {
        ProcessImage((IntPtr)p, texData.width, texData.height);
    }
    //Update the Texture2D with array updated in C++
    texData.SetPixels32(texDataColor);
    texData.Apply();
}

使用方法:

public Texture2D tex;

void Update()
{
    ProcessImage(tex);
}

如果你不想使用unsafefixed关键字,你也可以使用GCHandle.Alloc它发送到C ++侧前针阵列GCHandle.AddrOfPinnedObject 请参阅这篇文章,了解如何执行此操作。


如果您遇到以下异常:

在数组UnityEngine.Texture2D:SetPixels32(Color32 [])Webcam:Update()中调用了无效像素数的SetPixels32(位于Assets / Scripts / Webcam.cs:45)

这意味着您要调用SetPixels32Texture2DWebCamTexture纹理具有不同的大小或纹理尺寸。 要解决此问题,请在调用SetPixels32之前,检查纹理尺寸是否已更改,然后调整目标纹理的大小以与WebCamTexture匹配。

更换

tx2D.SetPixels32(rawImg);
tx2D.Apply();

//Fix texture dimension if it doesn't match with the web cam texture size
if ((tx2D.width != webCamTexture.width) || tx2D.height != webCamTexture.height)
{
    tx2D = new Texture2D(webCamTexture.width, webCamTexture.height, TextureFormat.RGBA32, false, false);
    Debug.Log("Fixed Texture dimension");
}

tx2D.SetPixels32(rawImg);
tx2D.Apply();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM