New sample framework integrated to Java part of SDK;

Frame format setter added to both views.
This commit is contained in:
Alexander Smorkalov 2012-10-22 12:58:13 +04:00 committed by Andrey Kamaev
parent 9029acf6f0
commit 641ee645ab
4 changed files with 106 additions and 76 deletions

View File

@ -237,7 +237,7 @@ if(ANDROID)
set(lib_target_files ${ANDROID_LIB_PROJECT_FILES}) set(lib_target_files ${ANDROID_LIB_PROJECT_FILES})
ocv_list_add_prefix(lib_target_files "${OpenCV_BINARY_DIR}/") ocv_list_add_prefix(lib_target_files "${OpenCV_BINARY_DIR}/")
android_get_compatible_target(lib_target_sdk_target ${ANDROID_NATIVE_API_LEVEL} ${ANDROID_SDK_TARGET}) android_get_compatible_target(lib_target_sdk_target ${ANDROID_NATIVE_API_LEVEL} ${ANDROID_SDK_TARGET} 11)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/android_lib/${ANDROID_MANIFEST_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${ANDROID_MANIFEST_FILE}") configure_file("${CMAKE_CURRENT_SOURCE_DIR}/android_lib/${ANDROID_MANIFEST_FILE}" "${CMAKE_CURRENT_BINARY_DIR}/${ANDROID_MANIFEST_FILE}")

View File

@ -6,9 +6,11 @@ import org.opencv.android.Utils;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.core.Size; import org.opencv.core.Size;
import org.opencv.highgui.Highgui; import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Canvas; import android.graphics.Canvas;
import android.util.AttributeSet; import android.util.AttributeSet;
@ -34,15 +36,15 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
protected int mMaxHeight; protected int mMaxHeight;
protected int mMaxWidth; protected int mMaxWidth;
protected int mPreviewFormat = Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA;
private Bitmap mCacheBitmap; private Bitmap mCacheBitmap;
public OpenCvCameraBridgeViewBase(Context context, AttributeSet attrs) { public OpenCvCameraBridgeViewBase(Context context, AttributeSet attrs) {
super(context,attrs); super(context, attrs);
getHolder().addCallback(this); getHolder().addCallback(this);
mMaxWidth = MAX_UNSPECIFIED; mMaxWidth = MAX_UNSPECIFIED;
mMaxHeight = MAX_UNSPECIFIED; mMaxHeight = MAX_UNSPECIFIED;
} }
public interface CvCameraViewListener { public interface CvCameraViewListener {
@ -69,20 +71,10 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
} }
public class FrameSize {
public int width;
public int height;
public FrameSize(int w, int h) {
width = w;
height = h;
}
}
private static final int STOPPED = 0; private static final int STOPPED = 0;
private static final int STARTED = 1; private static final int STARTED = 1;
private static final String TAG = "SampleCvBase";
private static final String TAG = "OpenCvCameraBridge";
private CvCameraViewListener mListener; private CvCameraViewListener mListener;
private int mState = STOPPED; private int mState = STOPPED;
@ -90,8 +82,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
private boolean mEnabled; private boolean mEnabled;
private boolean mSurfaceExist; private boolean mSurfaceExist;
private Object mSyncObject = new Object(); private Object mSyncObject = new Object();
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) { public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
@ -122,10 +112,9 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
} }
} }
/** /**
* This method is provided for clients, so they can enable the camera connection. * This method is provided for clients, so they can enable the camera connection.
* The actuall onCameraViewStarted callback will be delivered only after both this method is called and surface is available * The actual onCameraViewStarted callback will be delivered only after both this method is called and surface is available
*/ */
public void enableView() { public void enableView() {
synchronized(mSyncObject) { synchronized(mSyncObject) {
@ -136,7 +125,7 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
/** /**
* This method is provided for clients, so they can disable camera connection and stop * This method is provided for clients, so they can disable camera connection and stop
* the delivery of frames eventhough the surfaceview itself is not destroyed and still stays on the scren * the delivery of frames even though the surface view itself is not destroyed and still stays on the scren
*/ */
public void disableView() { public void disableView() {
synchronized(mSyncObject) { synchronized(mSyncObject) {
@ -145,7 +134,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
} }
} }
public void setCvCameraViewListener(CvCameraViewListener listener) { public void setCvCameraViewListener(CvCameraViewListener listener) {
mListener = listener; mListener = listener;
} }
@ -155,15 +143,20 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
* size - the biggest size which less or equal the size set will be selected. * size - the biggest size which less or equal the size set will be selected.
* As an example - we set setMaxFrameSize(200,200) and we have 176x152 and 320x240 sizes. The * As an example - we set setMaxFrameSize(200,200) and we have 176x152 and 320x240 sizes. The
* preview frame will be selected with 176x152 size. * preview frame will be selected with 176x152 size.
* This method is usefull when need to restrict the size of preview frame for some reason (for example for video recording) * This method is useful when need to restrict the size of preview frame for some reason (for example for video recording)
* @param maxWidth - the maximum width allowed for camera frame. * @param maxWidth - the maximum width allowed for camera frame.
* @param maxHeight - the maxumum height allowed for camera frame * @param maxHeight - the maximum height allowed for camera frame
*/ */
public void setMaxFrameSize(int maxWidth, int maxHeight) { public void setMaxFrameSize(int maxWidth, int maxHeight) {
mMaxWidth = maxWidth; mMaxWidth = maxWidth;
mMaxHeight = maxHeight; mMaxHeight = maxHeight;
} }
public void SetCaptureFormat(int format)
{
mPreviewFormat = format;
}
/** /**
* Called when mSyncObject lock is held * Called when mSyncObject lock is held
*/ */
@ -201,7 +194,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
}; };
} }
private void processExitState(int state) { private void processExitState(int state) {
switch(state) { switch(state) {
case STARTED: case STARTED:
@ -221,23 +213,32 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
/* nothing to do */ /* nothing to do */
} }
// NOTE: The order of bitmap constructor and camera connection is important for android 4.1.x
// Bitmap must be constructed before surface
private void onEnterStartedState() { private void onEnterStartedState() {
/* Connect camera */
if (!connectCamera(getWidth(), getHeight())) {
AlertDialog ad = new AlertDialog.Builder(getContext()).create();
ad.setCancelable(false); // This blocks the 'BACK' button
ad.setMessage("It seems that you device does not support camera (or it is locked). Application will be closed.");
ad.setButton(DialogInterface.BUTTON_NEUTRAL, "OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
((Activity) getContext()).finish();
}
});
ad.show();
connectCamera(getWidth(), getHeight()); }
/* Now create cahe Bitmap */
mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888);
} }
private void onExitStartedState() { private void onExitStartedState() {
disconnectCamera(); disconnectCamera();
if (mCacheBitmap != null) { if (mCacheBitmap != null) {
mCacheBitmap.recycle(); mCacheBitmap.recycle();
} }
} }
/** /**
* This method shall be called by the subclasses when they have valid * This method shall be called by the subclasses when they have valid
* object and want it to be delivered to external client (via callback) and * object and want it to be delivered to external client (via callback) and
@ -253,13 +254,22 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
modified = frame; modified = frame;
} }
boolean bmpValid = true;
if (modified != null) { if (modified != null) {
try {
Utils.matToBitmap(modified, mCacheBitmap); Utils.matToBitmap(modified, mCacheBitmap);
} catch(Exception e) {
Log.e(TAG, "Mat type: " + modified);
Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
bmpValid = false;
}
} }
if (mCacheBitmap != null) { if (bmpValid && mCacheBitmap != null) {
Canvas canvas = getHolder().lockCanvas(); Canvas canvas = getHolder().lockCanvas();
if (canvas != null) { if (canvas != null) {
canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null); canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null);
getHolder().unlockCanvasAndPost(canvas); getHolder().unlockCanvasAndPost(canvas);
} }
@ -273,21 +283,25 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
* @param width - the width of this SurfaceView * @param width - the width of this SurfaceView
* @param height - the height of this SurfaceView * @param height - the height of this SurfaceView
*/ */
protected abstract void connectCamera(int width, int height); protected abstract boolean connectCamera(int width, int height);
/** /**
* Disconnects and release the particular camera object beeing connected to this surface view. * Disconnects and release the particular camera object being connected to this surface view.
* Called when syncObject lock is held * Called when syncObject lock is held
*/ */
protected abstract void disconnectCamera(); protected abstract void disconnectCamera();
// NOTE: On Android 4.1.x the function must be called before SurfaceTextre constructor!
protected void AllocateCache()
{
mCacheBitmap = Bitmap.createBitmap(mFrameWidth, mFrameHeight, Bitmap.Config.ARGB_8888);
}
public interface ListItemAccessor { public interface ListItemAccessor {
public int getWidth(Object obj); public int getWidth(Object obj);
public int getHeight(Object obj); public int getHeight(Object obj);
}; };
/** /**
* This helper method can be called by subclasses to select camera preview size. * This helper method can be called by subclasses to select camera preview size.
* It goes over the list of the supported preview sizes and selects the maximum one which * It goes over the list of the supported preview sizes and selects the maximum one which
@ -297,7 +311,7 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
* @param surfaceHeight * @param surfaceHeight
* @return * @return
*/ */
protected FrameSize calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) { protected Size calculateCameraFrameSize(List<?> supportedSizes, ListItemAccessor accessor, int surfaceWidth, int surfaceHeight) {
int calcWidth = 0; int calcWidth = 0;
int calcHeight = 0; int calcHeight = 0;
@ -315,6 +329,7 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements
} }
} }
} }
return new FrameSize(calcWidth, calcHeight);
return new Size(calcWidth, calcHeight);
} }
} }

