减慢摄像机对象的setPreviewCallback方法

时间:2011-05-06 09:07:24

标签: java android callback camera

我在相机对象(mCamera)上运行以下代码,以检测相机指向的面部。问题是虽然这个过程确实非常快,但它会减慢应用程序的其余部分,即当我在按下按钮执行某些操作时,这个面部检测正在运行时,需要大约半秒才能注册它。我的想法是,我以某种方式放慢速度或减少它在一定时间内回拨的次数,然后按下这个按钮会更快:

Thread thread = new Thread(new Runnable() {
    public void run() {
        // TODO Auto-generated method stub
        mCamera.setPreviewCallback(new PreviewCallback() {
            public void onPreviewFrame(final byte[] _data, Camera _camera) {
                Camera.Parameters parameters = mCamera.getParameters();
                int format = parameters.getPreviewFormat();
                // YUV formats require more conversion
                if (format == ImageFormat.NV21) {
                    int w = parameters.getPreviewSize().width;
                    int h = parameters.getPreviewSize().height;
                    // Get the YuV image
                    YuvImage yuv_image = new YuvImage(_data, format, w, h, null);
                    // Convert YuV to Jpeg
                    Rect rect = new Rect(5 * w / 10, 1 * h / 5, 8 * w / 10, 4 * h / 5);
                    final ByteArrayOutputStream output_stream = new ByteArrayOutputStream();
                    yuv_image.compressToJpeg(rect, 10, output_stream);
                    // Convert from Jpeg to Bitmap
                    Bitmap bmp = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(output_stream.toByteArray(), 0, output_stream.size()), 3 * w / 10, 3 * h / 5, true);
                    detectFaces(bmp, w, h);
                }
            }
        });
    }
});
thread.start();

它已经在线程中,因为我认为这可能会有所帮助,但事实并非如此。无论如何都要改变回叫频率?

4 个答案:

答案 0 :(得分:2)

我已经完成了一些实时进行人脸检测的工作,这里有一些我在学习过程中学到的东西:

  • API面部检测器速度的最大贡献因素是被检查图像的大小。您可以考虑使用最小的合理的Camera.getSupportedPreviewSizes()来帮助加快速度。请注意,预览大小和图片大小是独立的参数,因此您不必牺牲捕获的图片质量,除非您要将预览框保存为捕获。
  • 此外,如果有任何方法可以假设面应该在框架的某个边界区域内,则可以通过将预览框架裁剪到这些边界然后将该位图交给面部检测器来获得一些性能。
  • 避免在循环中对处理预览帧的新对象进行任何分配。需要进行的分配和最终垃圾收集会花费大量时间。使用单身人士,静力学或成员变量来保留你可以重复使用的东西,而不是分配新东西。
  • 最后,一旦你尽可能地执行它,可以考虑限制线程不要尝试处理每一帧,但可能每隔几秒处理一次。添加一个名为mLastFrameAnalzedTime的成员var到您的线程类。存储上次成功解码/检测int的时间,然后每次获得新帧时,检查是否有足够的时间来处理下一个帧。

希望其中一些有用。

答案 1 :(得分:0)

您可以尝试在Thread.sleep()方法中插入一些onPreviewFrame调用,以便代码的其他部分也获得一些cpu时间。上面的代码看起来可能会占用onPreview代码中几乎所有的cpu时间。

您可能需要玩睡眠时间,因为太多睡眠会使预览速度降低。

答案 2 :(得分:0)

您可以查看setOneShotPreviewCallback

答案 3 :(得分:0)

请查看以下Camera.Parameters方法的文档

getSupportedPreviewFpsRange getPreviewFpsRange setPreviewFpsRange

在我的Nexus上,我有3种可能的预览FPS 最小15fps,最大15fps 最小15fps,最大30fps 最小24fps,最大30fps

注意: getSupportedPreviewFpsRange的返回值缩放1000 - 我不明白为什么。

我不确定这是否有效,因为我测量了两次调用onPreviewFrame之间的时间,而且我得到了fps 1000 ....也许我的测量中存在错误。

Android Offical Doc on Camera.Parameters