HoloLens開發手記 - Unity之Locatable camera 使用相機


Enabling the capability for Photo Video Camera 啟用相機能力


 

為了使用攝像頭,我們必須啟用WebCam能力。

  1. 在Unity中打開Player settings
  2. 展開Windows Store標簽頁
  3. 在"Publishing Settings > Capabilities"部分勾選WebCam能力

 

同一時刻只能執行一次相機操作。為了識別當前相機處在哪種模式下(拍照還是視頻),你可以通過UnityEngine.VR.WSA.WebCam.Mode API檢查。

 

Photo Capture 捕獲照片


 

命名空間UnityEngine.VR.WSA.WebCam

類型PhotoCapture

 

PhotoCapture類允許我們使用相機拍攝靜態照片。正常的使用模式如下:

  1. 創建PhotoCapture對象
  2. 使用我們想要的設置來創建一個CameraParameters對象
  3. 調用StartPhotoModeAsync()方法開始拍照模式
  4. 拍攝想要的照片
    • (可選項)進一步處理捕獲的圖像
  5. 關閉拍照模式並釋放資源

Common Set Up for PhotoCapture 使用PhotoCapture的通用做法

對於任何拍照方式,開始步驟都是像下面這樣:

 

創建PhotoCapture對象

 

PhotoCapture photoCaptureObject = null;
   void Start()
   {
       PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated);
   }

 

存儲對象,配置拍攝參數並開始拍照模式

 

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

 

最后關閉相機時需要使用同樣的清理代碼

 

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

 

完成這些步驟后,你可以挑選使用哪種方式捕獲照片。

 

Capture a Photo to a File 捕獲照片到文件

 

最簡單的做法是直接將照片捕獲到文件。照片可以被存儲為PNG或JPG文件。

如果我們成功開始了拍照模式,需要拍照並將照片存儲到磁盤上,做法如下:

 

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

 

完成捕獲照片到文件的操作后,需要退出拍照模式並清理資源

 

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

 

Capture a Photo to a Texture2D 捕獲文件到Texture2D對象

 

我們可以把捕獲的照片保存為Texture2D對象,做法和保存到文件類似。步驟如下:

在OnPhotoModeStarted()方法中,捕獲一幀圖像到內存中。

 

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

 

我們需要把得到的結果賦給Texture2D對象,然后清理相機資源

 

void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
   {
       if (result.success)
       {
           // 使用正確分辨率創建Texture2D對象
           Resolution cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First();
           Texture2D targetTexture = new Texture2D(cameraResolution.width, cameraResolution.height);
           // 將圖像數據拷貝到Texture2D對象中
           photoCaptureFrame.UploadImageDataToTexture(targetTexture);
           // 進一步使用Texture2D對象,比如賦給材質神馬的
       }
       // 清理相機
       photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
   }

 

Capture a Photo and Interact with the Raw bytes 捕獲照片並和原始數據交互

為了在內存中操作圖像原始數據,需要的步驟和捕獲圖片到Texture2D類似,不同之處在於,OnCapturedPhotoToMemory()方法里可以獲得圖像原始數據並操作它們。

在本示例中,我們會創建一個List<Color>用來進一步處理或者直接通過SetPixels()方法來應用於Texture2D對象。

 

void OnCapturedPhotoToMemory(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame)
   {
       if (result.success)
       {
           List<byte> imageBufferList = new List<byte>();
           // 復制原始 IMFMediaBuffer 數據到空的list
           photoCaptureFrame.CopyRawImageDataIntoBuffer(imageBufferList);

           //本例使用 BGRA32 格式捕獲照片.
           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));
           }
           // 接下來可以把list用做進一步的處理

       }
       photoCaptureObject.StopPhotoModeAsync(OnStoppedPhotoMode);
   }

 

Video Capture 捕獲視頻


 

命名空間UnityEngine.VR.WSA.WebCam

類型VideoCapture

捕獲視頻的用法和捕獲照片類似,不同的地方在於你必須指定一個幀率(FPS)並且你只能以MP4格式把視頻直接存儲到磁盤上。步驟如下:

  1. 創建VideoCapture對象
  2. 使用我們想要的設置來創建一個CameraParameters對象
  3. 調用 StartVideoModeAsync()方法開始視頻捕獲模式
  4. 開始錄制視頻
  5. 停止錄制視頻
  6. 停止視頻捕獲模式並釋放相機資源

創建並配置VideoCapture對象

 

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

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

 

一旦配置完成VideoCapture對象,我們就開始錄制視頻

 

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

 

在開始錄制后,我們需要更新UI或者行為來確保可以停止視頻捕獲。在這里我們只輸出log。

 

void OnStartedRecordingVideo(VideoCapture.VideoCaptureResult result)
   {
       Debug.Log("Started Recording Video!");
       // 我們將會通過一些方式來停止視頻捕獲,比如計時器或者點擊手勢等等
   }

 

最后我們需要停止視頻捕獲,可以中國定時器或者其他輸入方式來實現。

 

   void StopRecordingVideo()
   {
       m_VideoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
   }

 

一旦視頻捕獲停止后,需要及時退出視頻捕獲模式並釋放相機資源。

 

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

 

Troubleshooting 問題診斷


  • 獲取不到分辨率

    • 確保你在項目中啟用了WebCam能力
  • 全息圖像不能捕獲到圖片或者視頻中
    • 未來的更新會支持捕獲全息圖像

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM