package org.opencv.android;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
/**
* This class is an implementation of a bridge between SurfaceView and native OpenCV camera.
* Due to the big amount of work done, by the base class this child is only responsible
* for creating camera, destroying camera and delivering frames while camera is enabled
*/
public class NativeCameraView extends CameraBridgeViewBase {
public static final String TAG = "NativeCameraView";
private boolean mStopThread;
private Thread mThread;
protected VideoCapture mCamera;
public NativeCameraView(Context context, int cameraId) {
super(context, cameraId);
}
public NativeCameraView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected boolean connectCamera(int width, int height) {
/* 1. We need to instantiate camera
* 2. We need to start thread which will be getting frames
*/
/* First step - initialize camera connection */
if (!initializeCamera(getWidth(), getHeight()))
return false;
/* now we can start update thread */
mThread = new Thread(new CameraWorker());
mThread.start();
return true;
}
@Override
protected void disconnectCamera() {
/* 1. We need to stop thread which updating the frames
* 2. Stop camera and release it
*/
try {
mStopThread = true;
mThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mThread = null;
mStopThread = false;
}
/* Now release camera */
releaseCamera();
}
public static class OpenCvSizeAccessor implements ListItemAccessor {
public int getWidth(Object obj) {
Size size = (Size)obj;
return (int)size.width;
}
public int getHeight(Object obj) {
Size size = (Size)obj;
return (int)size.height;
}
}
private boolean initializeCamera(int width, int height) {
synchronized (this) {
if (mCameraIndex == -1)
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID);
else
mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID + mCameraIndex);
if (mCamera == null)
return false;
if (mCamera.isOpened() == false)
return false;
java.util.List<Size> sizes = mCamera.getSupportedPreviewSizes();
/* Select the size that fits surface considering maximum size allowed */
Size frameSize = calculateCameraFrameSize(sizes, new OpenCvSizeAccessor(), width, height);
mFrameWidth = (int)frameSize.width;
mFrameHeight = (int)frameSize.height;
if (mFpsMeter != null) {
mFpsMeter.setResolution(mFrameWidth, mFrameHeight);
}
AllocateCache();
mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, frameSize.width);
mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, frameSize.height);
}
Log.i(TAG, "Selected camera frame size = (" + mFrameWidth + ", " + mFrameHeight + ")");
return true;
}
private void releaseCamera() {
synchronized (this) {
if (mCamera != null) {
mCamera.release();
}
}
}
private class CameraWorker implements Runnable {
private Mat mRgba = new Mat();
private Mat mGray = new Mat();
public void run() {
do {
if (!mCamera.grab()) {
Log.e(TAG, "Camera frame grab failed");
break;
}
switch (mPreviewFormat) {
case Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA:
{
mCamera.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
deliverAndDrawFrame(mRgba);
} break;
case Highgui.CV_CAP_ANDROID_GREY_FRAME:
mCamera.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
deliverAndDrawFrame(mGray);
break;
default:
Log.e(TAG, "Invalid frame format! Only RGBA and Gray Scale are supported!");
}
} while (!mStopThread);
}
}
}