如何操作相机预览? [英] How can I manipulate the camera preview?

查看:13
本文介绍了如何操作相机预览?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有几个教程解释了如何在 Android 设备上启动和运行简单的相机预览.但我找不到任何示例来解释如何在图像被渲染之前对其进行操作.
我想要做的是实现自定义滤色器来模拟例如红色和/或绿色缺陷.

There are several tutorials out there which explain how to get a simple camera preview up and running on an android device. But i couldn't find any example which explains how to manipulate the image before it's being rendered.
What I want to do is implementing custom color filters to simulate e.g. red and/or green deficiency.

推荐答案

我对此做了一些研究,并整理了一个工作(ish)示例.这是我发现的.从相机中获取原始数据非常容易.它作为 YUV 字节数组返回.您需要手动将其绘制到表面上才能对其进行修改.为此,您需要有一个可以手动运行绘图调用的 SurfaceView.您可以设置几个标志来完成此操作.

I did some research on this and put together a working(ish) example. Here's what I found. It's pretty easy to get the raw data coming off of the camera. It's returned as a YUV byte array. You'd need to draw it manually onto a surface in order to be able to modify it. To do that you'd need to have a SurfaceView that you can manually run draw calls with. There are a couple of flags you can set that accomplish that.

为了手动进行绘图调用,您需要将字节数组转换为某种位图.此时位图和 BitmapDecoder 似乎不能很好地处理 YUV 字节数组.已经为此提交了一个错误,但不要不知道该状态是什么.所以人们一直在尝试自己将字节数组解码成RGB格式.

In order to do the draw call manually you'd need to convert the byte array into a bitmap of some sort. Bitmaps and the BitmapDecoder don't seem to handle the YUV byte array very well at this point. There's been a bug filed for this but don't don't what the status is on that. So people have been trying to decode the byte array into an RGB format themselves.

似乎手动进行解码有点慢,人们已经取得了不同程度的成功.像这样的事情可能真的应该在 NDK 级别使用本机代码来完成.

Seems like doing the decoding manually has been kinda slow and people have had various degrees of success with it. Something like this should probably really be done with native code at the NDK level.

仍然可以让它工作.另外,我的小演示只是我花了几个小时一起破解东西(我想这样做让我的想象力有点过分了;)).因此,通过一些调整,您可能会大大改善我已经设法开始工作的内容.

Still, it is possible to get it working. Also, my little demo is just me spending a couple of hours hacking stuff together (I guess doing this caught my imagination a little too much ;)). So chances are with some tweaking you could much improve what I've managed to get working.

这个小代码片段还包含我发现的其他一些宝石.如果您想要的只是能够在表面上绘图,您可以覆盖表面的 onDraw 函数 - 您可能会分析返回的相机图像并绘制叠加层 - 这比尝试处理每一帧要快得多.另外,我更改了 SurfaceHolder.SURFACE_TYPE_NORMAL ,如果您希望显示相机预览,则需要使用它.因此,对代码进行了一些更改 - 注释掉的代码:

This little code snip contains a couple of other gems I found as well. If all you want is to be able to draw over the surface you can override the surface's onDraw function - you could potentially analyze the returned camera image and draw an overlay - it'd be much faster than trying to process every frame. Also, I changed the SurfaceHolder.SURFACE_TYPE_NORMAL from what would be needed if you wanted a camera preview to show up. So a couple of changes to the code - the commented out code:

//try { mCamera.setPreviewDisplay(holder); } catch (IOException e)
//  { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); }

还有:

SurfaceHolder.SURFACE_TYPE_NORMAL //SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS - for preview to work

应该允许您将基于相机预览的帧叠加在真实预览之上.

Should allow you to overlay frames based on the camera preview on top of the real preview.

无论如何,这是一段工作代码 - 应该可以让您开始.

Anyway, here's a working piece of code - Should give you something to start with.

只需在您的一个视图中添加一行代码,如下所示:

Just put a line of code in one of your views like this:

<pathtocustomview.MySurfaceView android:id="@+id/surface_camera"
    android:layout_width="fill_parent" android:layout_height="10dip"
    android:layout_weight="1">
</pathtocustomview.MySurfaceView>

并将此类包含在您的源代码中的某处:

And include this class in your source somewhere:

package pathtocustomview;

import java.io.IOException;
import java.nio.Buffer;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.hardware.Camera;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;

public class MySurfaceView extends SurfaceView implements Callback,
    Camera.PreviewCallback {

    private SurfaceHolder mHolder;

    private Camera mCamera;
    private boolean isPreviewRunning = false;
    private byte [] rgbbuffer = new byte[256 * 256];
    private int [] rgbints = new int[256 * 256];

    protected final Paint rectanglePaint = new Paint();

    public MySurfaceView(Context context, AttributeSet attrs) {
    super(context, attrs);
        rectanglePaint.setARGB(100, 200, 0, 0);
        rectanglePaint.setStyle(Paint.Style.FILL);
        rectanglePaint.setStrokeWidth(2);

        mHolder = getHolder();
        mHolder.addCallback(this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_NORMAL);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawRect(new Rect((int) Math.random() * 100,
            (int) Math.random() * 100, 200, 200), rectanglePaint);
        Log.w(this.getClass().getName(), "On Draw Called");
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
    }

    public void surfaceCreated(SurfaceHolder holder) {
        synchronized (this) {
            this.setWillNotDraw(false); // This allows us to make our own draw
                                    // calls to this canvas

            mCamera = Camera.open();

            Camera.Parameters p = mCamera.getParameters();
            p.setPreviewSize(240, 160);
            mCamera.setParameters(p);


            //try { mCamera.setPreviewDisplay(holder); } catch (IOException e)
            //  { Log.e("Camera", "mCamera.setPreviewDisplay(holder);"); }

            mCamera.startPreview();
            mCamera.setPreviewCallback(this);

        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        synchronized (this) {
            try {
                if (mCamera != null) {
                    mCamera.stopPreview();
                    isPreviewRunning = false;
                    mCamera.release();
                }
            } catch (Exception e) {
                Log.e("Camera", e.getMessage());
            }
        }
    }

    public void onPreviewFrame(byte[] data, Camera camera) {
        Log.d("Camera", "Got a camera frame");

        Canvas c = null;

        if(mHolder == null){
            return;
        }

        try {
            synchronized (mHolder) {
                c = mHolder.lockCanvas(null);

                // Do your drawing here
                // So this data value you're getting back is formatted in YUV format and you can't do much
                // with it until you convert it to rgb
                int bwCounter=0;
                int yuvsCounter=0;
                for (int y=0;y<160;y++) {
                    System.arraycopy(data, yuvsCounter, rgbbuffer, bwCounter, 240);
                    yuvsCounter=yuvsCounter+240;
                    bwCounter=bwCounter+256;
                }

                for(int i = 0; i < rgbints.length; i++){
                    rgbints[i] = (int)rgbbuffer[i];
                }

                //decodeYUV(rgbbuffer, data, 100, 100);
                c.drawBitmap(rgbints, 0, 256, 0, 0, 256, 256, false, new Paint());

                Log.d("SOMETHING", "Got Bitmap");

            }
        } finally {
            // do this in a finally so that if an exception is thrown
            // during the above, we don't leave the Surface in an
            // inconsistent state
            if (c != null) {
                mHolder.unlockCanvasAndPost(c);
            }
        }
    }
}

这篇关于如何操作相机预览?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