HoloLens 2で取った写真をAzure Blob Storageにアップロードする

はじめに

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についての詳細は以下のドキュメントをご覧ください。

docs.microsoft.com

実装手順

NuGetForUnityの導入

UnityのプロジェクトにNugetパッケージを導入するためにはNugetForUnityが便利です。
以下のページからダウンロードすることができます。

github.com

.unitypackage形式のファイルをダウンロードしたらUnityのプロジェクトにインポートします。

Blob Storageのパッケージの導入

UnityエディタのメニューバーからNuGetManage 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

執筆担当者プロフィール
古川 貴浩

古川 貴浩(日本ビジネスシステムズ株式会社)

アプリケーション開発をしています。.NETやAI関連が好きです。

担当記事一覧