Обновление пикселей Texture2D из C ++ - PullRequest
0 голосов
/ 07 октября 2018

В проекте я использую сценарии Unity3D для C # и C ++ через DllImports.Моя цель состоит в том, чтобы на игровой сцене было 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 Texture

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();
    }
}

Отправить данные во внешнюю функцию C ++ с помощью DllImports и получить обработанныеданные с использованием 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.

Ошибка:

SetPixels32 вызывается с недопустимым количеством пикселей в массиве UnityEngine.Texture2D: SetPixels32 (Color32 []) Веб-камера: обновление () (в Assets / Scripts / Webcam.cs: 45)

Я не понимаю, почему недопустимое количество пикселей в массиве при вводе массива a в SetPixels32

Есть идеи?


ОБНОВЛЕНИЕ (10 октября2018)

Благодаря @Programmer, теперь он может работать с памятью контактов.

Кстати, я нахожу небольшую проблему который о Unity Engine.Когда камера Unity работает от 0 до 1 секунды, webCamTexture.width или webCamTexture.height всегда возвращают размер 16x16, даже если запрашивается большее изображение, такое как 1280x720, и затем через 1 секунду он вернет правильный размер. (возможно, несколько кадров) Итак, я ссылаюсь на этот post и задерживаюсь на 2 секунды для запуска Process() в Update() функции и сброса размера Texture2D в функции Process().Будет работать нормально:

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");
    }
    ...
}

1 Ответ

0 голосов
/ 07 октября 2018

C # не возвращает понять Color32 объект, который вы вернули из C ++.Это сработало бы, если бы вы сделали тип возвращаемого значения равным unsigned char*, затем используйте Marshal.Copy на стороне C #, чтобы скопировать возвращаемые данные в байтовый массив, а затем используйте 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);
}

Если вы не хотите использовать ключевые слова unsafe и fixed, вы также можете использовать GCHandle.Alloc длязакрепите массив перед отправкой на сторону C ++ с помощью GCHandle.AddrOfPinnedObject.См. этот пост о том, как это сделать.


Если вы получаете следующее исключение:

SetPixels32 вызван с недопустимым количеством пикселей вмассив UnityEngine.Texture2D: SetPixels32 (Color32 []) Веб-камера: обновление () (в разделе Активы / Сценарии / Веб-камера.cs: 45)

Это означает, что Texture2D вы звоните SetPixels32 on имеет другой размер или размер текстуры с текстурой WebCamTexture.Чтобы это исправить, перед вызовом SetPixels32 проверьте, изменился ли размер текстуры, затем измените размер целевой текстуры, чтобы она соответствовала WebCamTexture.

. Замените

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

на

*.1055 *
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...