【ARCore】Light estimationを利用


ARCoreのLight estimationを利用

ARCoreに初期から搭載されているLight estimation機能を触ってみました。
なお、AndroidビルドのためのUnity設定等々は実施済みです。

キーワード

ARCore, Unity, AR, ビデオシースルー, 環境光推定, Light estimation

Light estimationとは

Light estimation などを参照ください。
カメラ画像から環境光の強さや色合いを推定する機能です。

バージョン情報など

  • バージョン情報
機能 バージョン
ARCore 1.1.0
Unity 2017.3.0f3
OS Windows 10 バージョン1709
端末 Galaxy S8 SC-02J (docomoのやつです)
  • 作業日

    2017年4月上旬 21:30頃(外光はほぼない状態)

環境光推定を利用したアプリ作成

SDK導入

ダウンロードページより、arcore-unity-sdk-v1.1.0.unitypackageをダウンロードしました。
新規プロジェクトを作成し、SDKを全てインポートしました。

プレハブ確認

Assets > GoogleARCore > Prefabs > Environment Light を確認してみました。
EnvironmentalLightなるスクリプトがアタッチされていますので、開いて確認してみたところ、

Frame.LightEstimate.PixelIntensity
Frame.LightEstimate.ColorCorrection

あたりで環境光の推定結果を取得しているようでした。
公式のリファレンスによるとLightEstimateは3つのプロパティを持っているようでした。
PixelIntensityがピクセル強度の平均を0から1の範囲で算出しているので、明るさはこの値を利用できるはずです。

なお、ピクセル強度については強度が低い=より暗い、強度が強い=より明るい程度の理解でいます。

PixelIntensityの確認

とりあえずPixelIntensityの値を確認を行いました。

ARCoreが提供しているプレハブである、ARCore Deviceをシーンに配置しました。
環境光推定値を出力するスクリプトShowPixelIntensity.csを作成し、生成した空のGameObjectにアタッチしました。

方法

シーン上にuGUIのtextを配置し、ここにPixelIntensityの値を表示させました。
また、ARCore内のプレハブに含まれていたEnvironmentalLightで計算されている、
Frame.LightEstimate.ColorCorrectionと最終的にシェーダに適用されている値も表示してみました。

using UnityEngine;
using GoogleARCore;
using UnityEngine.UI;

public class ShowPixelIntensity : MonoBehaviour
{
    [SerializeField]
    private Text pixelIntensityText;
    [SerializeField]
    private Text colorCorrectionText;
    [SerializeField]
    private Text globalColorText;
    private void Update()
    {
        if (Frame.LightEstimate.State == LightEstimateState.NotValid)
            return;

        pixelIntensityText.text = Frame.LightEstimate.PixelIntensity.ToString("#.000");
        colorCorrectionText.text = Frame.LightEstimate.ColorCorrection.ToString("#.000");

        const float middleGray = 0.466f;
        float normalizedIntensity = Frame.LightEstimate.PixelIntensity / middleGray;
        globalColorText.text = (Frame.LightEstimate.ColorCorrection * normalizedIntensity).ToString("#.000");

    }
}

表示用のUIをシーンに追加し、ビルド設定を行いビルドしました。

結果

部屋の明かりを変化させ、値の変化を確認しました。

蛍光灯の状態 条件備考 PixelIntensity
全点灯 最もPixelIntensityが高かった場所 0.75
全点灯 机見下ろし 0.5
全点灯 平均 0.65
常夜灯 0.13
消灯 モニタの明かりのみ 0.1
消灯 0.08
全点灯 カメラを完全にふさいだ状態 0.08

以下、それぞれの状態のカメラ映像になります。

0.75付近(全点灯) 0.60付近 0.50付近 0.40付近 0.20付近(常夜灯) 0.15付近(側面にモニタ光) 0.08付近

注意点

画像から明るさを類推しているため、白に近いカーテンを見ているときと、黒に近いカーテンを見ている時では、恐らくPixelIntensityの値は変化します。

オブジェクト追加

スケルトン(BSHGAME Skeletons Pack)をお呼びし、明るさに応じて目を光らせて頂きました。
目の光らせ方は、テラシュールブログ様の記事、目やパーツの一部を光らせるを参照します。

スケさんの眼窩付近にFlareSmallを設定したPoint lightを配置しました。

LightEstimate.PixelIntensityが小さくなるほどライトを強くするスクリプトを作成し、先ほど作成したライトを参照しておきます。

[SerializeField]
private Light light;

light.intensity = 1f - (Frame.LightEstimate.PixelIntensity);

感想

  • 最後のライト部分がかなり適当ですが、外界の明るさに応じた処理を作成できました。
    外部の影響によって動きが変わるものは、単純でも意外に面白かったです。

  • ARCoreではカメラが光量を自動的に調節してしまうので、必ずしも光源に向かった状態がPixelIntensity最大ではありません。
    実際に利用する際は実地でのテストが必須だと思われます。

参考:光源を向いた場合のPixelIntensity

同様の理由で、昼間と夜間の室内を比較した場合、昼間のPixelIntensityの方が常に高いとは限りません。

  • 夜間だけ火のつく燈篭とか作れればカッコイイ。

  • Motion trackingと組み合わせ、特定の地点から特定の方向を向いた場合の光量を記憶できれば、明るい場所に向かって動くゾンビとか作れそうな気もしました。

  • ARCore1.1.0から搭載のInstant Previewが超便利です。
    特に設定していなくてもポップアップが出現し、それに従っていけば勝手に利用できる環境が構築されていました。
    二回目以降はAndroid側でARCore Instant Previewを起動しておく必要があるようです。