Android:OpenCV:同时使用Camera和CameraBridgeViewBase类,联合使用问题

时间:2014-04-16 01:21:15

标签: java android opencv android-camera

我对Java和Android一般都很陌生,但对C / C ++有一些很好的经验。我试图在同一个应用程序中使用多个类文件和多个Camera API。

我正在尝试构建一个获得全分辨率传感器数据的全景应用程序(我有一个800万像素的Nexus 5)。据我所知和研究,CameraBridgeViewBase类'方法onCameraFrame()基本上对数据进行缩减采样以适合您设备的屏幕分辨率(在我的情况下为1280x960)。因此,我不能将它用于我想要做的事情;我需要使用Java Camera API。

我基本上接受了代码presented here,并重做了几件事来尝试获取完整数据。

主java文件:

package org.opencv.samples.tutorial3;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.JavaCameraView;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Point;
import org.opencv.core.Scalar;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
import org.opencv.android.JavaCameraView;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;

public class Sample3Native extends Activity implements CvCameraViewListener2{
    private static final String TAG = "OCVSample::Activity";

    public static final int VIEW_MODE_RGBA = 0;
    public static final int SAVE_IMAGE_MAT = 1;
    public static final int CAPT_STILL_IM = 2;
    private static int viewMode = VIEW_MODE_RGBA;
//  public static int image_count = 0;
    private MenuItem mStitch;
    private MenuItem mItemCaptureImage;
    private Mat mRgba;
    private Mat mGrayMat;
    private Mat panorama;
    private Mat mtemp;
    private List<Mat> images_to_be_stitched = new ArrayList<Mat>();
    private CameraBridgeViewBase mOpenCvCameraView;
    private long mPrevTime = new Date().getTime();
    private static final int FRAME2GRAB = 10;
    private int mframeNum = 0;
    private static final File tempImageDir = new                          File(Environment.getExternalStorageDirectory() + File.separator + "panoTmpImage");
    private static final File StitchImageDir = new File(Environment.getExternalStorageDirectory()+ File.separator  + "panoStitchIm");
    private static final String mImageName = "im";
    private static final String mImageExt = ".jpeg";
    private long recordStart = new Date().getTime();
    private static final long MAX_VIDEO_INTERVAL_IN_SECONDS = 3 * 1000; // Convert milliseconds to seconds
    //private Sample3NativeCapturer imageCapturer = new Sample3NativeCapturer(getBaseContext(),1);

    //private Sample3Native_imgCapture imageCapturer;
//Had to insert to get it to work..
    public final Handler mHandler = new Handler();
    public 
    // Create runnable for posting
    final Runnable mUpdateResults = new Runnable() {
        public void run() {
            updateResultsInUi();
        }
    };


    private void updateResultsInUi()
    {

    }

    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV loaded successfully");

                //imageCapturer.enableView();
                //imageCapturer.setOnTouchListener( Sample3Native.this);
                // Load native library after(!) OpenCV initialization
                System.loadLibrary("native_sample");

                mOpenCvCameraView.enableView();

            }
                break;
            default: {
                super.onManagerConnected(status);
            }
                break;
            }
        }
    };

    public Sample3Native() {
        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        setContentView(R.layout.tutorial3_surface_view);


        final Button btnVidCapt = (Button) findViewById(R.id.btnVidCapt);
        btnVidCapt.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                startVidCap();
            }
        });

        final Button btnStitch = (Button) findViewById(R.id.btnStitch);
        btnStitch.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                stitchImages();
            }
        });

        final Button btnViewStitchedIm = (Button) findViewById(R.id.btnViewStitchedIm);
        btnViewStitchedIm.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                viewStitchImages();
            }
        });
        //button I may have to modify when capturing an image..
        final Button btnCapStil = (Button) findViewById(R.id.btnCapStil);
        btnCapStil.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                captStillImage();
            }
        });
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.tutorial4_activity_surface_view);
        mOpenCvCameraView.setCvCameraViewListener(this);
