【Unity】Android実機カメラの映像をUIに表示させる!

Android
https://amzn.to/3bd8XOX

 Unity上でスマホのカメラの映像を表示させる手順についてご紹介します。

Goal

カメラの画像をUnityで狙ったサイズで表示させる!




UI上に表示させてみる

 まずはUIにカメラ画像を出力するためのGameObjectであるRaw Imageを追加します。

 今回はボタンを押されたタイミングで表示を開始したかったのでButtonのOnClickイベントにカメラの表示開始を実装しました。カメラの表示はWebCamTextureを使用します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Button : MonoBehaviour
{
    public RawImage RawImage;
    WebCamTexture webCam;

    // Start と Update は省略
    public void OnClick()
    {
        // WebCamTextureのインスタンスを生成
        webCam = new WebCamTexture();
        //RawImageのテクスチャにWebCamTextureのインスタンスを設定
        RawImage.texture = webCam;
        //カメラ表示開始
        webCam.Play();
    }
}

 上記スクリプトをButtonにアタッチして、OnClick()をイベントに登録したら準備完了です。スクリプトのRawImageに先ほど追加したRawImageを設定するのを忘れないようにしてください。

 これで設定はOKです。PCにWebカメラがついている場合は表示されるので、実行してみます。

あっさりと表示させることができました。

Androidの実機で確認してみる

確認の前にちょっとはまった赤バツ

 では、このアプリをAndroidのアプリとして実行してみます。まずはスマホ上のスクリーンサイズに合わせたいので、Canvas>Canvas Scaler>Scale With Screen Sizeに設定してみました。

 Raw Imageに赤バツがついて、以降、カメラの映像は出なくなってしまいました。この赤バツは表示が裏返っていますよという意味らしく、もう一度適切にアンカーを設定しなおしてやることで、解消しました。今回、Heightが負の値になっていたので、正の値に修正することで改善しました。

 初心者はいちいちハマって、いちいち時間がかかるのがつらいです。。。あためて、実機でカメラの動作を確認してみます。

映像を表示する

 AndroidのPlatformに変更して実行してみます。実行してボタンを押すと、カメラのアクセス許可を求められるので、許可するを選択します。

 表示できましたが、向きが違います。長編の方を上向きで表示していますね。

映像の向きを変える

 Androidのカメラは90度の向きにつけられていることが多く、取得したデータをそのまま表示すると-90度に表示されるようです。90度回転させて表示するよう固定すると、デバイスによっては正しく表示できないことがあるので、お勧めしませんが、今回は愚直に90度回転させてみます。コードに以下を追加してみました。

    public void OnClick()
    {
        // WebCamTextureのインスタンスを生成
        webCam = new WebCamTexture();
        
        //RawImageのテクスチャにWebCamTextureのインスタンスを設定
        RawImage.texture = webCam;
        // 90度回転
        Vector3 angles = RawImage.GetComponent<RectTransform>().eulerAngles;
        angles.z = -90;

        RawImage.GetComponent<RectTransform>().eulerAngles = angles;

        //カメラ表示開始
        webCam.Play();
    }

 これで、このデバイスでは正しく表示されました。

 もしデバイス毎にカメラの角度を確認したい場合はNative Codeに取得用の関数を実装してライブラリ(AAR)化する必要があります。ライブラリの作成方法は以下の記事にもまとめいるので、参考にしてみてください。

サイズを変える

 ここまでで、カメラの映像を枠に表示させるところまでいきました。ただ、映像がつぶれています。映像をある固定サイズの領域どのように表示するかについていくつかのパターンを例に説明します。

 固定サイズ領域に表示させたい場合、以下の表示の仕方が考えられます。

  • アスペクト比を維持したまま映像全体を表示
  • アスペクト比を維持したまま映像の一部を表示
  • アスペクト比は崩れてもいいから固定領域サイズにサイズ変更して表示

 これら全ての表示方法を試してみます。今回、映像のサイズは1280×780表示枠は1:1とします。

アスペクト比を維持したまま映像全体を表示

 1280×780のカメラ映像を1:1の表示枠にアスペクト比を維持したまま全体を表示すると、上下が映像のない領域となります。1280×780のカメラ映像が来た時、正方形の枠にサイズ調整して表示するサンプルコードは以下になります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class Button : MonoBehaviour
{
    public RawImage RawImage;
    public GameObject Text;
    WebCamTexture webCam;


    // Start と Updateは省略
    public void OnClick()
    {
        // WebCamTextureのインスタンスを生成
        webCam = new WebCamTexture();
        
        //RawImageのテクスチャにWebCamTextureのインスタンスを設定
        RawImage.texture = webCam;

        //縦横のサイズを要求
        webCam.requestedWidth = 1280;
        webCam.requestedHeight = 780;

        //カメラ表示開始
        webCam.Play();

        float scale;
        Vector2 size;
        if (webCam.width > webCam.height) {
            // 横長映像 横のサイズに合わせる
            size = RawImage.GetComponent<RectTransform>().sizeDelta;
            scale = size.x / webCam.width;
            size.y = webCam.height * scale;
            RawImage.GetComponent<RectTransform>().sizeDelta = size;
        } else {
            // 縦長映像 縦のサイズに合わせる
            size = RawImage.GetComponent<RectTransform>().sizeDelta;
            scale = size.y / webCam.height;
            size.x = webCam.width * scale;
            RawImage.GetComponent<RectTransform>().sizeDelta = size;
        }
    }
}

 このコードで表示した時、映像の横を表示枠と同じ長さにして縦のサイズを調整するので、上下に非表示領域ができます。

アスペクト比を維持したまま映像の一部を表示

 アスペクト比を維持したまま表示枠いっぱいにできるだけ表示する方法です。アスペクト比がことなる表示エリアであった場合、必ず上下左右のどちらかが切れて表示されることになります。

    public void OnClick()
    {
        // WebCamTextureのインスタンスを生成
        webCam = new WebCamTexture();

        //RawImageのテクスチャにWebCamTextureのインスタンスを設定
        RawImage.texture = webCam;

        //縦横のサイズを要求
        webCam.requestedWidth = 1280;
        webCam.requestedHeight = 780;

        //カメラ表示開始
        webCam.Play();

        float scale;
        Vector2 size;
        if (webCam.width > webCam.height) {
            // 横長映像 縦のサイズに合わせる
            size = RawImage.GetComponent<RectTransform>().sizeDelta;
            scale = size.y / webCam.height;
            size.x = webCam.width * scale;
            RawImage.GetComponent<RectTransform>().sizeDelta = size;
        } else {
            // 縦長映像 横のサイズに合わせる
            size = RawImage.GetComponent<RectTransform>().sizeDelta;
            scale = size.x / webCam.width;
            size.y = webCam.height * scale;
            RawImage.GetComponent<RectTransform>().sizeDelta = size;
        }
    }

 このコードで表示した時、映像の縦を表示枠と同じ長さにして縦のサイズを調整するので、左右に映像がはみ出してしいます。先ほどよりくまさんが大きくなって両端が切れているのがわかります。

表示枠に無理やり合わせる

 アスペクト比を無視して無理やり表示エリアに合わせる方法です。あまりユースケースはないかもしれません。

        // WebCamTextureのインスタンスを生成
        webCam = new WebCamTexture();

        //RawImageのテクスチャにWebCamTextureのインスタンスを設定
        RawImage.texture = webCam;

        //縦横のサイズを要求
        webCam.requestedWidth = 1280;
        webCam.requestedHeight = 780;

        //カメラ表示開始
        webCam.Play();

        float scale;
        Vector2 size;
        size = RawImage.GetComponent<RectTransform>().sizeDelta;
        scale = size.y / webCam.height;
        size.y = webCam.height * scale;
        scale = size.x / webCam.width;
        size.x = webCam.width * scale;
        RawImage.GetComponent<RectTransform>().sizeDelta = size;
}

 無理やり比率を変えて表示しているので、横につぶれてしまっています。

まとめ

 今回はカメラの映像をUnityのUIに取り込んでみました。そしてAndroidの実機のカメラでも問題なく表示できることが確認できました。
 スマートフォンアプリでカメラの映像を扱う場合、映像のアスペクト比と実機の画面サイズを意識して表示させてやることが大事になります。表示領域を固定して、色々なアスペクト比で表示するサンプルについても参考になれば幸いです。

https://amzn.to/3bd8XOX

 

コメント