Top / VstoneMagicを使ってみる / プログラミング / 顔と名前を覚えさせてみよう

顔と名前を覚えさせてみよう


顔認識や音声認識のを使ったブロックには、発話の中から人の名前を取得したり、検出した顔の特徴を記憶して個人を特定するものも備わっています。人の名前を呼んだり顔を覚えたりすると、より深いコミュニケーションプログラムを作ることができます。それでは、これらの機能を使ったプログラムを作成してみましょう。また、併せて本ソフトウェア及びjava言語の「変数」を使ったプログラムについても説明します。



  • ○名前を取得するメソッドを追加する

    本ページのプログラムも、新しいメソッドを追加して作成していきます。クラスウィンドウにメソッドブロックをドラッグ&ドロップし、methodNameを「getName」に変更しましょう。続いて、エクスプローラよりgetNameメソッドをメインメソッドに設定してください。

    image2_047.png



  • ○ロボットに自分の名前を聞き取らせてしゃべらせてみる

    聞き取った言葉から名前だけを認識する場合、名前の取得ブロックを使います。このブロックを使って音声認識を行うと、「私は山田太郎と言います」のような文章の中から「山田」や「太郎」と言った人名だけを認識することができます。

    それでは、ロボットに自分の名前を話しかけて復唱させてみたいと思います。まず、名前の取得ブロックをgetNameメソッドに追加・接続してください。

    image2_048.png

    名前の取得ブロックは分岐構造になっていますが、それぞれの分岐は「名前が取得できた」(上側)、「名前を取得できなかった」(下側)で固定されており、音声認識ブロックのように、各条件に認識したい文字列を設定することができません。認識した人名は speechRecogResult という変数に文字列として代入され、他の命令ブロックよりこの変数を参照する形で利用します。

    image2_049.png

    「変数」とは、何らかの情報を記録しておくための箱のようなものです。これまでのプログラムでも、顔認識における「年齢」や「笑顔の度合い」などを使いましたが、このように実行中に取得した数値を変数に記録しておくことで、後から別のブロックでその内容を参照して処理を行うことができます。

    記録できる情報には文字列や数値などがありますが、各変数には記録できる情報の種類があらかじめ決められています。例えば speechRecogResult は文字列を記録するための変数であり、数字等それ以外の情報は記録できません。

    実はこれまで多用してきた発話ブロックには、「こんにちは」等の決まった文章以外に、変数に記録した文字列を指定することができます。これを使って、名前を取得できたら発話ブロックに 変数speechRecogResult の内容をしゃべらせてみましょう。

    名前の取得ブロックの上側の分岐に発話ブロックを接続し、これまでと同じくsay_wordsをダブルクリックして設定画面を開いてください。画面を開いたら一番上、変数選択のラジオボタン([〇]マーク)をクリックしてください。クリックするとその隣のリストボックスが操作できるようになるので、右端のプルダウンボタン([▼]マーク)をクリックしてください。

    表示されたプルダウンボタンをクリックすると、ブロックで使用できる変数が一覧表示されます。この中から speechRecogResult をクリックしてください。

    image2_050.png

    これで、発話ブロックは変数speechRecogResult に記録された情報をしゃべるようになります。名前の取得が成功すれば必ず speechRecogResult に人名が入るので、これで取得した名前を発話できます。

    プログラムを作成したら実行してみましょう。ロボットの目が水色になって音声認識を開始したら、「私は○○です」のように人名を含む文章を話しかけてみて、ロボットがその中の人名だけを返答するか確認してみてください。

    名前によっては認識しづらい場合があるので、上手く認識しない場合は「山田」など比較的一般的な名前で試してみてください。



    このように、変数を利用することで、ロボットの動作を柔軟に変化させたり、様々なブロックで同じ情報を共有したりすることができます。



  • ○変数を使って名前を文章に組み込む

    ここまでのプログラムで、名前を変数に取得してしゃべらせることには成功しましたが、speechRecogResult には名前しか記録されていないので、「あなたの名前は○○です」のような文章を発話できません。人名の発話ブロックの前後に「あなたの名前は」と「です」という発話ブロックを追加すれば文章をしゃべりますが、各発話ブロックに不自然な「間」ができてしまいます。

    きれいな発音にするためには、「あなたの名前は」と speechRecogResult と「です」の三つの文字列をくっつけて一つの文章を作る必要があります。このように、複数の情報を加算したりする場合、変数の「演算」を利用します。それでは、次の手順で、新しく変数を作り名前を含む文章を加算していきましょう。


    まず、発話させる文章を記録しておく変数を一つ作成します。変数の作成は、変数宣言ブロックを使います。変数宣言ブロックをドラッグ&ドロップし、発話ブロックの前につないでください。

    ブロックをつないだらクリックして設定項目を表示してください。変数宣言ブロックの設定項目では、変数の名前(name)・変数の型(type)・初期値(initParam)をそれぞれ設定します。

    変数の名前には、他に存在する変数と重複しない名前を付けます。ここでは「speechText」と命名してください。

    変数の型は、先に説明した「その変数が記録できる情報の種類」です。文字列を扱う型は「String」なので、typeの項目は「String」を選択してください。

    初期値は、作成する変数に最初に記憶させる内容を設定します。ここでは名前の前に来る「あなたの名前は」を(定数:String)の欄に入力してください。

    image2_051.png



    次に、変数の演算によって、 speechText に、取得した人名と語尾(「です」)を加算します。変数の演算には、演算ブロックを使用します。変数宣言ブロックの後ろに演算ブロックを追加・接続してください。

    image2_052.png


    演算ブロックは、任意の変数に値を記憶させたり、変数の現在値に対する演算を行うことができます。演算の概要は変数の型によって異なり、数値型の場合は四則演算、文字列型の場合は文字列同士の結合が可能です。

    ブロックの設定項目には、演算する変数(left)・演算方法(ccalc)・演算に使用する定数及び変数(right)があります。ここでは先ほど作成したString型の変数speechTextに、同じくString型の変数speechRecogResultを結合します。left及びrightの(変数選択)欄には、前者にspeechTextを、後者にspeechRecogResultを、それぞれ設定してください。また、ccalcは「+=」を設定してください。

    image2_053.png

    この設定により、speechText("あなたの名前は") + speechRecogResult("○○") という文字列の結合が行われます。

    最後に、変数speechTextに語尾「です。」を追加します。先程設定した演算ブロックの後ろに、もう一つ演算ブロックを追加・接続してください。

    追加したらブロックの設定を表示してください。こちらの演算も先程と同様に 変数speechText に文章を加算します。両者の違いは、加算する内容が 変数(speechRecogResult)か定数(「です」)かと言う点のみです。そのため、「left」には「speechText」、「ccalc」には「+=」をそれぞれ設定し、「right」には「定数:String」で「です。」と設定してください。

    image2_054.png

    以上の2回の演算で、変数speechTextに人名を含む文章が完成します。続いて発話ブロックのwordも「変数選択」で 変数speechTextに変更して、作成した文章が発話されるようにしましょう。

    image2_055.png

    ここまで作成したらプログラムを実行してみてください。先ほどと同じくロボットに自分の名前を話しかけ、「あなたの名前は○○です。」とロボットが返せば正しくプログラムを作成できています。

    文字列の一部しかしゃべらない場合は、演算ブロックのccalcの設定が「=」のままになっている可能性があります。また、ビルドエラーが出る場合、ccalcの設定がおかしい、または変数の初期値設定や演算ブロックのrightの項目の設定が間違っている可能性があります。


    ちなみに、変数を使わずに、発話ブロックだけで一度に2つ分の演算をすることも可能です。

    say_wordsの設定画面の「自由入力」には、javaのソースに出力する直接を記述できます。発話ブロックは、プログラムソース上ではロボットに発話させる引数にString型の引数を一つ持ったメソッドを呼び出しており、say_wordsの内容がその引数に使われます。

    java言語の仕様では、引数に演算を含む文字列を与えることが可能なので、say_wordsの設定で「自由入力」をクリックして、隣の入力欄に「"君の名前は"+speechRecogResult+"です。"」と記述すると、変数宣言や演算ブロックを使わずに、名前を含む文章を作成しつつ発話させられます。

    image2_063.png

    ただし、自由入力は便利な反面、java言語の仕様を理解していないとビルドエラーが発生するなどして、プログラムが正しく実行できなくなってしまいます。そのリスクや難しさを十分理解した上で使用してください。







  • ○ロボットに顔を覚えさせてみる

    次に、顔認識の「顔の特徴取得」の機能を利用して、自分の顔と名前をロボットに覚えさせてみましょう。今回のプログラムは、未登録の顔の場合のみ名前を聞いて登録し、既に登録済み顔の場合は登録された名前をしゃべるようにします。

    顔の特徴取得は、顔追従(検出)の最中でのみ行うことができます。まずは、過去のチュートリアルを参考に、新しいメソッドで以下のように顔追従のプログラムを作成してください。

    image2_057.png

