Fotocamera video in Unity

Abilitazione della funzionalità per l'accesso alla fotocamera

La funzionalità "WebCam" deve essere dichiarata per consentire a un'app di usare la fotocamera.

  1. Nell'editor di Unity passare alle impostazioni del lettore passando alla pagina "Modifica > lettore impostazioni > progetto"
  2. Selezionare la scheda "Windows Store"
  3. Nella sezione "Funzionalità delle impostazioni > di pubblicazione" controllare le funzionalità WebCam e Microfono

Solo una singola operazione può verificarsi con la fotocamera alla volta. È possibile controllare la modalità in cui la fotocamera si trova attualmente in UnityEngine.XR.WSA.WebCam.Mode Unity 2018 e versioni precedenti o UnityEngine.Windows.WebCam.Mode in Unity 2019 e versioni successive. Le modalità disponibili sono foto, video o nessuno.

Acquisizione di foto

Spazio dei nomi (prima di Unity 2019): UnityEngine.XR.WSA.WebCam
Spazio dei nomi (Unity 2019 e versioni successive): UnityEngine.Windows.WebCam
Tipo: PhotoCapture

Il tipo PhotoCapture consente di scattare fotografie ancora con la fotocamera fotografica. Il modello generale per l'uso di PhotoCapture per scattare una foto è il seguente:

  1. Creare un oggetto PhotoCapture
  2. Creare un oggetto CameraParameters con le impostazioni desiderate
  3. Avviare la modalità foto tramite StartPhotoModeAsync
  4. Scatta la foto che vuoi
    • (facoltativo) Interagire con l'immagine
  5. Arrestare la modalità foto e pulire le risorse

Configurazione comune per PhotoCapture

Per tutti e tre gli usi, iniziare con gli stessi primi tre passaggi precedenti

Iniziare creando un oggetto PhotoCapture

private void Start()
{
    PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
}

Archiviare quindi l'oggetto, impostare i parametri e avviare la modalità foto

private PhotoCapture photoCaptureObject = null;

void OnPhotoCaptureCreated(PhotoCapture captureObject)
{
    photoCaptureObject = captureObject;

    Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();

    CameraParameters c = new CameraParameters();
    c.hologramOpacity = 0.0f;
    c.cameraResolutionWidth = cameraResolution.width;
    c.cameraResolutionHeight = cameraResolution.height;
    c.pixelFormat = CapturePixelFormat.BGRA32;

    captureObject.StartPhotoModeAsync(c, false, OnPhotoModeStarted);
}

Alla fine, si userà anche lo stesso codice di pulizia presentato qui

void OnStoppedPhotoMode(PhotoCapture.PhotoCaptureResult result)
{
    photoCaptureObject.Dispose();
    photoCaptureObject = null;
}

Dopo questi passaggi, puoi scegliere il tipo di foto da acquisire.

Acquisire una foto in un file

L'operazione più semplice consiste nell'acquisire una foto direttamente in un file. La foto può essere salvata come JPG o PNG.

Se la modalità foto è stata avviata correttamente, scattare una foto e archiviarla su disco

private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
    if (result.success)
    {
        string filename = string.Format(@"CapturedImage{0}_n.jpg", Time.time);
        string filePath = System.IO.Path.Combine(Application.persistentDataPath, filename);

        photoCaptureObject.TakePhotoAsync(filePath, PhotoCaptureFileOutputFormat.JPG, OnCapturedPhotoToDisk);
    }
    else
    {
        Debug.LogError("Unable to start photo mode!");
    }
}

Dopo aver acquisito la foto su disco, uscire dalla modalità foto e quindi pulire gli oggetti

void OnCapturedPhotoToDisk(PhotoCapture.PhotoCaptureResult result)
{
    if (result.success)
    {
        Debug.Log("Saved Photo to disk!");
        photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
    }
    else
    {
        Debug.Log("Failed to save Photo to disk");
    }
}

Acquisire una foto in un oggetto Texture2D con la posizione

Quando si acquisisce dati in un oggetto Texture2D, il processo è simile all'acquisizione su disco.

Seguire il processo di installazione precedente.

In OnPhotoModeStarted acquisire un frame in memoria.

private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result)
{
    if (result.success)
    {
        photoCaptureObject.TakePhotoAsync(OnCapturedPhotoToMemory);
    }
    else
    {
        Debug.LogError("Unable to start photo mode!");
    }
}

Si applicherà quindi il risultato a una trama e si userà il codice di pulizia comune precedente.

void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
    if (result.success)
    {
        // Create our Texture2D for use and set the correct resolution
        Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
        Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
        // Copy the raw image data into our target texture
        photoCaptureFrame.UploadImageDataToTexture(targetTexture);
        // Do as we wish with the texture such as apply it to a material, etc.
    }
    // Clean up
    photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}

Fotocamera individuabile

Per posizionare questa trama nella scena e visualizzarla usando le matrici di fotocamere locabili, aggiungere il codice seguente a OnCapturedPhotoToMemory nel result.success controllo:

if (photoCaptureFrame.hasLocationData)
{
    photoCaptureFrame.TryGetCameraToWorldMatrix(out Matrix4x4 cameraToWorldMatrix);

    Vector3 position = cameraToWorldMatrix.GetColumn(3) - cameraToWorldMatrix.GetColumn(2);
    Quaternion rotation = Quaternion.LookRotation(-cameraToWorldMatrix.GetColumn(2), cameraToWorldMatrix.GetColumn(1));

    photoCaptureFrame.TryGetProjectionMatrix(Camera.main.nearClipPlane, Camera.main.farClipPlane, out Matrix4x4 projectionMatrix);
}

Unity ha fornito codice di esempio per l'applicazione della matrice di proiezione a uno shader specifico nei forum.