//      imageCapturer = (Sample3NativeCapturer) findViewById(R.id.tutorial4_activity_surface_view);
//      imageCapturer.setCvCameraViewListener(this);
    }

    @Override
    public void onPause() {
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
//      if (imageCapturer != null)
//      imageCapturer.disableView();
        super.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this,
                mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
//      if (imageCapturer != null)
//      imageCapturer.disableView();
    }

    public void onCameraViewStarted(int width, int height) {
        mRgba = new Mat(height, width, CvType.CV_8UC3);
        mGrayMat = new Mat(height, width, CvType.CV_8UC1);
        mtemp = new Mat(height, width, CvType.CV_8UC3);
        panorama = new Mat(height, width, CvType.CV_8UC3);
    }

    public void onCameraViewStopped() {
        mRgba.release();
        mGrayMat.release();
        mtemp.release();
        panorama.release();
    }

    public Mat onCameraFrame(CvCameraViewFrame inFrame) {
        Mat inputFrame = inFrame.rgba();
        inputFrame.copyTo(mRgba);
        switch (Sample3Native.viewMode) {
        case Sample3Native.VIEW_MODE_RGBA: {
            Core.putText(mRgba, "Video Mode", new Point(10, 50), 3, 1, new Scalar(255, 0, 0, 255), 2);
            // Update start recordtime until starting recording
        }break;
        case Sample3Native.SAVE_IMAGE_MAT: {
            long curTime = new Date().getTime();
            Core.putText(mRgba, "Record Mode", new Point(10, 50), 3, 1, new Scalar(255, 0, 0, 255), 2);
            long timeDiff = curTime - recordStart;
            Log.i("timeDiff", Long.toString(timeDiff));

            if ( timeDiff < MAX_VIDEO_INTERVAL_IN_SECONDS) {
                if ((mframeNum % FRAME2GRAB) == 0) {
                    saveImageToArray(inputFrame);
                    mframeNum++;
                } 
                else
                    mframeNum++;
            } 
            else
            {
                mframeNum = 0;
                turnOffCapture();
            }
        }break;
        case Sample3Native.CAPT_STILL_IM :
        {
            saveImageToArray(inputFrame);

            //RIGHT HERE IS WHERE I NEED TO MODIFY!  CAPTURE IMAGE
            //WITH THE CAMERA INSTEAD OF USING THE PREVIEW.
            //IF I CAN DO THIS, WE CAN GET AND STITCH FULL-RES IMAGES...
            //Camera.Parameters params = mCamera.getParameters();
//          Mat theImage = imageCapturer.getCapturedImage(1);
//          saveImageToArray(theImage);
            Sample3Native.viewMode = Sample3Native.VIEW_MODE_RGBA;
        }
        }
        return mRgba;
    }

    public void startVidCap() {
        if (Sample3Native.viewMode == Sample3Native.VIEW_MODE_RGBA)
        {
            turnOnCapture();
        }
        else if (Sample3Native.viewMode == Sample3Native.SAVE_IMAGE_MAT)
        {
            turnOffCapture();
        }
    }

    private void turnOffCapture()
    {   
//      Button startVidCapture = (Button) findViewById(R.id.btnVidCapt);
        // Stop Recording
//      startVidCapture.setText("Start Video Capture");
        Sample3Native.viewMode = Sample3Native.VIEW_MODE_RGBA; 
    }

    private void turnOnCapture()
    {
//      Button startVidCapture = (Button) findViewById(R.id.btnVidCapt);
        // Start recording
        Sample3Native.viewMode = Sample3Native.SAVE_IMAGE_MAT; 
//      startVidCapture.setText("Stop Video Capture");
        images_to_be_stitched.clear();
        recordStart = new Date().getTime();

    }

    public void stitchImages() {
        if(!images_to_be_stitched.isEmpty())
        {
            for (int j = 0; j < images_to_be_stitched.size(); j++) {
                writeImage(images_to_be_stitched.get(j), j);
            }
        Log.i("stitchImages", "Done writing 2 disk. Starting stitching " + images_to_be_stitched.size() + " images");
            FindFeatures(images_to_be_stitched.get(0).getNativeObjAddr(),
                    images_to_be_stitched.get(0).getNativeObjAddr(),
                    panorama.getNativeObjAddr(), images_to_be_stitched.size());
        Log.i("stitchImages", "Done stitching. Writing panarama");
            writePano(panorama);

        Log.i("stitchImages", "deleting temp files");

            deleteTmpIm();
        }
    }

    public void captStillImage()
    {
        Sample3Native.viewMode = Sample3Native.CAPT_STILL_IM;

    }

    private String getFullFileName( int num)
    {
        return mImageName + num + mImageExt;
    }

