1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

UnityでOVRFaceExpressionsのデータをまるっとCSVで取得する

Posted at

はじめに

前回の記事でMetaQuestProのフェイストラッキングで得られるデータの説明と取得する方法を書きました。
この記事では,OVRFaceExpressionsの値をまるっと取得して,CSVに出力する方法をまとめます。今後ウィンクによる認証を実装するため,今回はウィンクをした時のOVRFaceExpressionsの値を取得します。

ソースコードの修正

前回同様,Unity-Movementのソースコードを修正していきます。

Log.csの作成

Logという名前で空のオブジェクトを作成して,Log.csをアタッチします。

Log.cs
using System.Collections.Generic;
using UnityEngine;
using System.IO;

public class Log : MonoBehaviour {
  private static string filePath = string.Empty;

  void Start() {
    CreateDirectory();
  }

  private void CreateDirectory() {
    filePath = Application.persistentDataPath + "/Log/";

    if (!Directory.Exists(filePath)) {
      Directory.CreateDirectory(filePath);
    }
  }
    
  public static void Output(string fileName, List<string> logs) {
    var FullPath = Path.Combine(filePath, fileName);
    File.WriteAllLines(FullPath, logs);
  }
}

私の環境(Windows&MetaQuestPro)ではApplication.persistentDataPathは,
PC\Quest Pro\内部共有ストレージ\Android\data\com.DefaultCompany.プロジェクト名\files\
だったので,そこからCSVファイルを取ってくることができます。

OVRFaceExpressionsの修正

OVRFaceExpressions.cs
// OVRFaceExpressionsの値を時系列順に配列で管理するためのMyFaceExpressionクラスを定義
public class MyFaceExpression {
  public float BrowLowererL;
  public float BrowLowererR;
  ... (以下略)

  public MyFaceExpression(
    float BrowLowererL,
    float BrowLowererR,
    ... (以下略)
  ) {
    this.BrowLowererL = BrowLowererL;
    this.BrowLowererR = BrowLowererR;
    ... (以下略)
  }
}

public class OVRFaceExpressions : MonoBehaviour, IReadOnlyCollection<float>, OVRFaceExpressions.WeightProvider {
  ...
  private GameObject LogObj;
  private Log Log;
  private List<MyFaceExpression> myFaceExpressions = new List<MyFaceExpression>();
  ...

  private void Start() {
    Log = LogObj.GetComponent<Log>();
  }

  private void Update() {
    ...
    if (ValidExpressions) {
      // Aボタンを押している間,データを取得する
      if (OVRInput.Get(OVRInput.Button.One)) {
        myFaceExpressions.Add(new MyFaceExpression(
          GetWeight(FaceExpression.BrowLowererL),
          GetWeight(FaceExpression.BrowLowererR),
          ... (以下略)
        ));
      }

     // Bボタンを押すと,取得したデータをCSVファイルに保存する
      if (OVRInput.GetDown(OVRInput.Button.Two)) {
        var fileName = "face_" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv";
        Save(fileName, myFaceExpressions);
      }
    }
    ...
  }

  private void Save(string fileName, List<MyFaceExpression> history) {
    Log.Output(fileName, MyFaceExpressionListToCSV(history));
  }

  private List<string> MyFaceExpressionListToCSV(List<MyFaceExpression> history) {
    List<string> str = new List<string>() {"BrowLowererL,BrowLowererR,...(以下略)"};
      for (int i = 0; i < history.Count; i++) {
        str.Add(string.Join(",", new List<string>(){
          history[i].BrowLowererL.ToString(),
          history[i].BrowLowererR.ToString(),
          ... (以下略)
        }));
      }
    return str;
  }
}  

メトロノームの実装(おまけ)

後々データを利用しやすくするために,指定したタイミングでウィンクをするためのメトロノームを実装します。

OVRFaceExpressions.cs
public class OVRFaceExpressions : MonoBehaviour, IReadOnlyCollection<float>, OVRFaceExpressions.WeightProvider {
  ...
  [SerializeField] private AudioSource audioSource;
  [SerializeField] private AudioClip main;
  [SerializeField] private AudioClip sub;

  private int cnt = 0;
  private float _repeatSpan = 1.0f;
  private float _timeElapsed = 0.0f;
  ...
  void Play() {
   // 4拍のうち最初の1拍目(main)を別の音にする
    switch (cnt) {
      case 0:
        audioSource.PlayOneShot(main);
        break;
      default:
        audioSource.PlayOneShot(sub);
        break;
    }
    cnt = (cnt + 1) % 4;
  }
  ...
  private void Update() {
    _timeElapsed += Time.deltaTime;

    if (_timeElapsed >= _repeatSpan) {
      // _repeatSpan(1秒)ごとに音を鳴らす
      Play();
      _timeElapsed = 0.0f;
    }
  }
  ...
}

あとはUnity側のInspectorウィンドウでAudioSourceとAudioClipをアタッチすればOKです。

取得したデータ

取得したデータは,OVRFaceExpressionsで定義された63個のキーに対応する各値です(意味をなしていないA列は見なかったことに,,)。

4秒間隔で左目でウィンクをしており,とりあえず20秒くらい取得しました。

image.png

データ分析

ウィンクで認証をする際にどのデータが重要になるかを分析する必要があります。

とりあえず63個すべてにおいての折れ線グラフを出すと下図の様になりました。

face.png

わかりづらいので部位ごとに項目を分別してみます。

brow.png

eyes1.png

eyes2.png

cheek.png

nose.png

mouth.png

lip1.png

lip2.png

lip3.png

jaw.png

おわりに

これでCSVでデータを取得することができたので,次回は実際に分類器モデルを作ってみたいと思います。(データ集め大変,,)

参考にした記事

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?