顔認識+情感識別の多段階識別やってみた。
つまり、多段階識別で異なる識別を連続的に実施するとどうなるか。。。という課題です。
マルチタスクでやるのもいいけど、より複雑な複数タスクをこなす場合や、連続するタスクを処理する場合は、単純な多段階識別もそれなりに使うシーンは多いと思う。
ということで、今回は一番単純な顔識別を実施したあと、その人が笑顔、悲しい顔、真面目顔、そして変顔分類して発話で応答するようなアプリを作ってみた。
コード全体は以下に置きました。
・face_recognition/recognize_vgg16_camera_ohayo_multi.py
やったこと
・学習をどうするか
・多段階識別の構成
・コード解説
・結果
・学習をどうするか
これは、識別の構成とも関係するが、
1.顔識別と情感識別を全て独立なカテゴリとして学習する
2.顔識別後、それぞれの各人の情感識別を学習する
3.そもそも情感識別は共通であると仮定してひとまとめ(ある特定の人物について)に学習する
さすがに、3の特定の人について情感識別をすればすべての人に適用するというのは、無謀なようです。
つまり、あかりんだーすーさんの笑顔、悲しい顔、変顔、真面目顔を学習したものは、ウワンの同様な顔は識別してくれましたが、まゆゆさんだと笑顔が変顔に識別されてしまいました。
ということで、全ての人を一緒に学習するということは考えられますが、これをやってみると実はval_accが0.8程度以上にはならないという現象が発生してしまいました。
※あかりんだーすーさんとまゆゆさんの表情が違いすぎるせいだと思います
ということで、今回は、2としてまゆゆさんとあかりんだーすーさんの情感識別をそれぞれ学習して利用することとしました。
ちなみに、ウワンの情感識別にはあかりんだーすーさんの情感識別を利用しました。
・多段階識別の構成
今回は素直に顔識別―情感識別の順に実施することととしました。
・コード解説
前回からの差分のみ解説します。
顔識別と情感識別は同じ関数で単純にname_listを変更して対応します。
そのために、関数の引数としてmodelとnum_classesをとることとしました。
def yomikomi(model,img,num_classes=3):
if num_classes==4:
name_list=['えがお','へんがお','まじめ','悲しい','セクシー']
else:
name_list=['まゆゆ','あかりんだーすー','ウワン']
model定義は両識別ともvgg16を利用しているので同じ関数を利用し、カテゴリ数とパラメータを変更するだけで実施します。
def model_definition(num_classes = 4,params='params4_model_VGG16L3_i_100.hdf5'):
batch_size = 2
num_classes = num_classes
...
model = Model(input=vgg16.input, output=top_model(vgg16.output))
model.summary()
model.load_weights(params)
return model
出力テキスト部分は以下のとおりです。
txt_parsonに顔識別結果、txt_egaoに情感識別結果を入れて、以下の関数を呼び出すと、「まゆゆさん、笑顔がかわいいね」などと出力してくれます。
※なお、コードには残していますが、今回は情感識別でセクシーは識別できませんでした
この問題は大きな課題を含んでいそうですが今回は議論しません
def egao(txt_parson,txt_egao):
if txt_egao=='えがお':
num0=txt_parson+'さん'+txt_egao+"がかわいいね"
elif txt_egao=='へんがお':
num0=txt_parson+'さん'+txt_egao+"笑っちゃう"
elif txt_egao=='まじめ':
num0=txt_parson+'さん'+txt_egao+"な顔もいいね"
elif txt_egao=='悲しい':
num0=txt_parson+'さん'+"何か"+ txt_egao +"ことでもあったの"
elif txt_egao=='セクシー':
num0=txt_parson+'さん'+txt +"だね"
print(num0)
return num0
以下のとおり、モデル定義を3つとも先に定義し、それを利用して識別します。
txt_parsonを識別してから、txt_egaoを識別します。
そして、その結果をegao関数に渡して、文章に変換後、動画に表示するようにしています。
保存する一枚一枚の画像には識別結果とその確率を表示しています。
def main():
...
model_egao=model_definition(num_classes = 4,params='params4_model_VGG16L3_i_100.hdf5')
model_egao_m=model_definition(num_classes = 4,params='params4m_model_VGG16L3_i_100.hdf5')
model_parson=model_definition(num_classes = 3,params='history_params_model_VGG16L3_i_100.hdf5')
...
while True:
...
if len(facerect) > 0:
#検出した顔を囲む矩形の作成
...
try:
...
txt_parson, preds_parson=yomikomi(model_parson,roi,num_classes=3)
if txt_parson=="まゆゆ":
txt_egao, preds_egao=yomikomi(model_egao_m,roi,num_classes=4)
else:
txt_egao, preds_egao=yomikomi(model_egao,roi,num_classes=4)
print("txt_egao, preds",txt_egao,preds_egao*100 ," %")
print("txt_parson, preds",txt_parson,preds_parson*100 ," %")
txt2=conv.do(txt_parson+txt_egao)
cv2.imwrite(path+"/"+label+"/"+str(sk)+'_'+str(txt2)+'_'+str(int(preds_parson*100))+'_'+str(int(preds_egao*100))+'.jpg', roi)
num0=egao(txt_parson,txt_egao)
text2speak(num0)
txt=txt_parson+txt_egao
#time.sleep(2)
img_pil = Image.fromarray(img) # 配列の各値を8bit(1byte)整数型(0~255)をPIL Imageに変換。
draw = ImageDraw.Draw(img_pil) # drawインスタンスを生成
position = (x, y) # テキスト表示位置
draw.text(position, txt, font = font , fill = (b, g, r, a) ) # drawにテキストを記載 fill:色 BGRA (RGB)
img = np.array(img_pil) # PIL を配列に変換
except:
txt=""
continue
cv2.imshow('test',img)
sk +=1
key = cv2.waitKey(1)&0xff
・結果
今回、やる前は複雑かなと思ったが、それなりにシンプルなコードで実現できた。
しかも、精度は顔認識の精度に依存しているので、カメラ動画の場合は撮影条件に依存して今一つな場合もあるが、保存された画像を見るとほぼ正確に識別できている。
※あかりんだーすーさんをまゆゆさんと間違える場面があるが、。。
ということで、後処理を少し加えればさらに高度な識別まで使えそうである。
一応、今回の動画を以下に貼っておく。
また、おまけに標準出力の出力の一部を掲載する。
まゆゆさん、笑顔がかわいいね♪
※画像をクリックするとYouTube動画につながります
まとめ
・顔識別+情感識別の複数多段階同時識別が出来た
・音声発話もいい感じで発話出来た
・簡単なコードで実現できた
・一部あかりんだーすーさんとまゆゆを間違えたり、悲しい顔と変顔を間違えたりする
・特にセクシー顔(それって何かもだけど)は学習できなかった
おまけ
[1.8295898e-11 1.0000000e+00 1.0952591e-17]
1 あかりんだーすー 1.0
[2.2207530e-10 1.4839285e-08 9.9999988e-01 1.0219372e-07]
2 まじめ 0.9999999
txt_egao, preds まじめ 99.99998807907104 %
txt_parson, preds あかりんだーすー 100.0 %
あかりんだーすーさんまじめな顔もいいね
True
[1.6872643e-06 9.9999833e-01 1.6367013e-13]
1 あかりんだーすー 0.99999833
[1.3149245e-08 9.5771622e-07 9.9999118e-01 7.9103420e-06]
2 まじめ 0.9999912
txt_egao, preds まじめ 99.99911785125732 %
txt_parson, preds あかりんだーすー 99.99983310699463 %
あかりんだーすーさんまじめな顔もいいね
True
[1.0000000e+00 1.8305331e-10 2.5724297e-15]
0 まゆゆ 1.0
[1.0000000e+00 1.6338261e-23 1.1463776e-17 2.0159744e-16]
0 えがお 1.0
txt_egao, preds えがお 100.0 %
txt_parson, preds まゆゆ 100.0 %
まゆゆさんえがおがかわいいね
True
[1.000000e+00 5.385380e-10 8.331351e-15]
0 まゆゆ 1.0
[1.0000000e+00 3.5342270e-27 1.8051102e-23 3.1369254e-20]
0 えがお 1.0
txt_egao, preds えがお 100.0 %
txt_parson, preds まゆゆ 100.0 %
まゆゆさんえがおがかわいいね
True
[1.16494164e-01 8.83491516e-01 1.42974723e-05]
1 あかりんだーすー 0.8834915
[4.6015907e-06 7.4378681e-07 9.9994171e-01 5.2898242e-05]
2 まじめ 0.9999417
txt_egao, preds まじめ 99.99417066574097 %
txt_parson, preds あかりんだーすー 88.34915161132812 %
あかりんだーすーさんまじめな顔もいいね
True
[8.3884561e-01 1.6092020e-01 2.3414938e-04]
0 まゆゆ 0.8388456
[2.1349080e-03 1.8221991e-14 9.9703250e-03 9.8789483e-01]
3 悲しい 0.98789483
txt_egao, preds 悲しい 98.78948330879211 %
txt_parson, preds まゆゆ 83.88456106185913 %
まゆゆさん何か悲しいことでもあったの
True
[1.464050e-11 1.000000e+00 9.205185e-18]
1 あかりんだーすー 1.0
[3.0408808e-05 5.1973975e-01 4.1166630e-01 6.8563491e-02]
1 へんがお 0.51973975
txt_egao, preds へんがお 51.97397470474243 %
txt_parson, preds あかりんだーすー 100.0 %
あかりんだーすーさんへんがお笑っちゃう
True
[1.0999396e-18 1.0000000e+00 5.3678317e-22]
1 あかりんだーすー 1.0
[8.1748376e-06 1.8008234e-01 8.1359076e-01 6.3187331e-03]
2 まじめ 0.81359076
txt_egao, preds まじめ 81.35907649993896 %
txt_parson, preds あかりんだーすー 100.0 %
あかりんだーすーさんまじめな顔もいいね