saki4510t / UVC4UnityAndroid

UVC4UnityAndroid
Apache License 2.0
77 stars 19 forks source link

Pixel data in camera stream is blank #12

Closed Uralstech closed 8 months ago

Uralstech commented 8 months ago

Hi!

Thank you for this great plugin! This was just what I was looking for.

Environment

Issue

I have a simple script which uses the USB camera footage and converts it from ARGB32 to RGBA32. It was not working, so while debugging, I decided to try saving the copied frame to local storage. When I check the storage all I find is a blank, greyish translucent image.

The peculiar part is that in my preview RawImage, (_cameraPreviewImage), the Texture appears fine! In a different test, I also tried displaying the copied frame (_webCamTextureCopy), which also displayed fine!

Code

using UnityEngine;
using Serenegiant.UVC;
using UnityEngine.UI;
using System.IO;

public class FaceDetectionManager : MonoBehaviour, IUVCDrawer
{
    [SerializeField] private RawImage _cameraPreviewImage;
    [SerializeField] private RawImage _cameraTextureCopyPreviewImage;
    private Texture2D _webCamTexture = null;
    private Texture2D _webCamTextureCopy = null;
    private Texture2D _webCamTextureCorrected = null;

    public void WhenTheButtonHasBeenClicked()
    {
        if (_webCamTexture != null)
        {
            Graphics.CopyTexture(_webCamTexture, _webCamTextureCopy);
            File.WriteAllBytes(Path.Join(Application.persistentDataPath, "test.png"), _webCamTextureCopy.EncodeToPNG());

            Color[] pixels = _webCamTextureCopy.GetPixels();

            _webCamTextureCorrected.SetPixels(pixels);
            _webCamTextureCorrected.Apply();

            _cameraTextureCopyPreviewImage.texture = _webCamTextureCorrected;
        }
        else
        {
            Debug.LogError("Webcam texture is null!");
        }
    }

    public bool CanDraw(UVCManager manager, UVCDevice device)
    {
        Debug.Log($"UVC CanDraw called! Device: {device.name}.");
        return true;
    }

    public bool OnUVCAttachEvent(UVCManager manager, UVCDevice device)
    {
        Debug.Log($"UVC AttachEvent called! Device: {device.name}.");
        return true;
    }

    public void OnUVCDetachEvent(UVCManager manager, UVCDevice device)
    {
        Debug.Log($"UVC DetachEvent called! Device: {device.name}.");
    }

    public void OnUVCStartEvent(UVCManager manager, UVCDevice device, Texture2D tex)
    {
        Debug.Log($"UVC StartEvent called! Device: {device.name}.");

        _webCamTexture = tex;
        _webCamTextureCopy = new Texture2D(_webCamTexture.width, _webCamTexture.height, TextureFormat.ARGB32, false);
        _webCamTextureCorrected = new Texture2D(_webCamTexture.width, _webCamTexture.height, TextureFormat.RGBA32, false);

        _cameraPreviewImage.texture = _webCamTexture;
    }

    public void OnUVCStopEvent(UVCManager manager, UVCDevice device)
    {
        Debug.Log($"UVC StopEvent called! Device: {device.name}.");
        _webCamTexture = null;
    }
}
Uralstech commented 8 months ago

Update

I have fixed this issue using a RenderTexture:


// Get a temporary RenderTexture
RenderTexture rt = RenderTexture.GetTemporary(_webCamTexture.width, _webCamTexture.height, 0, RenderTextureFormat.ARGB32);

// Copy _webCamTexture to rt
Graphics.Blit(_webCamTexture, rt);

// Set the active RenderTexture to rt
RenderTexture.active = rt;

// Create a new Texture2D in ARGB32 format
Texture2D newTexture = new Texture2D(_webCamTexture.width, _webCamTexture.height, TextureFormat.ARGB32, false);
// Read the pixels from the RenderTexture and apply
newTexture.ReadPixels(new Rect(0, 0, _webCamTexture.width, _webCamTexture.height), 0, 0);
newTexture.Apply();

// Reset the active RenderTexture
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(rt);