2023/06/14

FaceLandmarkDetection

Mediapipe Face Landmark detectionでBlendshapeできる

以前はFacemeshとして知られていた顔の表情を3Dランドマークで推論するモデルがFacemeshV2として進化しましたね!なんとBlendshapeスコアが出せるようになりました。blazeFace => faceMeshV2 => blendShapeV2 という流れ。Facemeshに取って代わってFaceLandmarkDetectionになりました。

Face detection guide | MediaPipe | Google for Developers
使い方はPythonで試してみるのが一番わかる。

活用する側での一番のポイントは、ARKitのPerfectSyncとBlendShapeがコンパチなところ。BlendShapeの名前が同じなのでPerfectSync対応のアバターにそのまま使える。
ARFaceAnchor.BlendShapeLocation | Apple Developer Documentation

実際にPythonで動かしてみたところ、tongueOut 以外のBlendShapeスコアが出た。新しいFacemeshのドキュメントによると、cheekPuffとtongueOutは対象外とのことだが一応cheekPuffは含まれている。動いてるかどうかは微妙だけど。

これでPerfectSync対応にしておけばMediapipeからでも動かせることになる。Androidサンプルもあるので頑張ればネイティブに動かせる。

ARCoreやMLKitで動くようになれば、ARFoundationから利用できるようになるのかな。それまではPythonかWeb版でどうにかするかな。

2023/03/27

スイッチングハブが古すぎた

インターネットプロバイダを3年前に変更して特に不自由を感じてなかったのですが、昨年末にはついに子供たちに部屋を明け渡し、仕事と寝る部屋が同じになってしまいました。まあそれはそれでいいのですが。。そんなことから家のネットワーク環境を見直していたら、、、

まずプロバイダに問い合わせ。自分の契約だとアップリンク200MB制限だったことを知る。確かに速度計測すると100MB以下なので実質速度そんなもんかなと思っていた。

その後、1つ上の1GBに切り替えられることを知る。そんなこと契約情報ページからは分からない。早速回線種別変更をお願いして、切り替わった当日回線速度を測定、100MB以下。。。おや全然変わらないぞ?

Wifi接続すると160MBは出る。デスクトップはLANケーブル接続。ケーブルの方が遅い?それで疑ってもいなかったアップリンク速度を見ると100MBだと。なんとそこが原因!

最初はケーブルが1G対応してないほど古いやつ?と思った。10何年も前にロールで購入したやつを使っているが、確認するにCat5eだった。Cat6じゃないけど問題なし。

ってことはハブ?確かにいったんハブを通して接続している。直接接続するとちゃんとアップリンク速度が1Gになった。回線速度も計測値500MBオーバー。これかい。

思い起こせば使っているハブは光回線にする前から使っていたような。部屋の片隅でひっそり動いているやつなのでまさに眼中に入っていなかった。壊れないし。。

2千円台の安いやつでも普通にギガ対応なのね。今回は自分のボケ具合を公開してみました。

無駄に回線変更してしまったなとも思うし、10G時代に1Gってとも思うが、100Mでさほど不自由を感じていなかったのだから十分改善されたよと自分で自分の肩をたたく。。。


2022/11/18

Android Speech Translator Plugin for Unity

AndroidのSpeechRecognizerとMLKit Translateを使ってオンデバイスでリアルタイムスピーチ翻訳をUnityのプラグインとして実装してみた

ソースパッケージはGistで公開

概要はGistのREADMEに書いたので、ここでは作ってみて思ったことを書き残しておく

Unityプラグイン実装

よく見る記事ではAndroidネイティブAPIをUnityプラグインにする場合、AndroidStudio使って.aarにしてUnityのPlugins/Androidに置くとか書いてあるのが多いが、ものすごくめんどくさいので直接ネイティブソースを置いてUnityのgradleでビルドするようにした。