/*  private void writeImage(List<Mat> imList) {
        int counter = 0;
        for (Mat im : imList) {
            String fileName = "/sdcard/im" + counter + ".jpeg";
//          Highgui.imwrite(s, images_to_be_stitched.get(j));
            counter++;
        }
    }
*/  
    private void writeImage(Mat image, int imNum)
    {
        writeImage(image, getFullFileName(imNum));
    }

    private void writeImage(Mat image, String fileName) {
        File createDir = tempImageDir;
        if(!createDir.exists())
            createDir.mkdir();
        Highgui.imwrite(tempImageDir+File.separator + fileName, image);
    }


    private void writePano(Mat image)
    {
        Date dateNow = new  Date();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
        if(!StitchImageDir.exists())
            StitchImageDir.mkdir();
        Highgui.imwrite(StitchImageDir.getPath()+ File.separator + "panoStich"+dateFormat.format(dateNow) +mImageExt, image);

    }

    private void deleteTmpIm()
    {
        File curFile;
        for (int j = 0; j < images_to_be_stitched.size(); j++) {
            curFile = new File(getFullFileName(j));
            curFile.delete();
        }
        images_to_be_stitched.clear();
    }


    public void viewStitchImages() 
    {   
        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("content:" + StitchImageDir.getAbsolutePath()));//media/external/images/media"));
    startActivity(intent);
}

private void saveImageToArray(Mat inputFrame) {
    images_to_be_stitched.add(inputFrame.clone());
}

private int FPS() {
    long curTime = new Date().getTime();
    int FPS = (int) (1000 / (curTime - mPrevTime));
    mPrevTime = curTime;
    return FPS;
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    Log.i(TAG, "called onCreateOptionsMenu");
    mStitch = menu.add("Stitch Images");
    mItemCaptureImage = menu.add("Capture Image");
    return true;

}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);

    return true;
}

// public native void FindFeatures(List<Long> pano_images, Long stitch );
public native void FindFeatures(long image1, long image2, long image3,
        int count);

}

辅助文件(在第一个文件中实例化):

package org.opencv.samples.tutorial3;

import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.opencv.android.JavaCameraView;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.hardware.Camera.PictureCallback;
import android.hardware.Camera.Size;
import android.os.Environment;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.Toast;
import android.hardware.Camera.AutoFocusCallback;
public class Sample3NativeCapturer extends JavaCameraView implements PictureCallback {

