OpenCV Android - 已捕获的过程映像

时间:2015-12-03 09:21:28

标签: android c++ opencv

我有一个项目,使用OpenCV的CamerabridgeViewBase和另一个检测乒乓球的项目来捕获图像。问题是我无法将这两个项目结合起来。我想要的是捕获实时源,然后返回已经有检测的单个图像。

以下是可以捕获图像并将其存储在图库中的项目类:

public final class MainActivity extends ActionBarActivity
    implements CvCameraViewListener2 {

// A tag for log output.
private static final String TAG =
        MainActivity.class.getSimpleName();

// A key for storing the index of the active camera.
private static final String STATE_CAMERA_INDEX = "cameraIndex";

// A key for storing the index of the active image size.
private static final String STATE_IMAGE_SIZE_INDEX =
        "imageSizeIndex";

// An ID for items in the image size submenu.
private static final int MENU_GROUP_ID_SIZE = 2;

// The index of the active camera.
private int mCameraIndex;

// The index of the active image size.
private int mImageSizeIndex;

// Whether the active camera is front-facing.
// If so, the camera view should be mirrored.
private boolean mIsCameraFrontFacing;

// The number of cameras on the device.
private int mNumCameras;

// The image sizes supported by the active camera.
private List<Size> mSupportedImageSizes;

// The camera view.
private CameraBridgeViewBase mCameraView;

// Whether the next camera frame should be saved as a photo.
private boolean mIsPhotoPending;

// A matrix that is used when saving photos.
private Mat mBgr;

// Whether an asynchronous menu action is in progress.
// If so, menu interaction should be disabled.
private boolean mIsMenuLocked;

// The OpenCV loader callback.
private BaseLoaderCallback mLoaderCallback =
        new BaseLoaderCallback(this) {
            @Override
            public void onManagerConnected(final int status) {
                switch (status) {
                    case LoaderCallbackInterface.SUCCESS:
                        Log.d(TAG, "OpenCV loaded successfully");
                        mCameraView.enableView();
                        //mCameraView.enableFpsMeter();
                        mBgr = new Mat();
                        break;
                    default:
                        super.onManagerConnected(status);
                        break;
                }
            }
        };

// Suppress backward incompatibility errors because we provide
// backward-compatible fallbacks.
@SuppressLint("NewApi")
@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    final Window window = getWindow();
    window.addFlags(
            WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    if (savedInstanceState != null) {
        mCameraIndex = savedInstanceState.getInt(
                STATE_CAMERA_INDEX, 0);
        mImageSizeIndex = savedInstanceState.getInt(
                STATE_IMAGE_SIZE_INDEX, 0);
    } else {
        mCameraIndex = 0;
        mImageSizeIndex = 0;
    }

    final Camera camera;
    if (Build.VERSION.SDK_INT >=
            Build.VERSION_CODES.GINGERBREAD) {
        CameraInfo cameraInfo = new CameraInfo();
        Camera.getCameraInfo(mCameraIndex, cameraInfo);
        mIsCameraFrontFacing =
                (cameraInfo.facing ==
                        CameraInfo.CAMERA_FACING_FRONT);
        mNumCameras = Camera.getNumberOfCameras();
        camera = Camera.open(mCameraIndex);
    } else { // pre-Gingerbread
        // Assume there is only 1 camera and it is rear-facing.
        mIsCameraFrontFacing = false;
        mNumCameras = 1;
        camera = Camera.open();
    }
    final Parameters parameters = camera.getParameters();
    camera.release();
    mSupportedImageSizes =
            parameters.getSupportedPreviewSizes();
    final Size size = mSupportedImageSizes.get(mImageSizeIndex);

    mCameraView = new JavaCameraView(this, mCameraIndex);
    mCameraView.setMaxFrameSize(size.width, size.height);
    mCameraView.setCvCameraViewListener(this);
    setContentView(mCameraView);
}

public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the current camera index.
    savedInstanceState.putInt(STATE_CAMERA_INDEX, mCameraIndex);

    // Save the current image size index.
    savedInstanceState.putInt(STATE_IMAGE_SIZE_INDEX,
            mImageSizeIndex);

    super.onSaveInstanceState(savedInstanceState);
}