ソースファイルだけではだめで、AndroidManifest.xml、gradleTemplate.properties、mainTemplate.gradleファイルが必要。これらのファイルは、Android Player Settings>Publishing SettingsのBuildで、Custom Main Manifest、Custom Main Gradle Template、Custom Gradle Properties Templateにチェックを入れると自動的にPlugins/Androidにファイルが作成される。よくUnityインストールフォルダの奥深くから、これらのファイルを自分でコピーしてくるようなことを書いてある記事を見かけるが、そんな必要はない。

AndroidManifest.xmlに

  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-permission android:name="android.permission.INTERNET" />

gradleTemplate.propertiesに

android.useAndroidX=true

mainTemplate.gradleのdependenciesに

    implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.2'
    implementation 'com.google.mlkit:language-id:17.0.4'
    implementation 'com.google.mlkit:translate:17.0.1'

を追記。translateバージョンは17.0.1を入れたがその時点の最新を入れればいいと思う。
GistのunityPackageにはこれらのファイルは含まれている。

因みに、Unityのバージョンは2021.3.13f1を使用。2020.3.xxでもビルド可能だけど、Gradleなどのツールチェーンが今のAndroidStudioに比べかなり古いのでできるだけ新しいUnityバージョンを使うのがよさそう。2021.3.13f1で出力したAndroidProjectをAndroidStudioで開いてビルドしても問題なくビルドできた。

API Level

Player Settings>Other Settings:IdentificationのMinimum API LevelとTarget API Levelだけど、Minimumには24、TargetはHighest(30)を指定した。

SpeechRecognizer

品質はどうやらOSバージョンに強く依存するようだ。OS9くらいだとめちゃめちゃで使い物にならない。OS12だとまあ使える。OS13だともっといいかもしれない。

1回認識するとリスナーが終わってしまうので継続させるためには再度リスナー起動する必要がある。これが結構厄介。onResultsとonErrorイベント受けたタイミングでリスナー再起動している。本来ならonEndOfSpeechのタイミングが適切なのでは?と思うが、ここだといまいち安定しない。時々ERROR_CLIENTが出る。

何もしゃべらなかったとき、ERROR_SPEECH_TIMEOUTになるかなと思いきやERROR_NO_MATCHが出る。バグってない?と思ってしまう。

EXTRA_MAX_RESULTSで結果の最大数設定できるので1と設定しているが、結果が1つだけになるのはよっぽど自信があるときだけ。微妙な時は2~4つ候補が返ってくる。どんな仕様?

EXTRA_BIASING_STRINGSの使い方がさっぱり分からない。ドキュメントには

Optional list of strings, towards which the recognizer should bias the recognition results. These are separate from the device context.

と書かれているだけ。探しても具体的な設定方法とか効果とかがさっぱり分からない。
この設定で誤認識を少しは改善できるのでは?と思っているのだが。。。

onRmsChangedイベントって何?って思ったけど、簡単に言うと音量の事。rmsはRoot Mean Squareの略で一定時間内の平均音量ってこと。今音声拾ってますよというレベルメーターに使えるデータをずーっと返してくる。0..4はノイズ成分ぽいので捨ててます。

音声文字変換&音検知通知アプリもそうだけど、、

Pixel6に標準搭載された音声文字変換アプリに単語登録機能があるが、何入れても何の効果も感じられない。この機能がひょっとしてEXTRA_BIASING_STRINGSを使ってる部分かな?知らんけど。

結局EndToEndなんだよなぁ。学習モデルによるIN/OUTなので、しゃべる>直接日本語テキストが出てくる。出力結果に変化を与えたいと思ったら再学習させるしかないのだよね。
しゃべる>ひらがな認識>日本語入力エンジン>日本語テキストなら、途中のIME段階で辞書学習させれば誤認識も改善できそうなものだが。

固有名詞の誤認識を直したいときは、Unity上でonResultsで得られた文字列に対して特定の文字列があったら正しい文字列に直す、みたいな方法しか取れないかな。