【问题标题】:Android, manupulate camera preview framesAndroid,操纵相机预览帧
【发布时间】:2011-06-23 17:42:09
【问题描述】:

我想制作一个使用相机并在预览帧上应用图像处理过滤器的 Android 应用程序。

package alex.filter;

import java.io.IOException;

import android.content.Context;
import android.graphics.Canvas;
import android.hardware.Camera;
import android.hardware.Camera.PreviewCallback;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

class Preview extends SurfaceView implements SurfaceHolder.Callback {

    SurfaceHolder mHolder;
    public Camera camera;

    Preview(Context context) {
        super(context);
        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {        
        camera = Camera.open();        

        try {
            camera.setPreviewDisplay(holder);

            camera.setPreviewCallback(new PreviewCallback() {
                public void onPreviewFrame(byte[] data, Camera arg1) {                    
                    for( int i = 0 ; i < data.length ; i ++ ){
                        data[ i] = 0; // or some sirius filter
                    }                                                            
                    Preview.this.invalidate();
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }
        }

    public void surfaceDestroyed(SurfaceHolder holder) {        
        camera.stopPreview();        
        camera = null;
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {        
        Camera.Parameters parameters = camera.getParameters();
        parameters.setPreviewSize(w, h);
        camera.setParameters(parameters);
        camera.startPreview();
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);        
    }
}

但是,无论我在 onPreviewFrame 方法中做什么,模拟器都没有变化。

【问题讨论】:

  • +1,我也想知道是否可以直接操作预览帧。

标签: android preview android-camera


【解决方案1】:

另一种选择是使用具有 Android 端口的 OpenCV 框架:

http://opencv.willowgarage.com/wiki/Android2.3.0

它是开源 Open Computer Vision 项目的 NDK 端口,它将获取原始预览帧,并允许在将它们显示在 SurfaceView 上之前使用 OpenCV 对其进行处理。因为它处理帧,所以它不会以与直接挂钩硬件优化预览完全相同的帧速率运行,但因为它大部分是原生的,所以它做得很好。

在上面链接的那个版本中有一个 OpenCV_Sample 应用程序,它编译成一个演示应用程序,可以完成您正在寻找的大部分工作。它具有启用反转、模糊图像或在预览区域进行边缘检测的菜单选项。即使它不是您想要的,源代码中也有一些很棒的示例可供学习。

【讨论】:

    【解决方案2】:

    这是因为您在回调中获得的预览缓冲区只是预览缓冲区的副本,因此您所做的任何修改都不会显示,因为您获得的缓冲区是您的副本。 android sdk中提到here

    我不知道该怎么做,但我一直在思考如何去做,这就是我认为应该做的事情 -

    • 注册预览缓冲区
    • 禁用默认预览显示
      • 如果您不将预览显示设置为表面,那么您不应该得到任何显示(但我不确定它是否可以工作 - 在某些论坛中阅读过它但无法回忆出源)
      • 如果上述方法不起作用,那么我们将不得不隐藏视图(我知道效率很低,但我想不出其他任何东西..)
    • 降低预览的帧率,这样我们就不会被缓冲区压得喘不过气来
    • 现在要显示我们的缓冲区,我们可以使用默认的位图绘制功能或使用 opengl 来显示缓冲区。但是到目前为止我都没有使用过,所以甚至不知道是否可行,有什么想法吗?

    更新
    重新访问 SDK 文档,我发现了这个 API - setPreviewTexture 这个 API 允许我们 - “从图像流中捕获帧作为 OpenGL ES 纹理”。一旦你有了应用纹理的图像,你就可以使用 OpenGL 来显示你的帧。 (看看@Stephan 发布的关于如何做到这一点的答案。)

    注意 - setPreviewTexture 从 API 级别 11 开始可用! SDK Link

    【讨论】:

    • 我想我可以看到你要去哪里。有没有办法在不使用SurfaceView 的情况下使用SurfaceHolder?如果我们用它来获取预览数据和优化的GLSurfaceView 用于绘制处理后的帧,也许我们可以达到合理的帧速率。
    • 我想我可能已经破解了这个 - 再次浏览相机文档并发现这个 setPreviewTexture 这允许我们“从图像流中捕获帧作为 OpenGL ES 纹理”,我想这个 OpenGL ES 纹理是要走的路。完成后,我们可以再次使用 opengl 来显示帧。 SurfaceTexture
    • 不错!这些东西来自 API 级别 11,所以我没有在文档中看到它。我正在寻找适用于 API 级别 8 的东西,但仍然请将其包含在您的答案中,因为如果没有其他选择,我会奖励您。
    • 我还没有尝试过,所以我不知道它是否也适用于这个,但是尝试看看compatibility package。也许它可以帮助! :)
    猜你喜欢
    • 1970-01-01
    • 2012-02-20
    • 1970-01-01
    • 2013-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多