// Suppress backward incompatibility errors because we provide
// backward-compatible fallbacks.
@SuppressLint("NewApi")
@Override
public void recreate() {
    if (Build.VERSION.SDK_INT >=
            Build.VERSION_CODES.HONEYCOMB) {
        super.recreate();
    } else {
        finish();
        startActivity(getIntent());
    }
}

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

@Override
public void onResume() {
    super.onResume();
    OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0,
            this, mLoaderCallback);
    mIsMenuLocked = false;
}

@Override
public void onDestroy() {
    if (mCameraView != null) {
        mCameraView.disableView();
    }
    super.onDestroy();
}

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
    getMenuInflater().inflate(R.menu.menu_main, menu);
    if (mNumCameras < 2) {
        // Remove the option to switch cameras, since there is
        // only 1.
        menu.removeItem(R.id.menu_next_camera);
    }
    int numSupportedImageSizes = mSupportedImageSizes.size();
    if (numSupportedImageSizes > 1) {
        final SubMenu sizeSubMenu = menu.addSubMenu(
                R.string.menu_image_size);
        for (int i = 0; i < numSupportedImageSizes; i++) {
            final Size size = mSupportedImageSizes.get(i);
            sizeSubMenu.add(MENU_GROUP_ID_SIZE, i, Menu.NONE,
                    String.format("%dx%d", size.width,
                            size.height));
        }
    }
    return true;
}

// Suppress backward incompatibility errors because we provide
// backward-compatible fallbacks (for recreate).
@SuppressLint("NewApi")
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
    if (mIsMenuLocked) {
        return true;
    }
    if (item.getGroupId() == MENU_GROUP_ID_SIZE) {
        mImageSizeIndex = item.getItemId();
        recreate();

        return true;
    }
    switch (item.getItemId()) {
        case R.id.menu_next_camera:
            mIsMenuLocked = true;

            // With another camera index, recreate the activity.
            mCameraIndex++;
            if (mCameraIndex == mNumCameras) {
                mCameraIndex = 0;
            }
            mImageSizeIndex = 0;
            recreate();

            return true;
        case R.id.menu_take_photo:
            mIsMenuLocked = true;

            // Next frame, take the photo.
            mIsPhotoPending = true;

            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

@Override
public void onCameraViewStarted(final int width,
                                final int height) {
}

@Override
public void onCameraViewStopped() {
}

@Override
public Mat onCameraFrame(final CvCameraViewFrame inputFrame) {
    final Mat rgba = inputFrame.rgba();

    if (mIsPhotoPending) {
        mIsPhotoPending = false;
        takePhoto(rgba);
    }

    if (mIsCameraFrontFacing) {
        // Mirror (horizontally flip) the preview.
        Core.flip(rgba, rgba, 1);
    }

    return rgba;
}

private void takePhoto(final Mat rgba) {

    // Determine the path and metadata for the photo.
    final long currentTimeMillis = System.currentTimeMillis();
    final String appName = getString(R.string.app_name);
    final String galleryPath =
            Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_PICTURES).toString();
    final String albumPath = galleryPath + File.separator +
            appName;
    final String photoPath = albumPath + File.separator +
            currentTimeMillis + LabActivity.PHOTO_FILE_EXTENSION;
    final ContentValues values = new ContentValues();
    values.put(MediaStore.MediaColumns.DATA, photoPath);
    values.put(Images.Media.MIME_TYPE,
            LabActivity.PHOTO_MIME_TYPE);
    values.put(Images.Media.TITLE, appName);
    values.put(Images.Media.DESCRIPTION, appName);
    values.put(Images.Media.DATE_TAKEN, currentTimeMillis);

    // Ensure that the album directory exists.
    File album = new File(albumPath);
    if (!album.isDirectory() && !album.mkdirs()) {
        Log.e(TAG, "Failed to create album directory at " +
                albumPath);
        onTakePhotoFailed();
        return;
    }





    // Try to create the photo.
    Imgproc.cvtColor(rgba, mBgr, Imgproc.COLOR_RGBA2BGR, 3);
    if (!Imgcodecs.imwrite(photoPath, mBgr)) {
        Log.e(TAG, "Failed to save photo to " + photoPath);
        onTakePhotoFailed();
    }
    Log.d(TAG, "Photo saved successfully to " + photoPath);

    // Try to insert the photo into the MediaStore.
    Uri uri;
    try {
        uri = getContentResolver().insert(
                Images.Media.EXTERNAL_CONTENT_URI, values);
    } catch (final Exception e) {
        Log.e(TAG, "Failed to insert photo into MediaStore");
        e.printStackTrace();

        // Since the insertion failed, delete the photo.
        File photo = new File(photoPath);
        if (!photo.delete()) {
            Log.e(TAG, "Failed to delete non-inserted photo");
        }

        onTakePhotoFailed();
        return;
    }

    // Open the photo in LabActivity.
    final Intent intent = new Intent(this, LabActivity.class);
    intent.putExtra(LabActivity.EXTRA_PHOTO_URI, uri);
    intent.putExtra(LabActivity.EXTRA_PHOTO_DATA_PATH,
            photoPath);
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            startActivity(intent);
        }
    });
}

