Mobile Vision API - 连接新的探测器对象以继续帧处理

Lxu*_*Lxu 17 android google-vision

我想使用视觉API提供的新面部检测功能以及应用程序中的其他帧处理.为此,我需要访问由面部检测器处理的相机框架,并使用面部检测数据连接处理器.

正如我在示例中看到的,CameraSource抽象了检测和摄像头访问,我无法访问正在处理的帧.是否有如何在此API中获取相机框架的示例,或者,可能创建并连接接收它的检测器?那至少可能吗?

谢谢,卢西奥

pm0*_*464 22

对的,这是可能的.您需要创建自己的Detector子类,它包装FaceDetector并在detect方法中执行额外的帧处理代码.它看起来像这样:

class MyFaceDetector extends Detector<Face> {
  private Detector<Face> mDelegate;

  MyFaceDetector(Detector<Face> delegate) {
    mDelegate = delegate;
  }

  public SparseArray<Face> detect(Frame frame) {
    // *** add your custom frame processing code here
    return mDelegate.detect(frame);
  }

  public boolean isOperational() {
    return mDelegate.isOperational();
  }

  public boolean setFocus(int id) {
    return mDelegate.setFocus(id);
  }
}
Run Code Online (Sandbox Code Playgroud)

你将你的课程包裹在脸部探测器上,并将你的课程传递到相机源.它看起来像这样:

    FaceDetector faceDetector = new FaceDetector.Builder(context)
            .build();
    MyFaceDetector myFaceDetector = new MyFaceDetector(faceDetector);

    myFaceDetector.setProcessor(/* include your processor here */);

    mCameraSource = new CameraSource.Builder(context, myFaceDetector)
            .build();
Run Code Online (Sandbox Code Playgroud)

首先使用原始帧数据调用检测器.

请注意,如果旋转设备,图像可能不是直立的.您可以通过框架的metadata.getRotation方法获取方向.

需要注意的一点是:一旦检测方法返回,就不应该访问帧像素数据.由于相机源会回收图像缓冲区,因此一旦方法返回,帧对象的内容将最终被覆盖.

编辑:(附加说明)您还可以避免MyFaceDetector使用MultiDetector的样板代码,如下所示:

MultiDetector multiDetector = new MultiDetector.Builder()
    .add(new FaceDetector.Builder(context)
                .build())
    .add(new YourReallyOwnDetector())
    .build();
Run Code Online (Sandbox Code Playgroud)

还要注意FaceTrackerFactoryMultiProcessor 那里描述的结合使用.


MCR*_*MCR 18

这是我决定采用的最终解决方案.它假定框在屏幕上居中.

public class BoxDetector extends Detector {
    private Detector mDelegate;
    private int mBoxWidth, mBoxHeight;

    public BoxDetector(Detector delegate, int boxWidth, int boxHeight) {
        mDelegate = delegate;
        mBoxWidth = boxWidth;
        mBoxHeight = boxHeight;
    }

    public SparseArray detect(Frame frame) {
        int width = frame.getMetadata().getWidth();
        int height = frame.getMetadata().getHeight();
        int right = (width / 2) + (mBoxHeight / 2);
        int left = (width / 2) - (mBoxHeight / 2);
        int bottom = (height / 2) + (mBoxWidth / 2);
        int top = (height / 2) - (mBoxWidth / 2);

        YuvImage yuvImage = new YuvImage(frame.getGrayscaleImageData().array(), ImageFormat.NV21, width, height, null);
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(left, top, right, bottom), 100, byteArrayOutputStream);
        byte[] jpegArray = byteArrayOutputStream.toByteArray();
        Bitmap bitmap = BitmapFactory.decodeByteArray(jpegArray, 0, jpegArray.length);

        Frame croppedFrame =
                new Frame.Builder()
                        .setBitmap(bitmap)
                        .setRotation(frame.getMetadata().getRotation())
                        .build();

        return mDelegate.detect(croppedFrame);
    }

    public boolean isOperational() {
        return mDelegate.isOperational();
    }

    public boolean setFocus(int id) {
        return mDelegate.setFocus(id);
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样在你的探测器中包装这个类

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BoxDetector boxDetector = new BoxDetector(barcodeDetector, heightPx, widthPx);
Run Code Online (Sandbox Code Playgroud)