2016-05-11 5 views
1

ライブカメラのプレビューで顔を検出し、Googleが提供するplay-services-visionライブラリを使用してランドマークにいくつかのGIFを描画するコードがあります。play-services-vision:顔検出速度とカメラプレビュー速度をどのように同期させますか?

顔が静的である場合は十分に機能しますが、顔が適度な速度で動く場合、顔検出器は顔の新しい位置のランドマークを検出するためにカメラのフレームレートよりも時間がかかります。私はそれがビットマップ描画速度と関係があるかもしれないことを知っていますが、私はそれらの遅れを最小限に抑えるために措置を講じました。

(基本的に私はGIFを 『十分になめらかな再配置ではない』という苦情を取得)

編集:私は座標検出コードを取得しようとしなかった...

List<Landmark> landmarksList = face.getLandmarks(); 
    for(int i = 0; i < landmarksList.size(); i++) 
    { 
     Landmark current = landmarksList.get(i); 
     //canvas.drawCircle(translateX(current.getPosition().x), translateY(current.getPosition().y), FACE_POSITION_RADIUS, mFacePositionPaint); 
     //canvas.drawCircle(current.getPosition().x, current.getPosition().y, FACE_POSITION_RADIUS, mFacePositionPaint); 
     if(current.getType() == Landmark.LEFT_EYE) 
     { 
      //Log.i("current_landmark", "l_eye"); 
      leftEyeX = translateX(current.getPosition().x); 
      leftEyeY = translateY(current.getPosition().y); 
     } 
     if(current.getType() == Landmark.RIGHT_EYE) 
     { 
      //Log.i("current_landmark", "r_eye"); 
      rightEyeX = translateX(current.getPosition().x); 
      rightEyeY = translateY(current.getPosition().y); 
     } 
     if(current.getType() == Landmark.NOSE_BASE) 
     { 
      //Log.i("current_landmark", "n_base"); 
      noseBaseY = translateY(current.getPosition().y); 
      noseBaseX = translateX(current.getPosition().x); 
     } 
     if(current.getType() == Landmark.BOTTOM_MOUTH) { 
      botMouthY = translateY(current.getPosition().y); 
      botMouthX = translateX(current.getPosition().x); 
      //Log.i("current_landmark", "b_mouth "+translateX(current.getPosition().x)+" "+translateY(current.getPosition().y)); 
     } 
     if(current.getType() == Landmark.LEFT_MOUTH) { 
      leftMouthY = translateY(current.getPosition().y); 
      leftMouthX = translateX(current.getPosition().x); 
      //Log.i("current_landmark", "l_mouth "+translateX(current.getPosition().x)+" "+translateY(current.getPosition().y)); 
     } 
     if(current.getType() == Landmark.RIGHT_MOUTH) { 
      rightMouthY = translateY(current.getPosition().y); 
      rightMouthX = translateX(current.getPosition().x); 
      //Log.i("current_landmark", "l_mouth "+translateX(current.getPosition().x)+" "+translateY(current.getPosition().y)); 
     } 
    } 
    eyeDistance = (float)Math.sqrt(Math.pow((double) Math.abs(rightEyeX - leftEyeX), 2) + Math.pow(Math.abs(rightEyeY - leftEyeY), 2)); 
    eyeCenterX = (rightEyeX + leftEyeX)/2; 
    eyeCenterY = (rightEyeY + leftEyeY)/2; 
    noseToMouthDist = (float)Math.sqrt(Math.pow((double)Math.abs(leftMouthX - noseBaseX), 2) + Math.pow(Math.abs(leftMouthY - noseBaseY), 2)); 

...でView描画メソッド内の別のスレッドですが、SIGSEGVエラーが表示されます。

私の質問は:

  1. は、カメラのプレビューフレームレート、この場合に行うには正しいもので、顔検出器の処理速度を同期されるか、あるいはそれが他の方法で回避され、またはそれはいくつかの他の方法は何ですか?
  2. カメラのプレビューフレームで顔検出器が顔を検出すると、FDが終了する前にプレビューが供給するフレームをドロップする必要がありますか?もしそうなら、どうしたらいいですか?
  3. カメラのプレビューでsetClassificationMode(NO_CLASSIFICATIONS)setTrackingEnabled(false)を使用するだけで、検出が高速になるはずですか?
  4. play-services-visionライブラリはOpenCVを使用していますが、どちらが実際に優れていますか?

EDIT 2:

私は1本​​の研究論文を読んでOpenCVの顔検出と高速アンドロイドであり、それらのより高い処理能力にOpenCVのに利用可能な他の機能を使用しています、。私はそれを利用して顔検出を早めることができるかどうか疑問に思っていました。