private void onTakePhotoFailed() {
    mIsMenuLocked = false;

    // Show an error message.
    final String errorMessage =
            getString(R.string.photo_error_message);
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(MainActivity.this, errorMessage,
                    Toast.LENGTH_SHORT).show();
        }
    });
}

-

    public final class LabActivity extends ActionBarActivity {

    public static final String PHOTO_FILE_EXTENSION = ".png";
    public static final String PHOTO_MIME_TYPE = "image/png";

    public static final String EXTRA_PHOTO_URI =
            "com.nummist.secondsight.LabActivity.extra.PHOTO_URI";
    public static final String EXTRA_PHOTO_DATA_PATH =
            "com.nummist.secondsight.LabActivity.extra.PHOTO_DATA_PATH";

    private Uri mUri;
    private String mDataPath;

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Intent intent = getIntent();
        mUri = intent.getParcelableExtra(EXTRA_PHOTO_URI);
        mDataPath = intent.getStringExtra(EXTRA_PHOTO_DATA_PATH);

        final ImageView imageView = new ImageView(this);
        imageView.setImageURI(mUri);

        setContentView(imageView);
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        getMenuInflater().inflate(R.menu.activity_lab, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_delete:
                deletePhoto();
                return true;
            case R.id.menu_edit:
                editPhoto();
                return true;
            case R.id.menu_share:
                sharePhoto();
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }

    /*
     * Show a confirmation dialog. On confirmation ("Delete"), the
     * photo is deleted and the activity finishes.
     */
    private void deletePhoto() {
        final AlertDialog.Builder alert = new AlertDialog.Builder(
                LabActivity.this);
        alert.setTitle(R.string.photo_delete_prompt_title);
        alert.setMessage(R.string.photo_delete_prompt_message);
        alert.setCancelable(false);
        alert.setPositiveButton(R.string.delete,
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(final DialogInterface dialog,
                                        final int which) {
                        getContentResolver().delete(
                                Images.Media.EXTERNAL_CONTENT_URI,
                                MediaStore.MediaColumns.DATA + "=?",
                                new String[] { mDataPath });
                        finish();
                    }
                });
        alert.setNegativeButton(android.R.string.cancel, null);
        alert.show();
    }

    /*
     * Show a chooser so that the user may pick an app for editing
     * the photo.
     */
    private void editPhoto() {
        final Intent intent = new Intent(Intent.ACTION_EDIT);
        intent.setDataAndType(mUri, PHOTO_MIME_TYPE);
        startActivity(Intent.createChooser(intent,
                getString(R.string.photo_edit_chooser_title)));
    }

    /*
     * Show a chooser so that the user may pick an app for sending
     * the photo.
     */
    private void sharePhoto() {
        final Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType(PHOTO_MIME_TYPE);
        intent.putExtra(Intent.EXTRA_STREAM, mUri);
        intent.putExtra(Intent.EXTRA_SUBJECT,
                getString(R.string.photo_send_extra_subject));
        intent.putExtra(Intent.EXTRA_TEXT,
                getString(R.string.photo_send_extra_text));
        startActivity(Intent.createChooser(intent,
                getString(R.string.photo_send_chooser_title)));
    }
}

