Aizu-Progressive xr Lab blog

会津大学のVR部であるA-PxLの部員が持ち回りで投稿していくブログです。部員がそれぞれVRに関する出来事やVRにちなんだことについて学んだことを書いていきます。

連絡はサークルTwitterのDMへお願いします。
「面白法人カヤックVR分室」としても活動しています。詳細はこちら

MRTKv2 サンプルシーンをHoloLens1で試した

はじめに

学部2年の木村です. 今年からHoloLensをいじったりしてます. v2の前のバージョンのMRTKのことはあまり知らないのですが, MRTKv2のサンプルをHololensでビルドしてみたのでやったことの記録のようなものを書きます.

環境

やった手順

まずは, 公式のGitHubからMRTKv2 RC1 Refreshの2つのアセットをダウンロードしてUnityへインポートします.

次に, サンプルのシーンを開きます. MRTKには機能などに応じて多くのサンプルシーンが用意されているようです. ここではAssets/MixedRealityToolKit.Examples/Demos/HandTracking/Scenes/HandInteractionExamplesを使います.


シーンを開くと, このようにTMP Importerのウィンドウが出てきました.

このシーンではText Mesh Proが使われているようなのでImport TMP Essentialsを選択して必要なパッケージをインポートしておきます.

次に, HoloLens用の設定です.
こんな感じで設定しました

  • Platform -> Universal Windows Platform
  • Target Device -> HoloLens
  • Architecture -> x86

Player Settings

これでシーンの準備はできたはずなので, ビルドする前にHolographic Remoting Playerでシーンを再生してみます.

Window/XR/Holographic Emulation を開いて

  • Emulation Mode -> Remote to Device
  • Remote Machine -> HoloLensのIPアドレスを入力

入力できたらHoloLensでHolographic Remoting Playerを開き, connectをクリックします.connectingになればokです.

シーンを再生するとこんな感じになりました

次はビルドします.
まずはUnity上での操作です.
Build Settingで現在のシーンをScenes In Buildへ追加したらBuildクリックして, 適当なフォルダを作成してそのフォルダを選択します.

Unityでのビルドが完了したらさっき選択したフォルダの中に.slnという拡張子のファイルがあるのでそれをダブルクリックします. すると, Visual Studioでslnファイルが開かれます.

今度はVisual Studioでの操作です.
slnファイルが開かれたら構成やプラットフォームの設定をします. 次の画像のように設定します.

  • ソリュージョン構成 -> Release
  • ソリュージョンプラットフォーム -> x86
  • その右のやつ -> リモートコンピューター

最後にデバッグ/プロジェクト名のプロパティページ/デバッグ/コンピューター名にHoloLensのIPアドレスを入力します.
あとは, Ctrl + F5でデバッグ無しでビルドすれば完了です.


動画ではfpsが低いんですけど録画中とかスクショを撮った瞬間にfpsが30~40くらいに下がっちゃうみたいですが, 録画とかしてなければ60fpsでした.

70行弱で書ける!音声データから話者を当てる人工知能を作ってみた!

こんにちは。学部3年の柴山です。
今回はPythonで音声データを機械学習させて、話者認識(誰が話しているかを判定する)をする方法を紹介したいと思います。
コード総数70行弱、しかし正答率98.7%コスパ良しな人工知能に興味を持っていただけたのなら、ぜひ最後までお付き合いください。

データの前処理

今回使用した音声データは「12人の話者が日本中の駅名を呟いたもの」です。
音声データは駅名ごとに用意してあり、総数は約4万件、一人当たり3千ちょいあります。
ちなみに日本の駅の総数は9500個ほどらしいので、これでも一部なんですね( ̄◇ ̄;)

以下のことに気をつけていただければ音声データはなんでも平気です。
全てのデータは.wavファイルにします。
ファイル名を全て「<話者の名前>_<番号>」という形式にします。
データは学習用とテスト用に7:3の割合でディレクトリを分けます。
学習用のディレクトリ名は「<話者の名前>」、テスト用のディレクトリ名は「<話者の名前>test」にします。
f:id:aizu-vr:20190425185127p:plain

コード

今回は以下のライブラリを使用します。

