Android,操纵相机预览帧

发布于 2024-11-17 00:51:47 字数 1925 浏览 4 评论 0原文

我想制作一个使用相机并在预览帧上应用图像处理滤镜的 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 方法中执行什么操作,我都看不到模拟器发生任何变化。

I want to make an Android application that uses the camera and applies image processing filters on the preview frames.

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

However, I see no changes in the emulator no matter what I do in the onPreviewFrame method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鼻尖触碰 2024-11-24 00:51:47

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

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

它是开源开放计算机视觉项目的 NDK 端口,它将获取原始预览帧并允许使用 OpenCV 对其进行处理,然后再将其显示在 SurfaceView 上。因为它操纵帧,所以它运行的帧速率与直接挂钩硬件优化预览的帧速率不同,但因为它的大部分内容是本机的,所以它做得非常好。

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

Another option is to use the OpenCV framework, which has an Android port:

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

It's an NDK port of the open source Open Computer Vision project, and it'll take raw preview frames and allow for processing them with OpenCV before displaying them on a SurfaceView. Because it manipulates the frames it doesn't run at quite the same framerate as just a directly hooked in hardware optimized preview, but because so much of it is native it does a pretty good job.

There's an OpenCV_Sample app in that version linked above which compiled into a demo app which can do much of what you're looking for. It has menu options to enable inverse, blur the image, or do edge detection on the preview area. Even if it's not exactly what you want, there are some great samples in the source code to learn from.

眼角的笑意。 2024-11-24 00:51:47

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

我不知道如何做到这一点,但我一直在考虑如何解决这个问题,这是我认为应该做的事情 -

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

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

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

Well that's because the preview buffers that you are getting in the callback is only a copy of the preview buffers, hence any modifications that you do will not be displayed since the buffer that you get is your copy. Mentioned in the android sdk here

I am not sure how to do this but I have been giving it some thought on how to go about this and here is what I think should be done -

  • Register for the preview buffers
  • Disable the default preview display
    • If you don't set the preview display to a surface then you should not get any display (but I am not sure if it will work - had read it in some forum not able to recall the source)
    • If the above doesn't work then we will have to hide the view (I know hardly efficient but I couldn't think of anything else..)
  • Reduce the framerate of the preview, so that we will not be overwhelmed with buffers
  • Now to display our buffers, we can either use the default bitmap draw functionality or use opengl to display buffers. But I have so far used neither so don't even know if it is feasible, any thoughts on the same?

UPDATE
Revisiting the SDK documentation I found this API - setPreviewTexture this API allows us to - "captures frames from an image stream as an OpenGL ES texture". Once you have the images with the applied texture you can use OpenGL to display your frames. (Take a look at the answer posted by @Stephan on how to do this.)

NOTE - setPreviewTexture is available from API level 11 onwards! SDK Link

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文