以下是乒乓球检测项目的类别:

    public class MainActivity extends AppCompatActivity {
    private static final String TAG = "ObjTrackActivity";

    private MenuItem mItemPreviewRGBA;
    private MenuItem mItemPreviewTresholded;

    public static boolean bShowTresholded = false;

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

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "onCreate");
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);
        setContentView(new ObjTrackViewer(this));
    }

    public boolean onCreateOptionsMenu(Menu menu){
        Log.i(TAG, "onCreateOptionsMenu");
        mItemPreviewRGBA = menu.add("Preview RGBA");
        mItemPreviewTresholded = menu.add("Preview Thresholded");
        return true;
    }

    public boolean onOptionsItemSelected(MenuItem item){
        Log.i(TAG, "Menu Item selected " + item);
        if (item == mItemPreviewRGBA)
            bShowTresholded = false;
        else if (item == mItemPreviewTresholded)
            bShowTresholded = true;
        return true;
    }
}

-

public class ObjTrackViewer extends SampleViewBase {


    private int mFrameSize;
    private Bitmap mBitmap;
    private int[] mRGBA;

    public ObjTrackViewer(Context context) {
        super(context);
    }

    @Override
    protected void onPreviewStared(int previewWidtd, int previewHeight) {
        mFrameSize = previewWidtd * previewHeight;
        mRGBA = new int[mFrameSize];
        mBitmap = Bitmap.createBitmap(previewWidtd, previewHeight, Bitmap.Config.ARGB_8888);
    }

    @Override
    protected void onPreviewStopped() {
        if(mBitmap != null) {
            mBitmap.recycle();
            mBitmap = null;
        }
        mRGBA = null;


    }

    @Override
    protected Bitmap processFrame(byte[] data) {
        int[] rgba = mRGBA;

        CircleObjectTrack(getFrameWidth(), getFrameHeight(), data, rgba, MainActivity.bShowTresholded);

        Bitmap bmp = mBitmap;
        bmp.setPixels(rgba, 0/* offset */, getFrameWidth() /* stride */, 0, 0, getFrameWidth(), getFrameHeight());
        return bmp;
    }

    public native void CircleObjectTrack(int width, int height, byte yuv[], int[] rgba, boolean debug);

    static {
        System.loadLibrary("objtrack_opencv_jni");
    }
}

-