import scipy.io.wavfile as wav  # .wavファイルを扱うためのライブラリ
from sklearn.svm import SVC     # SVC(クラス分類をする手法)を使うためのライブラリ
import numpy                    # ndarray(多次元配列)などを扱うためのライブラリ
import librosa                  # 音声信号処理をするためのライブラリ
import os                       # osに依存する機能を利用するためのライブラリ


次にROOT_PATHに音声データの各ディレクトリが入っているディレクトリへの絶対パス、speakersに話者名の配列を代入します。
word_trainingとspeaker_trainingは後々、計算結果を入れたり、データのラベリング(そのデータがどの話者の音声なのかを対応づける)をしたりするために使います。

# ルートディレクトリ
ROOT_PATH = '<音声データのディレクトリが入っているディレクトリへの絶対パス>'

# 話者の名前(各話者のデータのディレクトリ名になっている)
speakers=['SP203', 'SP205', 'SP206', 'SP208', 'SP210', 'SP211',
    'SP502', 'SP605', 'SP619', 'SP622', 'SP704', 'SP708']

word_training=[]    # 学習用のFCCの値を格納する配列
speaker_training=[] # 学習用のラベルを格納する配列

次に、MFCC(メル周波数ケプストラム係数)を求めるための関数を定義します。
MFCCとは音声にどのような特徴があるかを数値化したものです。
この数値によって分類していきます。

# MFCCを求める関数
def getMfcc(filename):
    y, sr = librosa.load(filename)      # 引数で受けとったファイル名でデータを読み込む。
    return librosa.feature.mfcc(y=y, sr=sr) # MFCCの値を返します。

ディレクトリごとにデータをロードして、MFCC求めていきます。

# 各ディレクトリごとにデータをロードし、MFCCを求めていく
for speaker in speakers:
    # どの話者のデータを読み込んでいるかを表示
    print('Reading data of %s...' % speaker)
    # 話者名でディレクトリを作成しているため<ルートパス+話者名>で読み込める。
    path = os.path.join(ROOT_PATH + speaker)    
    # パス、ディレクトリ名、ファイル名に分けることができる便利なメソッド
    for pathname, dirnames, filenames in os.walk(path): 
        for filename in filenames:
            # macの場合は勝手に.DS_Storeやらを作るので、念の為.wavファイルしか読み込まないようにします。
            if filename.endswith('.wav'):
                mfcc=getMfcc(os.path.join(pathname, filename))
                word_training.append(mfcc.T)    # word_trainingにmfccの値を追加
                label=numpy.full((mfcc.shape[1] ,), 
                speakers.index(speaker), dtype=numpy.int)   # labelをspeakersのindexで全て初期化
                speaker_training.append(label)  # speaker_trainingにラベルを追加

word_training=numpy.concatenate(word_training)  # ndarrayを結合
speaker_training=numpy.concatenate(speaker_training)

ここで機械学習のプログラムを書く上でのちょっとしたコツを一つ。
上記のprint('Reading 〜')のところをご覧ください。
この行は本来機械学習をする上では一切必要ありません。ただ文字をコンソールに出力しているだけですから。
ですが、この一行がないと自らのプログラムがきちんと動いているのか疑心暗鬼になります。
余談ですが、上記の4万件のデータだと一回の実行に10時間以上かかりました。
その間何も映らない暗い画面だけ、タスクマネージャーを見るとCPU使用率が100%。
私は一度、数時間実行した挙句、自分のコードが信じられずにCtrlを押しながらCキーに指を当て...。
皆さんには同じ目にあって欲しくありません笑。
なのである程度進捗がわかるような構造を作りましょう。

そして、いよいよ学習部分ですが、なんと3行です。

# カーネル係数を1e-4で学習
clf = SVC(C=1, gamma=1e-4)      # SVCはクラス分類をするためのメソッド
clf.fit(word_training, speaker_training)    # MFCCの値とラベルを組み合わせて学習
print('Learning Done')