Acquisire una foto e interagire con i byte non elaborati

Per interagire con i byte non elaborati di un frame di memoria, seguire la stessa procedura di configurazione descritta in precedenza e OnPhotoModeStarted come nell'acquisizione di una foto in un oggetto Texture2D. La differenza è in OnCapturedPhotoToMemory in cui è possibile ottenere i byte non elaborati e interagire con essi.

In questo esempio si creerà un elenco da elaborare ulteriormente o applicare a una trama tramite SetPixels()

void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
{
    if (result.success)
    {
        List<byte> imageBufferList = new List<byte>();
        // Copy the raw IMFMediaBuffer data into our empty byte list.
        photoCaptureFrame.CopyRawImageDataIntoBuffer(imageBufferList);

        // In this example, we captured the image using the BGRA32 format.
        // So our stride will be 4 since we have a byte for each rgba channel.
        // The raw image data will also be flipped so we access our pixel data
        // in the reverse order.
        int stride = 4;
        float denominator = 1.0f / 255.0f;
        List<Color> colorArray = new List<Color>();
        for (int i = imageBufferList.Count - 1; i >= 0; i -= stride)
        {
            float a = (int)(imageBufferList[i - 0]) * denominator;
            float r = (int)(imageBufferList[i - 1]) * denominator;
            float g = (int)(imageBufferList[i - 2]) * denominator;
            float b = (int)(imageBufferList[i - 3]) * denominator;

            colorArray.Add(new Color(r, g, b, a));
        }
        // Now we could do something with the array such as texture.SetPixels() or run image processing on the list
    }
    photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
}

Acquisizione video

Spazio dei nomi (prima di Unity 2019): UnityEngine.XR.WSA.WebCam
Spazio dei nomi (Unity 2019 e versioni successive): UnityEngine.Windows.WebCam
Tipo: VideoCapture

Funzioni VideoCapture in modo analogo a PhotoCapture. Le uniche due differenze sono che è necessario specificare un valore Frame al secondo (FPS) e si può salvare direttamente su disco come file .mp4. I passaggi per usare VideoCapture sono i seguenti:

  1. Creare un oggetto VideoCapture
  2. Creare un oggetto CameraParameters con le impostazioni desiderate
  3. Avviare la modalità video tramite StartVideoModeAsync
  4. Avviare la registrazione del video
  5. Interrompi registrazione video
  6. Arrestare la modalità video e pulire le risorse

Per iniziare, creare l'oggetto VideoCapture VideoCapture m_VideoCapture = null;

void Start ()
{
    VideoCapture.CreateAsync(false, OnVideoCaptureCreated);
}

Configurare quindi i parametri desiderati per la registrazione e l'avvio.

void OnVideoCaptureCreated(VideoCapture videoCapture)
{
    if (videoCapture != null)
    {
        m_VideoCapture = videoCapture;

        Resolution cameraResolution = VideoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
        float cameraFramerate = VideoCapture.GetSupportedFrameRatesForResolution(cameraResolution).OrderByDescending((fps) => fps).First();

        CameraParameters cameraParameters = new CameraParameters();
        cameraParameters.hologramOpacity = 0.0f;
        cameraParameters.frameRate = cameraFramerate;
        cameraParameters.cameraResolutionWidth = cameraResolution.width;
        cameraParameters.cameraResolutionHeight = cameraResolution.height;
        cameraParameters.pixelFormat = CapturePixelFormat.BGRA32;

        m_VideoCapture.StartVideoModeAsync(cameraParameters,
                                            VideoCapture.AudioState.None,
                                            OnStartedVideoCaptureMode);
    }
    else
    {
        Debug.LogError("Failed to create VideoCapture Instance!");
    }
}

Una volta avviata, iniziare la registrazione

void OnStartedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
{
    if (result.success)
    {
        string filename = string.Format("MyVideo_{0}.mp4", Time.time);
        string filepath = System.IO.Path.Combine(Application.persistentDataPath, filename);

        m_VideoCapture.StartRecordingAsync(filepath, OnStartedRecordingVideo);
    }
}

Dopo l'avvio della registrazione, è possibile aggiornare l'interfaccia utente o i comportamenti per abilitare l'arresto. Qui è sufficiente registrare.

void OnStartedRecordingVideo(VideoCapture.VideoCaptureResult result)
{
    Debug.Log("Started Recording Video!");
    // We will stop the video from recording via other input such as a timer or a tap, etc.
}

In un secondo momento, si vuole arrestare la registrazione usando un timer o un input dell'utente, ad esempio.

// The user has indicated to stop recording
void StopRecordingVideo()
{
    m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
}

Una volta arrestata la registrazione, arrestare la modalità video e pulire le risorse.

void OnStoppedRecordingVideo(VideoCapture.VideoCaptureResult result)
{
    Debug.Log("Stopped Recording Video!");
    m_VideoCapture.StopVideoModeAsync(OnStoppedVideoCaptureMode);
}

void OnStoppedVideoCaptureMode(VideoCapture.VideoCaptureResult result)
{
    m_VideoCapture.Dispose();
    m_VideoCapture = null;
}

Risoluzione dei problemi

  • Non sono disponibili risoluzioni
    • Verificare che la funzionalità WebCam sia specificata nel progetto.

Successivo checkpoint di sviluppo

Se si sta seguendo il percorso di checkpoint per lo sviluppo di Unity, si stanno esplorando le funzionalità e le API della piattaforma Realtà mista. Da qui, è possibile passare all'argomento successivo:

In alternativa, passare direttamente alla distribuzione dell'app in un dispositivo o emulatore:

È sempre possibile tornare ai checkpoint per lo sviluppo con Unity in qualsiasi momento.

Vedi anche