    public Sample3NativeCapturer(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public Sample3NativeCapturer(Context context, int camID){
        super(context,camID);
    }

    private static final String TAG = "Sample::Tutorial3View";
    private static int MEDIA_TYPE_IMAGE = 1;
    private int interpBy = 1;
    private Mat theImage;




    public List<String> getEffectList() {

        return mCamera.getParameters().getSupportedColorEffects();
    }

    public boolean isEffectSupported() {
        return (mCamera.getParameters().getColorEffect() != null);
    }

    public String getEffect() {
        return mCamera.getParameters().getColorEffect();
    }

    public void setEffect(String effect) {
        Camera.Parameters params = mCamera.getParameters();
        params.setColorEffect(effect);
        mCamera.setParameters(params);
    }

    public List<Size> getResolutionList() {
        return mCamera.getParameters().getSupportedPreviewSizes();
        //mCamera.getParameters().getSupportedPictureSizes()
    }

    public void setResolution(Size resolution) {
        disconnectCamera();
        mMaxHeight = resolution.height;
        mMaxWidth = resolution.width;
        connectCamera(getWidth(), getHeight());
    }
    //Set CAPTURE resolution (currently only setting preview resolution)
    public void setCaptureResolution(Size resolution){
        Parameters params = mCamera.getParameters();
        params.setPictureSize(resolution.width,resolution.height);
        mCamera.setParameters(params);
    }

    public Size getResolution() {
        return mCamera.getParameters().getPreviewSize();
    }

    public void takePicture() {
        Log.i(TAG, "Taking picture");
        Parameters params = mCamera.getParameters();
        try{
            params.setJpegQuality(100);
            params.setFocusMode(Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
        }finally{}
        mCamera.setParameters(params);
        // Postview and jpeg are sent in the same buffers if the queue is not empty when performing a capture.
        // Clear up buffers to avoid mCamera.takePicture to be stuck because of a memory issue
        mCamera.setPreviewCallback(null);

        // PictureCallback is implemented by the current class

        mCamera.takePicture(null, null, this);
    }

    //@Override
    public void onPictureTaken(byte[] data, Camera camera) {
        Log.i(TAG, "Saving a bitmap to file");
        // The camera preview was automatically stopped. Start it again.
        mCamera.startPreview();
        mCamera.setPreviewCallback(this);

        // Write the image in a file (in jpeg format)
        //File pictureFile = getOutputMediaFile(MEDIA_TYPE_IMAGE);
        try {
            //Now try to convert and save.
            Parameters params = camera.getParameters();
            Size sz = params.getPictureSize();
            Mat raw = new Mat(1, data.length, CvType.CV_8UC1);
            raw.put(0, 0, data);
            theImage = Highgui.imdecode(raw, 0);

        } finally {
            Log.e("PictureDemo", "Exception in photoCallback");
        }

    }

    @SuppressLint("SimpleDateFormat")
    public static File getOutputMediaFile(int type){
        // To be safe, you should check that the SDCard is mounted
        // using Environment.getExternalStorageState() before doing this.

        File mediaStorageDir = new File(Environment.getExternalStoragePublicDirectory(
                  Environment.DIRECTORY_PICTURES), "MyCameraApp");
        // This location works best if you want the created images to be shared
        // between applications and persist after your app has been uninstalled.

        // Create the storage directory if it does not exist
        if (! mediaStorageDir.exists()){
            if (! mediaStorageDir.mkdirs()){
                Log.d("MyCameraApp", "failed to create directory");
                return null;
            }
        }

        // Create a media file name
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        File mediaFile;
        if (type == MEDIA_TYPE_IMAGE){
            mediaFile = new File(mediaStorageDir.getPath() + File.separator +
            "IMG_"+ timeStamp + ".jpg");
        } else {
            return null;
        }

        return mediaFile;
    }


       public Mat getCapturedImage(int interpVal){
           interpBy = interpVal;
           takePicture();
           return theImage;
       }

}

经过调试,我发现问题来自于实例化行中的第二个类

private Sample3NativeCapturer imageCapturer = new Sample3NativeCapturer(getBaseContext(),1);

将上下文和整数作为其设置。如果我把它放在BaseLoaderCallback类中似乎没问题,但如果我把它放在原来的位置,它会崩溃,我甚至无法看到导致调试器崩溃的原因。也许这不是我的问题?

我想知道是否可以使用这种双功能(CameraBridgeViewBase和Camera API),或者我应该尝试将所有内容移植到Camera API?同样,我对Android来说还是一个新手,所以如果有替代解决方案,我宁愿避免使用它。

0 个答案:

没有答案