python機械学習をするためのライブラリが充実しているのがいいですね。
カーネル係数は長くなる上私も勉強中であまり下手なことは言えないので、
カーネル法という機械学習に用いられるパターン認識の手法に使う値」と思ってください。
この値をいじると正答率に直接影響します。私の場合はトライ&エラーの結果1e-4という値に落ち着きましたが、
データによってはある程度上下すると思います。

つぎに、学習したデータをもとに、〜testディレクトリのデータでテストします。

counts = []     # predictionの中で各値(予測される話者のインデックス)が何回出ているかのカウント
file_list = []  # file名を格納する配列

# 各話者のテストデータが入っている~testというディレクトリごとにMFCCを求めていく
for speaker in speakers:
    path = os.path.join(ROOT_PATH + '%stest' % speaker)
    for pathname, dirnames, filenames in os.walk(path):
        for filename in filenames:
            if filename.endswith('.wav'):
                mfcc = getMfcc(os.path.join(pathname, filename))
                prediction = clf.predict(mfcc.T)    # MFCCの値から予測した結果を代入
                # predictionの中で各値(予測される話者のインデックス)が何回出ているかをカウントして追加
                counts.append(numpy.bincount(prediction))   
                file_list.append(filename)  # 実際のファイル名を追加

最後は推測される話者のインデックスより、speakersから話者の名前を取得し、実際のファイル名がその名前から始まっていれば正解。
違っていれば間違いという判定で正答率を求めます。

total = 0   # データの総数
correct = 0 # 正解の数

# 推測される話者の名前がファイル名の頭と一致したらCorrect
for filename, count in zip(file_list, counts):
    total += 1
    result = speakers[numpy.argmax(count-count.mean(axis=0))]   # 
    if  filename.startswith(result):
        correct += 1

print('score : ' + str(correct / total))

まとめ

こうしてみると随分ライブラリ頼りで、70行弱なんてのは詐欺まがいですが、そこがpythonのいいところと許していただきたいです笑。
自分で想定していた以上の正答率が出たので嬉しいですが、課題としては如何せん実行時間がかかり過ぎかもしれません。
今回使用したMFCCというのは精度は高いですが、計算量が多めな手法だったので、今度は別の手法も試してみたいと思います!
最後まで読んでいただきありがとうございました!

学部3年 柴山 叶

Marvelous Designerの紹介

こんにちは、学部3年の丹野です。 今回私はMarvelous Designerというソフトの紹介をしていきたいと思います。 Marvelous Designerとは服作りを目的とした3DCGツールです。 機能としては服のモデリング以外にもUVの配置やテクスチャの適用。作成した服のアニメーションも作ることができます。

続きを読む

VR ZONE 新宿 感想

こんにちは、学部1年の髙橋です。先日、VR部ないの友人と一緒に VR ZONE に行ってきました。今日は実際に体験した感想や思ったことを書いていこうとおもいます。おそらくほとんどのアトラクションと体験してきましたが特に印象に残った2つについて書こうと思います。あ、ネタバレを含むので見たくない方は見ないでくださいね。

DRAGON BALL
脱出病棟Ω
感想

DRAGON BALL

f:id:aizu-vr:20190331173828j:plain

どんなゲーム?

ドラゴンボールの世界で気弾やかめはめ波を習得して最後に同時にプレイしているプレイヤーと対戦できるゲームでした。

できたこと

気弾・・・素早く掌底を突き出すことで生み出すことができる。
かめはめ波・・・膝を曲げ、腰に手を当てることで気を溜め、ため終わり次第両手を右腰に持ってきてあとは「か〜め〜は〜め〜波ぁぁぁぁ!!!」と両手を方に突き出す。

よかったところ

     
  • かめはめ波を撃つ際、気を貯めた時に足元が震え実際に気が溜まっていることを体感できる。
  •  
  • ゲーム開始前、スタッフさんが技の発動方法について説明してくれますがさらにゲーム内のチュートリアルで悟空、ベジータ、ピッコロ、クリリンが技について指導してくれます。(悟空、ベジータ、ピッコロ、クリリンについてはゲーム開始前に選ぶことができました。)

もっとよくできそうなところ

