play-services-vision:如何将人脸检测速度与摄像头预览速度同步?

时间:2016-05-11 04:22:28

标签: android performance camera face-detection

我有一些代码可以让我在实时相机预览中检测到面部,并使用Google提供的play-services-vision库在地标上绘制一些GIF。

当脸部静止时效果很好,但当脸部以中等速度移动时,脸部探测器需要比相机的帧速率更长的时间来检测脸部新位置的地标。我知道它可能与位图绘制速度有关,但我采取措施尽量减少它们的滞后。

(基本上我抱怨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. 将Face Detector的处理速度与Camera Preview相同,在这种情况下框架是正确的事情,还是反过来,还是以其他方式?
  2. 当面部检测器在相机预览框中找到面部时,是否应该在FD完成之前删除预览所提供的帧?如果是这样,我该怎么办?
  3. 我是否应该在相机预览中使用setClassificationMode(NO_CLASSIFICATIONS)setTrackingEnabled(false),以便更快地进行检测?
  4. 播放服务视觉库是否使用OpenCV,哪个更好?
  5. 编辑2:

    我读了一篇研究论文,使用OpenCV,OpenCV中可用的人脸检测和其他功能由于其更高的处理能力而在Android中更快。我想知道我是否可以利用它来加速面部检测。

2 个答案:

答案 0 :(得分:0)

即使头部运动适中,也无法保证面部检测速度足够快,不会出现明显的延迟。即使你成功地在你的开发设备上优化它的地狱,你肯定会找到数千个中的另一个模型,这将太慢。

您的代码应该能够适应这种情况。假设它平稳移动,您可以提前一秒预测面部位置。如果用户决定抽搐他们的头部或设备,没有算法可以提供帮助。

如果您使用已弃用的 Camera API,则应预先分配缓冲区并使用setPreviewCallbackWithBuffer()。这样,您可以保证帧一次一个地到达图像处理器。你也不应该忘记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()可以获得最显着的增益,但我无法预测此设置对您设备的实际影响。

答案 1 :(得分: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)可以更快地进行面部检测。

如果您只跟踪一张脸,则使用setProminentFaceOnly()选项可以更快地进行脸部检测。使用这个和LargestFaceFocusingProcessor也会更快。

要使用LargestFaceFocusingProcessor,请将其设置为面部检测器的处理器。例如:

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

您的智能设备实施将仅接收最初找到的最大面部的面部更新。此外,它会向探测器发出信号,只要它可见,它只需跟踪该面。

如果您不需要检测较小的脸部,则使用较大的setMinFaceSize()会使脸部检测更快。只检测较大的面部会更快,因为它不需要花时间寻找较小的面部。

如果您不需要睁眼或微笑指示,您可以转为分类。但是,这只会给你一个小的速度优势。

使用跟踪选项也可以加快速度,但需要花费一些精确的费用。这对一些中间帧使用预测算法,以避免在每一帧上运行全面检测的费用。