はじめに
HoloLens 2で撮った写真をBlob Storageに保存したかったので、Unityでの実装方法を調査しました。
環境
Microsoft Visual Studio Professional 2022 (64-bit) Version 17.2.5
Unity 2020.3.36f1
NugetForUnity 3.0.5
Azure.Storage.Blobs 12.13.0
前提
- Unityプロジェクトの作成やHoloLens 2向けの設定が完了していること
- Azure Blob Storageについては以下が完了していること
- リソースの作成
- 「images」という名前のコンテナの作成
Azure Blob Storageについての詳細は以下のドキュメントをご覧ください。
実装手順
NuGetForUnityの導入
UnityのプロジェクトにNugetパッケージを導入するためにはNugetForUnityが便利です。
以下のページからダウンロードすることができます。
.unitypackage
形式のファイルをダウンロードしたらUnityのプロジェクトにインポートします。
Blob Storageのパッケージの導入
UnityエディタのメニューバーからNuGet
→ Manage NuGet Packages
と選択していきます。
メニュー画面が開いたらAzure.Storage.Blobs
で検索を行い、パッケージを導入します。
私の場合はパッケージ導入直後にエラーが出たのですが、Unityエディタを開きなおしたらエラーがなくなりました。
コード
Unityのプロジェクトにスクリプトを作成します。内容は以下の通りです。
using Azure.Storage.Blobs; using System.IO; using System.Linq; using System.Threading.Tasks; using UnityEngine; using UnityEngine.Windows.WebCam; public class HoloBlob : MonoBehaviour { private PhotoCapture photoCaptureObject = null; private Resolution cameraResolution; Texture2D texture; string connectionString = "[Blob Storageの接続文字列]"; public void TakePhoto() { PhotoCapture.CreateAsync(false, OnPhotoCaptureCreated); } private void OnPhotoCaptureCreated(PhotoCapture captureObject) { photoCaptureObject = captureObject; cameraResolution = PhotoCapture.SupportedResolutions.OrderByDescending((res) => res.width * res.height).First(); CameraParameters cameraParameters = new CameraParameters(WebCamMode.PhotoMode) { hologramOpacity = 0.0f, cameraResolutionWidth = cameraResolution.width, cameraResolutionHeight = cameraResolution.height, pixelFormat = CapturePixelFormat.BGRA32 }; captureObject.StartPhotoModeAsync(cameraParameters, OnPhotoModeStarted); } private void OnPhotoModeStarted(PhotoCapture.PhotoCaptureResult result) { if (result.success) { photoCaptureObject.TakePhotoAsync(OnPhotoCaptured); } else { Debug.Log("Photo is not ready"); } } private void OnPhotoCaptured(PhotoCapture.PhotoCaptureResult result, PhotoCaptureFrame photoCaptureFrame) { if (result.success) { texture = new Texture2D(cameraResolution.width, cameraResolution.height); //カメラで撮影した画像データをテクスチャにコピー photoCaptureFrame.UploadImageDataToTexture(texture); } photoCaptureObject.StopPhotoModeAsync(OnPhotoCaptureStopped); } private void OnPhotoCaptureStopped(PhotoCapture.PhotoCaptureResult result) { photoCaptureObject.Dispose(); photoCaptureObject = null; //JPEG形式にエンコード var imageData = texture.EncodeToJPG(); Task.Run(() => UploadImage(imageData)); } /// <summary> /// 撮影した画像をAzure Blob ストレージにアップロードする /// </summary> /// <param name="image">画像データのバイト配列</param> /// <returns></returns> async Task UploadImage(byte[] image) { BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString); string containerName = "images"; BlobContainerClient containerClient = blobServiceClient.GetBlobContainerClient(containerName); string fileName = "testimage.jpg"; BlobClient blobClient = containerClient.GetBlobClient(fileName); using var memoryStream = new MemoryStream(image); //第2引数をtrueにすることにより、同じ名前のファイルがあった場合は上書きする await blobClient.UploadAsync(memoryStream, true); } }
上からOnPhotoCaptured
までは写真を撮るための処理です。
UploadImage
では撮影した画像データをBlob Storageへアップロードしています。
次に上記スクリプトのTakePhoto
を実行するためのボタンを作ります。
UnityエディタのHierarchyでCreate Empty
を選択して空のオブジェクトを作ります。
このオブジェクトに先ほど作成したスクリプトを追加します。
次にボタンを追加します。
ProjectウィンドウでPressableButtonHoloLens2
と検索します。これをHierarchyウィンドウに追加します。
追加したら以下の画像のように、ボタンを押したらTakePhoto
を実行するように設定します。
アプリの実行
あとはHoloLens 2にデプロイしてアプリを起動し、ボタンを押せばカメラで撮影した画像をBlob Storageにアップロードすることができます。
また、Unityエディタで実行するとPCのカメラで撮影した画像がアップロードされます。
Blob Storageのコンテナを確認すると、画像がアップロードされていました。
1点気になることとしては、HoloLens 2で実行するとボタンを押した後にアプリが一瞬重くなることです。画像データが大きいためでしょうか?
これについては何か解決する方法を探したいと思います。
参考ページ
クイックスタート: Azure Blob Storage ライブラリ v12 - .NET | Microsoft Docs
Unity のフォト ビデオ カメラ - Mixed Reality | Microsoft Docs