View File

@ -17,6 +17,7 @@ import android.view.SurfaceHolder;
import org.opencv.core.CvType; import org.opencv.core.CvType;
import org.opencv.core.Mat; import org.opencv.core.Mat;
import org.opencv.core.Size; import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc; import org.opencv.imgproc.Imgproc;
/** /**
@ -41,13 +42,11 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
public static class JavaCameraSizeAccessor implements ListItemAccessor { public static class JavaCameraSizeAccessor implements ListItemAccessor {
@Override
public int getWidth(Object obj) { public int getWidth(Object obj) {
Camera.Size size = (Camera.Size) obj; Camera.Size size = (Camera.Size) obj;
return size.width; return size.width;
} }
@Override
public int getHeight(Object obj) { public int getHeight(Object obj) {
Camera.Size size = (Camera.Size) obj; Camera.Size size = (Camera.Size) obj;
return size.height; return size.height;
@ -189,7 +188,6 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
releaseCamera(); releaseCamera();
} }
@Override
public void onPreviewFrame(byte[] frame, Camera arg1) { public void onPreviewFrame(byte[] frame, Camera arg1) {
Log.i(TAG, "Preview Frame received. Need to create MAT and deliver it to clients"); Log.i(TAG, "Preview Frame received. Need to create MAT and deliver it to clients");
Log.i(TAG, "Frame size is " + frame.length); Log.i(TAG, "Frame size is " + frame.length);
@ -213,7 +211,6 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
mHeight = h; mHeight = h;
} }
@Override
public void run() { public void run() {
do { do {
synchronized (OpenCvJavaCameraView.this) { synchronized (OpenCvJavaCameraView.this) {
@ -227,7 +224,16 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements
if (!mStopThread) { if (!mStopThread) {
Mat frameMat = new Mat(); Mat frameMat = new Mat();
switch (mPreviewFormat) {
case Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA:
Imgproc.cvtColor(mBaseMat, frameMat, Imgproc.COLOR_YUV2RGBA_NV21, 4); Imgproc.cvtColor(mBaseMat, frameMat, Imgproc.COLOR_YUV2RGBA_NV21, 4);
break;
case Highgui.CV_CAP_ANDROID_GREY_FRAME:
frameMat = mBaseMat.submat(0, mFrameHeight, 0, mFrameWidth);
break;
default:
Log.e(TAG, "Invalid frame format! Only RGBA and Gray Scale are supported!");
};
deliverAndDrawFrame(frameMat); deliverAndDrawFrame(frameMat);
frameMat.release(); frameMat.release();
} }

View File

@ -66,13 +66,11 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase {
public static class OpenCvSizeAccessor implements ListItemAccessor { public static class OpenCvSizeAccessor implements ListItemAccessor {
@Override
public int getWidth(Object obj) { public int getWidth(Object obj) {
Size size = (Size)obj; Size size = (Size)obj;
return (int)size.width; return (int)size.width;
} }
@Override
public int getHeight(Object obj) { public int getHeight(Object obj) {
Size size = (Size)obj; Size size = (Size)obj;
return (int)size.height; return (int)size.height;
@ -112,6 +110,7 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase {
private class CameraWorker implements Runnable { private class CameraWorker implements Runnable {
private Mat mRgba = new Mat(); private Mat mRgba = new Mat();
private Mat mGray = new Mat();
private int mWidth; private int mWidth;
private int mHeight; private int mHeight;
@ -120,7 +119,6 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase {
mHeight = h; mHeight = h;
} }
@Override
public void run() { public void run() {
Mat modified; Mat modified;
@ -130,9 +128,20 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase {
Log.e(TAG, "Camera frame grab failed"); Log.e(TAG, "Camera frame grab failed");
break; break;
} }
mCamera.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
switch (mPreviewFormat) {
case Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA:
{
mCamera.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
deliverAndDrawFrame(mRgba); 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); } while (!mStopThread);