Fotocamera video foto in Unity

Abilitazione della funzionalità per l'accesso alla fotocamera

La funzionalità "WebCam" deve essere dichiarata per un'app per l'uso della fotocamera.

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

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

Acquisizione foto

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

Il tipo PhotoCapture consente di scattare ancora fotografie 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. Scattare la foto desiderata
    • (facoltativo) Interagire con tale 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, è possibile scegliere quale tipo di foto 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 UN PNG.

Se è stata avviata la modalità foto, 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 una Trama2D con la posizione

Quando si acquisiscono 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 della fotocamera locatable, 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 applicare la 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 precedente e OnPhotoModeStarted come nell'acquisizione di una foto in una Trama2D. La differenza è in OnCapturedPhotoToMemory in cui è possibile ottenere i byte non elaborati e interagire con loro.

In questo esempio si creerà un elenco per essere ulteriormente elaborato o applicato 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 analogamente a PhotoCapture. Le uniche due differenze sono che è necessario specificare un valore Frame al secondo (FPS) e è possibile salvare direttamente sul disco come file .mp4. I passaggi per l'uso di 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 video
  5. Arrestare la registrazione video
  6. Arrestare la modalità video e pulire le risorse

Iniziare creando l'oggetto VideoCapture m_VideoCapture = null;

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

Configurare quindi i parametri che si desidera 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!");
    }
}

Dopo l'avvio, 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 utente, ad esempio.

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

Dopo aver arrestato 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 del checkpoint di sviluppo di Unity, si è in corso l'esplorazione delle funzionalità e delle API della piattaforma di 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.

Vedere anche