播放服务视觉:如何将人脸检测速度与相机预览速度同步



我有一些代码,可以在实时相机预览中检测人脸,并使用谷歌提供的播放服务视觉库在其地标上绘制一些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 draw方法中的一个单独线程中,但它只会给我一个SIGSEGV错误。

我的问题:

  1. 在这种情况下,将人脸检测器的处理速度与相机预览帧速率同步是正确的做法吗?还是相反,还是其他方式
  2. 当人脸检测器在相机预览帧中找到人脸时,我应该在FD完成之前放下预览馈送的帧吗?如果是,我该怎么做
  3. 我应该在相机预览中只使用setClassificationMode(NO_CLASSIFICATIONS)setTrackingEnabled(false)来加快检测速度吗
  4. 游戏服务视觉库使用OpenCV吗?哪一个更好

编辑2:

我读过一篇研究论文,使用OpenCV,OpenCV中的人脸检测和其他功能在Android中更快,因为它们的处理能力更高。我想知道我是否可以利用这一点来加快人脸检测。

即使头部运动适中,也无法保证人脸检测足够快,不会显示可见延迟。即使你成功地在你的开发设备上优化了它,你肯定会在成千上万的模型中找到另一个,那太慢了。

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

如果使用已弃用的相机API,则应预先分配缓冲区并使用setPreviewCallbackWithBuffer()。通过这种方式,您可以保证帧一次一帧地到达图像处理器。您也不应该忘记在后台线程上打开相机,这样[onPreviewFrame()](http://developer.android.com/reference/android/hardware/Camera.PreviewCallback.html#onPreviewFrame(byte[],android.hardware.Camera))回调,在这里进行繁重的图像处理,不会阻塞UI线程。

  • 是的,在某些情况下,OpenCV人脸检测可能更快,但更重要的是,它比谷歌人脸检测器更强大
  • 是的,如果你不在乎微笑和睁开眼睛,最好关掉分类器。性能增益可能会有所不同
  • 我相信关闭跟踪只会减慢谷歌人脸检测器的速度,但你应该自己进行测量,并选择最佳策略
  • 打开setProminentFaceOnly()可以获得最显著的增益,但我无法预测此设置对您的设备的实际效果

总会有一些滞后,因为任何人脸检测器都需要一定的时间才能运行。当你绘制结果时,你通常会在未来的一个框架上绘制,在这个框架中,脸可能已经移动了一点。

以下是一些最小化滞后的建议:

谷歌视觉库提供的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()较大的值可以更快地检测人脸。只检测较大的人脸会更快,因为它不需要花时间寻找较小的人脸。

如果你不需要睁开眼睛或微笑,你可以切换分类。然而,这只会给你一个小的速度优势。

使用跟踪选项也会使速度更快,但会以一定的准确性为代价。这对一些中间帧使用了预测算法,以避免在每个帧上运行人脸检测的费用。

最新更新