私はベジータとピッコロに指導をしてもらいましたが、一度めのベジータはしっかりと思った方向にかめはめ波を撃つことができました。しかし、ピッコロでは思うようにかめはめ波が打てずまともに戦えませんでした。気弾に関しては両方とも思った方向に行かず、かなり手こずりました。修行が足りないせいもありますが、目の前のセンサーとトラッカーの設定がうまく行ってなかったと思うのでうまくいけばさらに楽しめそうだなと思いました。

脱出病棟Ω

f:id:aizu-vr:20190331181402j:plain

どんなゲーム?

廃病院から車椅子に縛られた状態で脱出を試みるゲームでした。ルールは制限時間内の脱出です。誰か一人が殺された場合、仲間が道連れになります。

できたこと

  • 電動車椅子に似せた筐体に座りレバーを動かしながら、懐中電灯を頼りに移動。
  • ルート選択

よかったところ

  • ログインからゲームが始まるまで(他のプレイヤーがログインするまで)一つの部屋に隔離され、ゲームが始まる前から恐怖心を植えつけられました。
  • ゲームのルールでは一人が殺されると他のプレイヤーも道連れとあり、捕まった習慣殺されるのかと思いました。しかし、捕まると処刑室に連れて行かれました。そこには自分と同じ格好をした人、処刑人がいて、仲間とゴールが映ったモニターがありました。 ボイスチャットができるのでそれで仲間を誘導し、自分が殺されるまでに仲間をゴールに届けることができれば自分も助かるというものでした。復活のチャンスがあって助かりました。しかし助かったのも束の間、今度は仲間と同じ選択肢を選らぶように迫られさらにはギロチンのようなものが回転しながら迫ってきてかなり怖かったです。助かったと思ったら次の習慣から絶望に落としにくるような仕様が面白かったです。

もっとよくできそうなところ

廃病院にしてはものがたくさんあり電気が通っていたのでまだ潰れて年数が経っていないのかなと思えば、病室の中がシーツがビリビリで所々にはゾンビのような生き物たちがいる。廃病院ではなく、知能のあるゾンビのような殺戮者に支配された病院なのかなと思ったのでもう少しゲーム内の世界を細かく設定できるんじゃないかなと思いました。

感想

f:id:aizu-vr:20190331190635j:plain VR ZONEが終わる前に行くことができとても良かったです。いくつかのゲームの説明書きの下にUnreal-Enginのロゴがあり普段部活で使っていたUnityとの違いやそれぞれでゲームを作ることで何が変わるのかとても気になりました。また、まだまだトラッカーやヘッドセットがあるとストレスがかかるのでもっともっとデバイス自体が小さくなりストレスフリーになればより快適にプレイできるのでその日がさらに楽しみになりました。

面白法人カヤックインターン体験談

こんにちは学部2年(新3年)の森口です

本日はタイトルにもある通りインターンシップで経験したことの話をしたいと思います。
今週1週間(3/25~3/29)鎌倉にある面白法人カヤックさんのインターンシップに参加させていただきました。 私はクライアントワーク事業部に所属し、課題としてヒューマノイドモデル絡みのことをしました。(以降ある程度はコンプライアンス的に伏せさせていただきます)

1週間のざっくりとした流れとインターンシップに参加してみての感想を述べていきたいと思います。

1日目

 1日目は主に課題のための下調べでした。どんな機能を盛り込めばいいか、どうすればそれを実現できるかなどについて調べました。その過程で人間の体の構造について調べたりしたこともあり、普段目にしないような分野にまで踏み入ったのである意味面白かったです。

2日目

 2日目から本格的に実装に入りました。 いくつかタスクがあったのですが、一応簡単にするためにこれ以降やった作業はタスクn(nはタスク番号)といった形で記事は書かせてもらいます。

タスク1はヒューマノイドモデルの目を人間ぽく回転させるというものだったのですが実際これが一番苦戦した内容でした。個人的Unityで内容がよくわかんないものランキングで上位に来るQuaternionにとても苦しめられました。回転をいじるときに出てくるものなんですがPositionなどとは違いベクトルではなく4元数と呼ばれるものなので扱いが若干違ったりオイラー角に直して扱うときの範囲が0~360だったりと何かと厄介者でした。

3日目

 しれっと3日目に入りました。なぜかというと全部で5日間あるインターンシップの日程の中でタスクの割り振りは以下のように結果的になりました。