public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
    private static final String TAG = "Sample::SurfaceView";

    private Camera              mCamera;
    private SurfaceHolder       mHolder;
    private int                 mFrameWidth;
    private int                 mFrameHeight;
    private byte[]              mFrame;
    private boolean             mThreadRun;
    private byte[]              mBuffer;


    public SampleViewBase(Context context) {
        super(context);
        mHolder = getHolder();
        mHolder.addCallback(this);
        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    public int getFrameWidth() {
        return mFrameWidth;
    }

    public int getFrameHeight() {
        return mFrameHeight;
    }

    public void setPreview() throws IOException {
        //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
        //    mCamera.setPreviewTexture( new SurfaceTexture(10) );
        //else
            mCamera.setPreviewDisplay(null);
    }

    public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
        Log.i(TAG, "surfaceCreated");
        if (mCamera != null) {
            Camera.Parameters params = mCamera.getParameters();
            List<Camera.Size> sizes = params.getSupportedPreviewSizes();
            mFrameWidth = width;
            mFrameHeight = height;

            // selecting optimal camera preview size
            {
                int  minDiff = Integer.MAX_VALUE;
                for (Camera.Size size : sizes) {
                    if (Math.abs(size.height - height) < minDiff) {
                        mFrameWidth = size.width;
                        mFrameHeight = size.height;
                        minDiff = Math.abs(size.height - height);
                    }
                }
            }

            params.setPreviewSize(getFrameWidth(), getFrameHeight());

            List<String> FocusModes = params.getSupportedFocusModes();
            if (FocusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO))
            {
                params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
            }

            mCamera.setParameters(params);

            /* Now allocate the buffer */
            params = mCamera.getParameters();
            int size = params.getPreviewSize().width * params.getPreviewSize().height;
            size  = size * ImageFormat.getBitsPerPixel(params.getPreviewFormat()) / 8;
            mBuffer = new byte[size];
            /* The buffer where the current frame will be coppied */
            mFrame = new byte [size];
            mCamera.addCallbackBuffer(mBuffer);

            try {
                setPreview();
            } catch (IOException e) {
                Log.e(TAG, "mCamera.setPreviewDisplay/setPreviewTexture fails: " + e);
            }

            /* Notify that the preview is about to be started and deliver preview size */
            onPreviewStared(params.getPreviewSize().width, params.getPreviewSize().height);

            /* Now we can start a preview */
            mCamera.startPreview();
        }
    }

    public void surfaceCreated(SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated");
        mCamera = Camera.open();

        mCamera.setPreviewCallbackWithBuffer(new PreviewCallback() {
            public void onPreviewFrame(byte[] data, Camera camera) {
                synchronized (SampleViewBase.this) {
                    System.arraycopy(data, 0, mFrame, 0, data.length);
                    SampleViewBase.this.notify(); 
                }
                camera.addCallbackBuffer(mBuffer);
            }
        });

        (new Thread(this)).start();
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        Log.i(TAG, "surfaceDestroyed");
        mThreadRun = false;
        if (mCamera != null) {
            synchronized (this) {
                mCamera.stopPreview();
                mCamera.setPreviewCallback(null);
                mCamera.release();
                mCamera = null;
            }
        }
        onPreviewStopped();
    }

    /* The bitmap returned by this method shall be owned by the child and released in onPreviewStopped() */
    protected abstract Bitmap processFrame(byte[] data);

    /**
     * This method is called when the preview process is beeing started. It is called before the first frame delivered and processFrame is called
     * It is called with the width and height parameters of the preview process. It can be used to prepare the data needed during the frame processing.
     * @param previewWidth - the width of the preview frames that will be delivered via processFrame
     * @param previewHeight - the height of the preview frames that will be delivered via processFrame
     */
    protected abstract void onPreviewStared(int previewWidtd, int previewHeight);

    /**
     * This method is called when preview is stopped. When this method is called the preview stopped and all the processing of frames already completed.
     * If the Bitmap object returned via processFrame is cached - it is a good time to recycle it.
     * Any other resourcses used during the preview can be released.
     */
    protected abstract void onPreviewStopped();

    public void run() {
        mThreadRun = true;
        Log.i(TAG, "Starting processing thread");
        while (mThreadRun) {
            Bitmap bmp = null;

            synchronized (this) {
                try {
                    this.wait();
                    bmp = processFrame(mFrame);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            if (bmp != null) {
                Canvas canvas = mHolder.lockCanvas();
                if (canvas != null) {
                    canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null);
                    mHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }
}

0 个答案:

没有答案