+0

この問題でお手伝いできますか? https://stackoverflow.com/questions/45141098/google-vision-drawing-mask-on-face-with-animations –

答えて

0

頭の動きが中程度であっても目に見える遅延が見られないほど速くなることを保証する方法はありません。あなたの開発デバイスでその地獄を最適化することに成功したとしても、そこには何千ものモデルの中から別のモデルが見つかるでしょう。それは遅すぎます。

あなたのコードは、このような状況に耐えられるはずです。スムーズに動くと仮定して、1秒前に顔の位置を予測することができます。ユーザーが頭やデバイスをつまむことに決めた場合、アルゴリズムは役に立たない。

推奨されないCamera APIを使用する場合は、バッファを事前に割り当ててsetPreviewCallbackWithBuffer()を使用する必要があります。この方法で、フレームが一度に1つずつ画像プロセッサに到着することを保証することができます。 open the Camera on a background threadも忘れてはならないので、重い画像処理が行われる[onPreviewFrame()](http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html#onPreviewFrame(byte[]、android.hardware.Camera))コールバックはUIスレッドをブロックしません。

  • はい、OpenCVの顔検出が高速になる場合もありますが、もっと重要なことに、Google顔検出器より堅牢です。
  • はい、笑顔と目を気にしない場合は、分類をオフにする方が良いです。パフォーマンスの向上は異なる場合があります。
  • 私は、トラッキングをオフにするとGoogle顔検出器の動作が遅くなると思っていますが、自分で測定して最適な方法を選択する必要があります。
  • setProminentFaceOnly()をオンにすると最も大きな利得が得られますが、この設定のデバイスへの実際の影響を予測することはできません。
+0

私は第2段落で言及した場所予測の作業に取り組んでいます。どのように機能するのですか?現在の顔の位置と以前の反復の顔の位置のX座標とY座標の差を求め、2を掛けて現在の顔のX座標とY座標に加算するのと同じくらい簡単ですか? – Gensoukyou1337

+0

私はおそらく放物線の外挿を試みるでしょう:3つの最後の位置を与え、それらを曲線にフィットさせて、将来的にはx、yを30 FPSの割合で計算してください –

+0

これにApacheのコモンズ数学ライブラリを使用できますか? – Gensoukyou1337

0

顔検出器には時間がかかるため、常に遅れが生じます。あなたが結果を描く時には、通常、顔が少し動いているかもしれない将来のフレームにわたってそれを描くでしょう。ここで

は遅れを最小限に抑えるためのいくつかの提案です:

Googleのビジョンライブラリで提供CameraSource実装が自動的にそれはそれができる最善を維持できるように、必要なときに、プレビューのフレームをドロップハンドル。同様のアプローチをアプリに組み込む場合は、このコードのオープンソース版をご覧ください。https://github.com/googlesamples/android-vision/blob/master/visionSamples/barcode-reader/app/src/main/java/com/google/android/gms/samples/vision/barcodereader/ui/camera/CameraSource.java#L1144

320x240などのカメラのプレビュー解像度を下げると、顔検出が高速になります。

1つの顔だけをトラッキングする場合は、setProminentFaceOnly()オプションを使用すると、顔検出が高速になります。これとLargestFaceFocusingProcessorを使用すると、これをさらに高速化できます。

LargestFaceFocusingProcessorを使用するには、顔検出器のプロセッサとして設定します。例:

Tracker<Face> tracker = *your face tracker implementation* 
detector.setProcessor(
    new LargestFaceFocusingProcessor.Builder(detector, tracker).build()); 

トラッカーの実装では、最初に検出された最大の顔のみの顔の更新を受け取ります。さらに、検出器には、その顔が見える限り、その顔を追跡する必要があるだけであることが信号で伝えられます。

小さい顔を検出する必要がない場合は、setMinFaceSize()を大きくすると顔検出が高速になります。小さな顔を探すのに時間を費やす必要がないので、大きな顔だけを検出する方が速いです。

目を開けたり、笑顔を表示する必要がない場合は、分類を切り替えることができます。しかし、これはあなたに小さなスピードの利点を与えるだけです。

トラッキングオプションを使用すると、これも速くなりますが、精度はいくらかかかります。これは、すべてのフレームでフル・フェース検出を実行する費用を回避するために、いくつかの中間フレームに予測アルゴリズムを使用します。

+0

LargestFaceFocusingProcessorをどのように構築すればよいですか? – Gensoukyou1337

+0

上記のLargestFaceFocusingProcessorにもう少し追加しました。 – pm0733464

関連する問題