相机卡在Android应用程序中

时间:2013-06-05 13:38:27

标签: android opencv camera

我开发了一个Android项目,在其中我使用了YUV420帧并使用opencv librarires将它们转换为灰度。然后最终使用相机表面上的位图创建灰度图像。 一段时间后,应用程序停止接收帧。我甚至将帧速率降低到15.

    package com.example;

import org.opencv.android.Utils;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;

import android.graphics.Bitmap;
import android.graphics.Canvas;
//import android.graphics.drawable.BitmapDrawable;
import android.hardware.Camera;
import android.hardware.Camera.Size;
import android.util.Log;
import android.view.SurfaceHolder;
import android.hardware.Camera.Parameters;

public class Preview  extends CameraDemo implements SurfaceHolder.Callback,Camera.PreviewCallback

{//Class Starts
    public Camera mCamera;  //Camera Object
    private int PreviewSizeWidth;   //Width of preview size
    private int PreviewSizeHeight; //Height of Preview Size
    private static final String TAG = "Preview";
    public boolean drawStatus = true;
    SurfaceHolder mHolder;

//Constructor to set preview size width and height
public Preview(int width, int height)
{
    PreviewSizeWidth = width;
    PreviewSizeHeight = height;
    Log.i(TAG, "Instantiated new Preview");
}

//Override onpreviewFrame method of camera.previewcallback
@Override
public void onPreviewFrame(byte[] arg0, Camera arg1)
{
    Log.i(TAG, "Frame is Received +++++");
    Bitmap bmp = processFrame(arg0);
            if (bmp != null) {
        draw(bmp);
            }
            bmp.recycle();
    Log.i(TAG, "Frame is Processed");

}

//Called when surface is changed
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) 
{

    Log.i(TAG, "Surface Changed");
        Parameters parameters;
    parameters = mCamera.getParameters();
    Size size = parameters.getPreviewSize();


    PreviewSizeWidth = size.width;
    PreviewSizeHeight = size.height;
    parameters.setPreviewSize(PreviewSizeWidth, PreviewSizeHeight);
    parameters.setPreviewFrameRate(15);
            mCamera.setParameters(parameters);
    mCamera.startPreview();
}

//Called when surface is created
@Override
public void surfaceCreated(SurfaceHolder arg0) {
    mHolder = arg0;
    Log.i(TAG, "Surface Created");
    mCamera = Camera.open();
            mCamera.setPreviewCallback(this);
    Log.i(TAG, "Surface Created Successfully");
}

//Called when surface is destroyed
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
    //mHolder = arg0;
    Log.i(TAG, "Surface Destroyed");
            mCamera.setPreviewCallback(null);
    mCamera.stopPreview();
    mCamera.release();
    mCamera = null;
    Log.i(TAG, "Surface Destroyed Exit");

}


//Process Frame Data
protected Bitmap processFrame(byte[] data)
{
    Log.i(TAG, "Frame is Processing");
    Mat mYUV = new Mat(PreviewSizeHeight + PreviewSizeHeight/2,    PreviewSizeWidth, CvType.CV_8UC1);
    mYUV.put(0, 0, data);

    Mat mRgba = new Mat();
    Mat mGray = new Mat();
    Imgproc.cvtColor(mYUV, mRgba, Imgproc.COLOR_YUV2GRAY_NV21, 3);
    Imgproc.cvtColor(mGray, mRgba, Imgproc.COLOR_GRAY2RGB, 0);
    Bitmap mBitmap = Bitmap.createBitmap(PreviewSizeWidth,PreviewSizeHeight, Bitmap.Config.ARGB_8888);
     try {
            Utils.matToBitmap(mRgba, mBitmap);
        } catch(Exception e) {
            Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
            mBitmap.recycle();
            mBitmap = null;
        }
     mRgba.release();
     mGray.release();
     mYUV.release();
    return mBitmap;
}

//For drawing bitmap
public void draw(Bitmap bmp){

    Canvas canvas = mHolder.lockCanvas();
            if (canvas != null) {
                 Log.i(TAG, "Drawing Canvas");
                     canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
                                }
            else{
                Log.i(TAG, "Canvas is null");
                }
            mHolder.unlockCanvasAndPost(canvas);
}



}//CameraPreview Class ends

注意:我能够在屏幕上看到灰色图像,但在某些帧后它没有显示。

1 个答案:

答案 0 :(得分:0)

主线程无法处理图像处理并在表面上创建位图。因此,我创建了另一个线程,它将在表面上处理和创建位图。输入帧将存储在缓冲区中。 将mCamera.setPreviewCallback(this)更改为mCamera.setPreviewCallbackWithBuffer(this)