移动视觉API - 连接新的检测器对象以继续帧处理

19

我想在应用程序中使用视觉API提供的新面部检测功能,并结合额外的帧处理。为此,我需要访问经人脸检测器处理的相机帧,并使用检测到的人脸数据连接处理器。

正如我在示例中所看到的,CameraSource抽象了检测和相机访问,我无法访问正在处理的帧。这个API中有没有获取相机帧的示例,或者创建并连接一个接收相机帧的检测器?至少有可能吗?

谢谢, Lucio

3个回答

23

是的,这是可能的。您需要创建自己的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);
  }
}

您需要将人脸检测器与您的类一起包装,并将您的类传入相机源。代码大致如下:

    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();

您的检测器将首先使用原始帧数据进行调用。

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

一个警告:一旦detect方法返回,您就不应该访问帧像素数据。由于相机源重复使用图像缓冲区,一旦方法返回,帧对象的内容最终将被覆盖。

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

MultiDetector multiDetector = new MultiDetector.Builder()
    .add(new FaceDetector.Builder(context)
                .build())
    .add(new YourReallyOwnDetector())
    .build();

还需要注意在那里描述了与MultiProcessor一起使用的FaceTrackerFactory的用法。


不知道这个怎么还能让你裁剪图像。框架出现了,你可以编辑它,但是Frame是私有的,没有setBitMap... - JPM
@JPM 你可能需要使用Frame.Builder()创建一个新的Frame,并使用setBitmap(Bitmap image)或setImageData(ByteBuffer data, int width, int height, int format)将裁剪后的位图设置到其中。所有参数都可以直接从输入帧或帧元数据中获取。 - user1689757

22

这是我最终确定的解决方案。它假设盒子在屏幕中心。

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);
    }
}

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

BarcodeDetector barcodeDetector = new BarcodeDetector.Builder(context).build();
BoxDetector boxDetector = new BoxDetector(barcodeDetector, heightPx, widthPx);

@saturov 我应该如何使用detect函数?我应该传递什么框架?我已经创建了BoxDetector:new BoxDetector(barcodeDetector, cameraView.getHeight()/3, cameraView.getWidth()); 当我调用boxDetector.detect时,我不知道要传递什么框架。 - mikro098
1
如何使用boxDetector? - upward
如何使用Sparsearray仅检测脸部框? - DoctorWho
我正在将这段代码转换为 Kotlin。请分享所有的导入。 - Faizan Haidar Khan
有任何确切的解决方案吗? - Ashmeet Arora
显示剩余2条评论

1
根据用户(新开发人员)的要求,如何设置框探测器。您可以使用@MCR BoxDetector类,然后按照以下步骤操作。我只是提供有关文本识别器的示例,所以您可以像这样设置。
TextRecognizer mTextRecognizer = new TextRecognizer.Builder(getApplicationContext()).build();
BoxDetector boxDetector = new BoxDetector(mTextRecognizer, heightPx, widthPx);

在此设置boxDetecotr。
boxDetector.setProcessor(new Detector.Processor<TextBlock>() {
                @Override
                public void release() {

                }

                @Override
                public void receiveDetections(Detector.Detections<TextBlock> detections) {
                    SparseArray<TextBlock> items = detections.getDetectedItems();
                    StringBuilder stringBuilder = new StringBuilder();
                    for (int i = 0; i < items.size(); ++i) {
                        TextBlock item = items.valueAt(i);
                        if (item != null && item.getValue() != null) {
                            stringBuilder.append(item.getValue() + " ");
                        }
                    }

                    final String fullText = stringBuilder.toString();
                    Handler handler = new Handler(Looper.getMainLooper());
                    handler.post(new Runnable() {
                        public void run() {
                            // here full string(fullText) you can get whatever is it scanned.
                        }
                    });

                }
            });

1
你好,我遇到了异常检测器处理器必须先使用setProcessor设置才能接收检测结果的问题。 - Alan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接