追加したメソッドの名前はgetFaceに変更し、エクスプローラからメインメソッドに切り替えてください。

次に、顔が見つかったらその特徴検出を行う処理を作ります。顔が見つかったか?の上側の分岐(見つかった)に、ツールボックスより顔の特徴検出のブロックを追加・接続してください。

image3_012.png



次に、特徴検出ブロックの上側の分岐に「登録された顔か」ブロックを接続し、登録済みの顔かどうかの分岐を作ります。

image3_013.png


「登録された顔か」のブロックは、上側の分岐が登録された(知っている)顔である場合、下側の分岐がそうでない(登録されていない)場合にそれぞれあたります。上側の分岐に発話ブロックを追加し、saywordを 変数GlobalVariable.facename に設定すれば、とりあえず名前をしゃべらせることは可能ですが、できれば名前取得で行ったように、一つ変数を作り、名前を含んだ文章を喋るようにしてみましょう。

image3_014.png



以上で登録された顔が見つかった場合の分岐は作成完了です。続いて、未登録の顔の場合に新しく名前を聞いて登録する処理を作成します。

顔の登録処理の注意点として、見つかった顔の認識精度が低いと登録できないという点があります。これは、精度が低い情報で顔を登録すると、別の人との間違いが多発するためであり、顔を極力正面向きで大きめに写す必要があります。

