2015年2月27日金曜日

[OPC]顔認識の話

顔認識のAPIはあるんだけど、なんか突っかかったっていう話

■解決しました
SDK自体のバグでした。
SDK Ver1.1から治ります。

■顔認識API
開発のヒント>開発のガイドライン Android カテゴリー3に書いてある。
  OLYCameraStatusListener#onUpdateStatus()
  通知されるステータス名:DetectedHumanFaces
  getterメソッド:Map<String, RectF> getDetectedHumanFaces()
    ⇒戻り値内のRectFはビューファインダー座標系

■開発トピックス
・戻り値をライブビューに表示するときは、ライブビュー座標系に変換する
 convertRectOnViewfinderIntoLiveImage
・ライブビューにRect表示させるときは、オフセット値を加算する
 CameraLiveImageView#drawImage内の以下処理がオフセット値になる。
centerX - halfWidth;
centerY - halfHeight;
・CameraLiveImageView#drawFocusFrameを使えばあっさり矩形表示可能

こんな感じ



--------ここから下は旧SDKの話-----------
■顔認識の使い方
顔認識の取得結果はgetDetectedHumanFaces()で取れるけど、
使い方で必要と噂されているのは、2つ。

①getDetectedHumanFaces()の更新契機
開発のヒント>開発のガイドライン Android カテゴリー3に書いてある。
  OLYCameraStatusListener#onUpdateStatus()
  通知されるステータス名:DetectedHumanFaces
  getterメソッド:getDetectedHumanFaces()
 ★いくら待ってもDetectedHumanFacesなんて来ない

②前提条件
ドキュメント(Android)>プロパティリスト
 プロパティ:顔検出 
 プロパティ名:FACE_SCAN
 プロパティ値:FACE_SCAN_ON or FACE_SCAN_NEAR
 対応する撮影モード:iAuto以外OK
 ★設定はできてると思う。



■結局、実動作はというと
・onUpdateLiveViewでgetDetectedHumanFacesログだししたら一応取得できてた
・ただし戻り値のMap<String, Rect>に、8個常時詰まってる
・認識してないときのRectの値は左上(0,0,0,0)
・で、左上×8とか詰まってる★バグ?
・使い方の①で言った通り、通知が来ない。★バグ?
・前提条件でFACE_SCANをONにしないととかいう話だが、設定値関係なく取得できる
 ⇒前提条件意味なし!!
・というわけで前提条件の設定は正直効いてないとおもう。★バグ?
・もちろんiAutoでもgetDetectedHumanFacesでの顔認識可能

なんかもう、前提条件なんて意味ないし、
通知なくても取得はできるし。
自作通知クラス作れるんでないか?

■自作顔認識通知クラス
ここに置いとく
ポーリングして、状態変化したら通知してくれる。
Map<String, Rect>の中身も整形して渡す。
やることは2つ。
①リスナ登録
private DetectedHumanFacesManager mFace = new DetectedHumanFacesManager( 
  new DetectedHumanFacesManager.UpdateListener() {
 
 @Override
 public void onUpdateDetectedHumanFaces(OLYCamera camera, Map faces) {
  //変更があったらこれが呼ばれる
 }
});

②ポーリング
OLYCameraLiveViewListener#onUpdateLiveViewに実装するのがおすすめ。
@Override
public void onUpdateLiveView(OLYCamera camera, byte[] data, Map metadata) {
 mFace.onUpdateLiveView(camera);//これ追加
 imageView.setImageData(data, metadata);
}

これをアレンジして、
顔認識したところに緑枠つけるテスト
座標変換しないとイケなさそうだけど勉強中ということでここまで。



みんながんばれ

--------ここから下はメモ----
基本的にこんな流れだと思ってる
1.撮影モードに移行
2.iAuto以外の状態にする
3.FACE_SCANプロパティセット
4.onUpdateStatusで”DetectedHumanFaces”が来るのを待つ
5.getDetectedHumanFaces()で顔認識結果ゲット!


ImageCaputerSampleのLiveViewFragmentをいじる。
なんで、1,2はすっ飛ばす。
3.FACE_SCANプロパティセット
private static final String CAMERA_PROPERTY_FACE_SCAN = "FACE_SCAN";
private void setFaceScanOn(){
 int which = 1;
 final String propertyName = CAMERA_PROPERTY_FACE_SCAN;
 String beforeState=null;
 String setState = null;
 String afterState = null;
 try {
  beforeState = camera.getCameraPropertyValue(propertyName);
 } catch (OLYCameraKitException e1) {
  // TODO Auto-generated catch block
  e1.printStackTrace();
 }
 
 final List<String> valueList;
 try {
  valueList = camera.getCameraPropertyValueList(propertyName);

  if (valueList == null || valueList.size() == 0) return;

  if(camera.canSetCameraProperty(propertyName)){

   Log.e("LiveViewFragment","set " + propertyName + " " + valueList.get(which));
   setState = valueList.get(which);
   camera.setCameraPropertyValue(propertyName, setState);
   afterState = camera.getCameraPropertyValue(propertyName);
  }
 } catch (OLYCameraKitException e) {
  e.printStackTrace();
  return;
 }
 final String sBeforeState= beforeState!=null ? beforeState:"" ;
 final String sSetState = setState!=null ? setState:"";
 final String sAfterState = afterState!=null ? afterState:"";
 runOnUiThread(new Runnable() {
  @Override
  public void run() {
   Toast.makeText(getActivity(), "FaceScan before: "+ sBeforeState + "\n" +
     "setstate: " + sSetState + "\n" +
     "afterstate: " + sAfterState
      , Toast.LENGTH_SHORT).show();
  }
 });
}

顔認証が対応する撮影モードはiAuto以外。
これはWBと一緒。
WBの設定使って、WB変更しようとしたらsetFaceScanOn()を呼ぶようにする
 @Override
 public void onClick(View v) {
         //省略
  } else if (v == whiteBalanceImageView) {
   whiteBalanceImageViewDidTap();

   setFaceScanOn();
  } else if (v == settingImageView) {

4.onUpdateStatusで”DetectedHumanFaces”が来るのを待つ
 @Override
 public void onUpdateStatus(OLYCamera camera, final String name) {
                //省略
  } else if(name.equals("DetectedHumanFaces")){
                    //作ったメソッド呼ぶ
      UpdateDetectedHumanFaces();
  }


5.getDetectedHumanFaces()で顔認識結果ゲット!
 protected void UpdateDetectedHumanFaces() {
  final Map humanFace = camera.getDetectedHumanFaces();
  Log.e("LiveViewFragment","UpdateHumanFaces size" + humanFace.size() + " " + humanFace.toString());
  
  Toast.makeText(getActivity(), "UpdateHumanFaces size" + humanFace.size() + " " + humanFace.toString(), Toast.LENGTH_SHORT).show();
 }


これでいいと思ってるんだが、できぬ

1 件のコメント: