Fotovideokamera i Unity

Aktivera funktionen för kameraåtkomst

Funktionen "WebCam" måste deklareras för att en app ska kunna använda kameran.

  1. Gå till spelarinställningarna i Unity-redigeraren genom att gå till sidan "Redigera > Project Inställningar > Player"
  2. Välj fliken "Windows Store"
  3. I avsnittet "Inställningar > funktioner" kontrollerar du funktionerna WebCam och Microphone

Endast en enda åtgärd kan ske med kameran i taget. Du kan kontrollera vilket läge kameran för närvarande är i i Unity 2018 och tidigare eller UnityEngine.XR.WSA.WebCam.Mode UnityEngine.Windows.WebCam.Mode i Unity 2019 och senare. Tillgängliga lägen är foto, video eller inget.

Fotoinspelning

Namnområde (före Unity 2019): UnityEngine.XR.WSA.WebCam
Namnområde (Unity 2019 och senare): UnityEngine.Windows. WebCam
Typ: PhotoCapture

Med PhotoCapture-typen kan du ta fortfarande fotografier med fotovideokameran. Det allmänna mönstret för att använda PhotoCapture för att ta ett foto är följande:

  1. Skapa ett PhotoCapture-objekt
  2. Skapa ett CameraParameters-objekt med de inställningar du vill ha
  3. Starta fotoläge via StartPhotoModeAsync
  4. Ta det foto du vill ha
    • (valfritt) Interagera med den bilden
  5. Stoppa fotoläge och rensa resurser

Vanlig set-up för PhotoCapture

För alla tre användningsområden börjar du med samma tre första steg ovan

Börja med att skapa ett PhotoCapture-objekt

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

Lagra sedan objektet, ange parametrarna och starta Fotoläge

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

I slutändan använder du också samma rensningskod som visas här

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

Efter de här stegen kan du välja vilken typ av foto som ska tas.

Ta ett foto i en fil

Den enklaste åtgärden är att ta ett foto direkt till en fil. Fotot kan sparas som en JPG- eller PNG-fil.

Om du har startat fotoläget tar du ett foto och lagrar det på disk

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

När du har tagit fotot till disken avslutar du fotoläget och rensar sedan objekten

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

Ta ett foto till en Texture2D med plats

När du samlar in data till en Texture2D liknar processen att samla in till disk.

Följ konfigurationsprocessen ovan.

I OnPhotoModeStarted avbildar du en ram till minnet.

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

Sedan tillämpar du resultatet på en struktur och använder den vanliga rensningskoden ovan.

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

Inaktuell kamera

Lägg till följande kod i OnCapturedPhotoToMemory i kontrollen för att placera den här strukturen i scenen och visa den med hjälp av de oskadliga kameramatriserna: result.success

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 har angett exempelkod för att tillämpa projektionsmatrisen på en specifik skuggare på sina forum.

Ta ett foto och interagera med byte i rådata

Om du vill interagera med rådatabyte för en i minnesramen följer du samma installationssteg som ovan och OnPhotoModeStarted som vid insamling av ett foto till en Texture2D. Skillnaden är OnCapturedPhotoToMemory där du kan hämta rådata byte och interagera med dem.

I det här exemplet skapar du en lista som ska bearbetas ytterligare eller tillämpas på en struktur via 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);
}

Videoinspelning

Namnområde (före Unity 2019): UnityEngine.XR.WSA.WebCam
Namnområde (Unity 2019 och senare): UnityEngine.Windows. WebCam
Typ: VideoCapture

VideoCapture fungerar på samma sätt som PhotoCapture. De enda två skillnaderna är att du måste ange ett VÄRDE för bildrutor per sekund (FP) och du kan bara spara direkt till disk som en .mp4 fil. Stegen för att använda VideoCapture är följande:

  1. Skapa ett VideoCapture-objekt
  2. Skapa ett CameraParameters-objekt med de inställningar du vill ha
  3. Starta videoläge via StartVideoModeAsync
  4. Starta inspelning av video
  5. Stoppa inspelning av video
  6. Stoppa videoläge och rensa resurser

Börja med att skapa VideoCapture-objektet VideoCapture m_VideoCapture = null;

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

Konfigurera sedan de parametrar som du vill använda för inspelningen och starta.

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

Starta inspelningen när du har startat

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

När inspelningen har startat kan du uppdatera användargränssnittet eller beteendet för att aktivera stopp. Här loggar du bara.

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.
}

Vid ett senare tillfälle vill du till exempel stoppa inspelningen med hjälp av en timer eller användarindata.

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

När inspelningen har stoppats stoppar du videoläget och rensar dina resurser.

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

Felsökning

  • Inga lösningar är tillgängliga
    • Kontrollera att WebCam-funktionen har angetts i projektet.

Nästa kontrollpunkt för utveckling

Om du följer utvecklingskontrollen i Unity som vi har tagit fram är du inte ute efter att utforska de Mixed Reality plattformsfunktionerna och API:erna. Härifrån kan du fortsätta till nästa avsnitt:

Eller gå direkt till att distribuera din app på en enhet eller emulator:

Du kan alltid gå tillbaka till kontrollpunkterna för Unity-utveckling när som helst.

Se även