ロボットの動作環境によっては、品質の良い画像を取得しづらい場合があるため、プログラム内でループを組んで、登録できるまで顔の画像を撮り続ける構造にします。この処理は比較的規模が大きくなるため、別のメソッドに分けて作成します。

まずは新しくメソッドブロックをプログラムに追加し、名前を「getUser」にしてください。メソッドを追加したら、「登録された顔か」の下側の分岐(未登録の顔)にメソッド呼び出しブロックを接続してください。

image3_015.png



それでは、getUserメソッド内に「顔が登録できるまでの特徴取得を繰り返す」という処理を作成していきましょう。

まずはforブロックを追加して繰り返し構造を作ります。forブロックは無限ループと異なり、主に回数を指定した繰り返しを行います。もし顔の特徴を取得する前に人がいなくなってしまった場合などのために、登録するまで無限に繰り返さずに、一定回数で終わるようにします。

image3_016.png


forブロックの「loop」の項目が繰り返し回数を表します。今回は繰り返し回数を50回に設定しましょう。

image3_017.png




続いて、顔の特徴取得の仕組みとして、特徴量は「顔の特徴の取得」ブロックで取得しますが、その元になる情報は「顔が見つかったか」ブロックで取得されます。そのため、この二つのブロックをforブロック内に接続してください。

image3_018.png


続いて「顔の登録(エラー付き)」ブロックをプログラムに追加しましょう。このブロックは取得した特徴を元に顔の登録を行い、登録できたかどうかで分岐します。また、登録できなかった場合、ロボットにその原因をしゃべらせます。

image3_019.png


「顔の登録(エラー付き)」ブロックの設定項目は以下の通りです。






次に、顔が見つかったらその特徴検出を行う処理を作ります。顔が見つかったか?の上側の分岐(見つかった)に、ツールボックスより顔の特徴検出のブロックを追加・接続してください。

image2_058.png

このブロックは、顔認識の機能で見つかった顔に関する特徴を取得し、変数faceuserに代入します。また、見つかった顔がロボットに登録されている顔と一致した場合、その名前を変数GlobalVariable.facenameに代入します。

