Enabling the capability for Photo Video Camera 啟用相機能力
為了使用攝像頭,我們必須啟用WebCam能力。
- 在Unity中打開Player settings
- 展開Windows Store標簽頁
- 在"Publishing Settings > Capabilities"部分勾選WebCam能力
同一時刻只能執行一次相機操作。為了識別當前相機處在哪種模式下(拍照還是視頻),你可以通過UnityEngine.VR.WSA.WebCam.Mode API檢查。
Photo Capture 捕獲照片
命名空間: UnityEngine.VR.WSA.WebCam
類型: PhotoCapture
PhotoCapture類允許我們使用相機拍攝靜態照片。正常的使用模式如下:
- 創建PhotoCapture對象
- 使用我們想要的設置來創建一個CameraParameters對象
- 調用StartPhotoModeAsync()方法開始拍照模式
- 拍攝想要的照片
- (可選項)進一步處理捕獲的圖像
- 關閉拍照模式並釋放資源
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格式把視頻直接存儲到磁盤上。步驟如下:
- 創建VideoCapture對象
- 使用我們想要的設置來創建一個CameraParameters對象
- 調用 StartVideoModeAsync()方法開始視頻捕獲模式
- 開始錄制視頻
- 停止錄制視頻
- 停止視頻捕獲模式並釋放相機資源
創建並配置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能力
- 全息圖像不能捕獲到圖片或者視頻中
- 未來的更新會支持捕獲全息圖像