はじめに
前回の記事でMetaQuestProのフェイストラッキングで得られるデータの説明と取得する方法を書きました。
この記事では,OVRFaceExpressionsの値をまるっと取得して,CSVに出力する方法をまとめます。今後ウィンクによる認証を実装するため,今回はウィンクをした時のOVRFaceExpressionsの値を取得します。
ソースコードの修正
前回同様,Unity-Movementのソースコードを修正していきます。
Log.csの作成
Logという名前で空のオブジェクトを作成して,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の値を時系列順に配列で管理するための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;
}
}
メトロノームの実装(おまけ)
後々データを利用しやすくするために,指定したタイミングでウィンクをするためのメトロノームを実装します。
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秒くらい取得しました。
データ分析
ウィンクで認証をする際にどのデータが重要になるかを分析する必要があります。
とりあえず63個すべてにおいての折れ線グラフを出すと下図の様になりました。
わかりづらいので部位ごとに項目を分別してみます。
眉
目
頬
鼻
口
唇
顎
おわりに
これでCSVでデータを取得することができたので,次回は実際に分類器モデルを作ってみたいと思います。(データ集め大変,,)
参考にした記事