また、ブロックは分岐構造となっており、顔の特徴を取得できたら上側、ブロックの実行時点で顔が検出できず特徴が取得できなかった場合は下側の分岐に、それぞれ進みます。顔が見つかった後のプログラムはこの後作成するので、ここは見つからなかった場合の分岐に発話ブロックを一つ追加し、「顔が見つからなかったよ」としゃべらせましょう。

image2_058_2.png




次に、見つかった顔が登録済みかどうかを判断し、登録済みの顔であればその名前をしゃべる処理を作成します。見つかった顔が登録済みかどうかは「登録された顔か」のブロックを使います。ツールボックスよりこのブロックをドラッグ&ドロップし、顔の特徴検出ブロックの上側の分岐に接続してください。

image2_059.png


「登録された顔か」のブロックは、上側の分岐が登録された(知っている)顔である場合、下側の分岐がそうでない(登録されていない)場合にそれぞれあたります。上側の分岐に発話ブロックを追加し、saywordを 変数GlobalVariable.facename に設定すれば、とりあえず名前をしゃべらせることは可能ですが、できれば名前取得で行ったように、一つ変数を作り、名前を含んだ文章を喋るようにしてみましょう。

image2_060.png




次に、知らない顔の場合に名前を聞いて登録する処理を作ります。ここでは、本ページ冒頭で作成した名前の取得メソッド(getName)を改造して、聞き取った名前を登録するように変えてみます。

まずはエクスプローラより getNameメソッドをドラッグ&ドロップし、「登録された顔か」の下側の分岐(未登録の顔である)に接続してください。

image2_061.png





次はgetNameメソッドの中を修正していきます。まずメソッドの最初に「あなたの名前は?」と発話させましょう。名前が取得できたら「あなたは○○さんだね」と言った後に、取得した名前と顔情報(特徴)をロボットに登録します。

顔の登録処理には、「顔の登録」ブロックを使用します。ブロックには二つの分岐が備わっており、顔の特徴がしっかり取得できて登録に成功したら上の分岐に、取得した顔の特徴が良くない(はっきり見えない・顔が遠い等)ため登録に失敗したら下の分岐に、それぞれ進みます。また、登録する際の人の名前をusernameという項目に設定します。

今回のプログラムでは、usernameには、名前の取得ブロックによって人名が記録された 変数speechRecogResult を選択してください。また、各分岐に一つずつ発話ブロックを追加し、上側の分岐(登録成功)には「覚えたよ」、下側の分岐(登録失敗)には「もうちょっとよく顔を見せて」としゃべらせましょう。

最後に、名前が取得できなかった場合の下側の分岐にも発話ブロックを追加し、「ごめんなさい、聞き取れなかったよ」としゃべらせましょう。

image2_062.png





以上で、顔を覚えるプログラムの完成です。プログラムを実行して動作確認してみましょう。最初は自分の顔がロボットに登録されていないため、顔と名前を登録する処理に必ず進みます。そして、一度顔を登録したら、次に顔が見つかった際に、ちゃんと登録時の名前で「○○さんだね」と発話するか確認してみましょう。

ちなみに、覚えた顔を個別に削除する場合は登録した顔の削除ブロックを使います。この時、削除する人の名前を使うので、顔の特徴の取得や名前の取得を使って、消す人の名前をプログラムから取得しましょう。

また、登録した顔をすべて削除する場合は、登録した顔のクリアブロックを使います。


ロボットは、個人の識別精度を高めるため、しっかり顔だけを登録するように制限を掛けており、顔の登録を行う場合、ロボットに対して30cm程度の距離で、真正面からまっすぐ顔を見せる必要があります。

顔が傾いている(かしげ・頷き・横向き)、距離が遠い・近すぎる(見切れている)等の場合、しっかり顔が見えていないとみなされて、顔の登録に失敗します。登録に失敗すると、コンソールウィンドウにその原因が表示されます。以下のメッセージを参考に、登録に失敗した理由をご確認ください。

  • [Error][CRoboCamera]Out of Range Angle Yaw
    • 顔が横を向きすぎている
  • [Error][CRoboCamera]Out of Range Angle Roll
    • 首を傾げきすぎている
  • [Error][CRoboCamera]Out of Range Angle Pitch
    • 顔が上・下を向きすぎている
  • [Error][CRoboCamera]Out of Range Face Size
    • 顔が遠すぎる
  • [Error][CRoboCamera]Low FocusScore