1日目:下調べ

2日目:タスク1

3日目:タスク1

4日目:タスク1、タスク2、タスク3

5日目:タスク3、タスク4

はい。ご覧の通りほとんどを件のタスク1もといQuaternionにやられていました。なぜそこまで苦戦したのか、それはUnityではオイラー角が0~360度の間で取り扱われることが主な原因だと思っています。例えば-30度は330度と同じ角度ですが計算や判別処理を-30度でやるのと330度でやるのは全然違います。また、-30度というのは内部的に330度として処理されるので改めて値をとってくると前回と違う値になってたりします。また、人間の目は回転可能な角度が決まっているので閾値を設けて制限をかけるようにしたのですが、人間の目は球体ですので(当たり前)どちらか一方向に回転を続ければ反対側から戻ってきます。つまり正の方向にオーバーしたのか、負の方向にオーバーしたのかというのを判定させる必要もありました。そのような理由でこのあたりの実装に苦戦していました。

後この日は飛び入りでしたがブレストにも参加させていただきました。私は緊張などで全く発言できなかったんですが自分が今まで経験とは全く違うどんどんアイデアが膨らんでいくブレストで、社員の方々皆さんが「あれが実現できたらおもしろい」「やっぱりこれがやりたい」と互いの意見を尊重しつつもしっかりとまとまりのある素晴らしいブレストを見させていただきました。これが本来のブレストなんだと思いさすがはカヤックと感じました。

4日目

 よくわかりませんがこの日は異様に頭がさえてました。3日目ずっと考えても出なかった解決案が午前中の数時間で出ました。まずは0~360の範囲で扱われるオイラー角を-180~180の間に変換してあげます。そうすることで判定処理や計算過程で負の角度を用いることができるようになります。角度の変更は以下の式でできます

float angle; //使いたい角度
angle=(angle>180)?angle-360:angle; //0~360を-180~180に

//諸々の処理

angle=(angle<0)?angle+360:angle // -180~180を0~360に

後は諸々の処理のところに正の方向の閾値をオーバーしてたら~みたいな処理を書いてあげればOKです。
ここまでたどり着くまでにだいぶQuaternion関係の記事を漁ったのでだいぶ成長できたと思います。
タスク1が完了した後は次のタスクへ進むわけですが割とこの辺はサクサク進みました。

タスク2,3を簡単に説明すると、2はまた目関係ですがこれはカヤックさんにあったものを1で作ったものとかみ合うようにしたというものなので詳細は省かせていただきます。

3は呼吸に合わせて肩や胸が動く機能を実装しました。適度なスパンでボーンに回転を加えてあげるといい感じです。

5日目

 最終日です。ここでは3の調整とオプションみたいな立ち位置で時間があったらやってと言われていた4をこなしました。4は感情を表現するといったもので、人間の感情には流れがあるというものを目にしたのでそれの実装を行う予定でした。構想はできていたものの実装で詰まったところがあり時間が足りず納得のいくところまでは実装ができませんでした、

 この日まで本当にあっという間で体感的に1日前に出てきて次の日に戻ってきたくらいでした

感想&まとめ

 長くなってきたのでこの辺でまとめますね。

 自分自身がっつりコードが書けるほど技量があるわけではないので、もしかしたらできる人ならサクサクこなしてしまう課題だったのかもしれませんがそれでも学習することは非常に多くてためになった課題だと感じました。判定処理の方法や回転の取得方法についても様々な考え方やアドバイスをいただけたので処理手順の勉強にもなりました。

 また、オフィスでエンジニアの一人として働く雰囲気というのも体験できたと感じています。カヤックの社員さんは非常に和気あいあいと仕事をしていて面白く仕事をしているのがよく感じられました。

 繰り返しにはなりますがこの1週間は自分にとって大きく成長できる機会でとても内容の濃い1週間だったと思います。今回のインターンシップにてお世話になった面白法人カヤックの皆さん、本当にありがとうございました!お世話になりました!

会津大学VR部の部員が持ち回りで投稿していくブログです。特にテーマに縛りを設けずに書いていきます!