1

現在、アプリケーションは Snapdragon SDK を正常に実行しています。互換性のあるデバイスの数を増やすために、プロジェクトに Vision 8.3.0 の FaceDetector を実装しようとしています。特定の機能を提供するためにカスタム カメラ + サーフェスに依存しているため、CameraSource は使用できません。できるだけ多くのコードを再利用したいと考えており、Snapdragon SDK は現在の実装で驚くほどうまく機能しています。

ワークフローは次のとおりです。

1) カメラのプレビューを取得する

2) 入力バイト配列をビットマップに変換します (何らかの理由で、ByteBuffers を操作できませんでした。画像サイズ、回転、および NV21 画像フォーマットが提供され、検証されましたが、顔が見つかりませんでした)。Bitmap は、割り当てによる速度低下を避けるために、処理スレッド内で既に初期化されているグローバル変数です。

3) receiveFrame を介したフィード検出器

これまでの結果は十分ではありません。ランドマークと分類を無効にしていても、検出は遅すぎて (2 ~ 3 秒) 不正確です。

問題は、前者を使用せずに CameraSource + Detector のパフォーマンスを複製することは可能ですか? ライブ入力で動作させるために CameraSource を使用することは必須ですか?

前もって感謝します!

編集

以下の pm0733464 の推奨事項に従って、Bitmap の代わりに ByteBuffer を使用しようとしています。これは私が従う手順です:

// Initialize variables
// Mat is part of opencvSDK
Mat currentFrame = new Mat(cameraPreviewHeight + cameraPreviewHeight / 2, cameraPreviewWidth, CvType.CV_8UC1);
Mat yuvMat = new Mat(cameraPreviewHeight + cameraPreviewHeight / 2, cameraPreviewWidth, CvType.CV_8UC1);

// Load current frame
yuvMat.put(0, 0, data);

// Convert the frame to gray for better processing
Imgproc.cvtColor(yuvMat, currentFrame, Imgproc.COLOR_YUV420sp2RGB);
Imgproc.cvtColor(currentFrame, currentFrame, Imgproc.COLOR_BGR2GRAY); 

ここから、バイト配列の作成:

// Initialize grayscale byte array
byte[] grayscaleBytes = new byte[data.length];

// Extract grayscale data
currentFrame.get(0, 0, grayscaleBytes);

// Allocate ByteBuffer
ByteBuffer buffer = ByteBuffer.allocateDirect(grayscaleBytes.length);

// Wrap grayscale byte array
buffer.wrap(grayscaleBytes);

// Create frame
// rotation is calculated before
Frame currentGoogleFrame = new Frame.Builder().setImageData(buffer, currentFrame.cols(), currentFrame.rows(), ImageFormat.NV21).setRotation(rotation).build();

この方法でフレームを構築すると、面が見つかりません。ただし、ビットマップを使用すると、期待どおりに機能します。

if(bitmap == null) {
    // Bitmap allocation
    bitmap = Bitmap.createBitmap(currentFrame.cols(), currentFrame.rows(), Bitmap.Config.ARGB_8888);
}

// Copy grayscale contents
org.opencv.android.Utils.matToBitmap(currentFrame, bitmap);

// Scale down to improve performance
Matrix scaleMatrix = new Matrix();
scaleMatrix.postScale(scaleFactor, scaleFactor);

// Recycle before creating scaleBitmap
if(scaledBitmap != null) {
    scaledBitmap.recycle();
}

// Generate scaled bitmap
scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), rotationMatrix, true);

// Create frame
// The same rotation as before is still used
if(scaledBitmap != null) {
    Frame currentGoogleFrame = new Frame.Builder().setBitmap(scaledBitmap).setRotation(rotation).build();
}
4

1 に答える 1

4

検出に 2 ~ 3 秒かかることは一般的ではありません。最高のパフォーマンスを得るために CameraSource を使用する必要はありません どのハードウェアを使用していますか? 詳細を教えていただけますか?

顔検出のいくつかの側面は、速度と精度のトレードオフです。

スピード:

  1. 可能であれば、解像度の低い画像を使用してみてください。たとえば、顔検出は 640x480 で正常に機能するはずです。顔検出器のコードは、検出を実行する前に大きな画像をダウンサンプリングしますが、解像度の低いオリジナルを受け取る場合に比べて時間がかかります。

  2. Bitmaps ではなく ByteBuffers を使用すると、少し速くなります。この最初の部分は単なるグレースケール画像 (色情報なし) である必要があります。

  3. 上で述べたように、ランドマークと分類を無効にすると高速になります。

  4. 将来のリリースでは、「顔の最小サイズ」オプションが追加される予定です。最小サイズを大きく設定すると、顔検出が高速になります (小さな顔を検出しないという精度のトレードオフがあります)。

  5. モードを「高速」に設定すると、高速になります (正面以外の顔を検出しないという精度のトレードオフがあります)。

  6. 「目立つ顔のみ」オプションを使用すると高速になりますが、1 つの大きな顔 (画像の幅の少なくとも 35%) しか検出されません。

正確さ:

  1. ランドマークを有効にすると、ポーズ角度をより正確に計算できます。

  2. モードを「正確」に設定すると、より広い範囲の角度で顔が検出されます (横顔の顔など)。ただし、これにはさらに時間がかかります。

  3. 上記の「顔の最小サイズ」オプションがないため、デフォルトでは、画像の幅の 10% を超える顔のみが検出されます。それより小さい顔は検出されません。今後、この設定を変更すると、より小さな顔を検出するのに役立ちます。ただし、小さい顔の検出には時間がかかることに注意してください。

  4. 高解像度の画像を使用すると、低解像度の画像よりも正確になります。たとえば、320x240 の画像では、画像が 640x480 の場合に検出されたはずの一部の顔が見逃される可能性があります。設定する「最小顔サイズ」が小さいほど、そのサイズの顔を検出するために必要な解像度が高くなります。

  5. 回転が正しいことを確認してください。たとえば、顔が上下逆の場合、顔は検出されません。逆さまの顔を検出する場合は、回転した画像で顔検出器を再度呼び出す必要があります。

また、大量のビットマップを作成している場合は、ガベージ コレクション時間が要因になる可能性があります。ByteBuffer を使用する利点は、イメージごとにビットマップを使用した場合に発生するイメージごとの GC オーバーヘッドを発生させることなく、同じバッファーを繰り返し再利用できることです。CameraSource は少数のバッファしか使用しないため、この利点があります。

于 2015-12-08T16:17:07.023 に答える