diff --git a/modules/java/CMakeLists.txt b/modules/java/CMakeLists.txt index eb40260366..ee1ad30813 100644 --- a/modules/java/CMakeLists.txt +++ b/modules/java/CMakeLists.txt @@ -237,7 +237,7 @@ if(ANDROID) set(lib_target_files ${ANDROID_LIB_PROJECT_FILES}) 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}") diff --git a/modules/java/generator/src/java/framework+OpenCvCameraBridgeViewBase.java b/modules/java/generator/src/java/framework+OpenCvCameraBridgeViewBase.java index 43a010a991..e3163ff763 100644 --- a/modules/java/generator/src/java/framework+OpenCvCameraBridgeViewBase.java +++ b/modules/java/generator/src/java/framework+OpenCvCameraBridgeViewBase.java @@ -6,9 +6,11 @@ import org.opencv.android.Utils; import org.opencv.core.Mat; import org.opencv.core.Size; 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.DialogInterface; import android.graphics.Bitmap; import android.graphics.Canvas; import android.util.AttributeSet; @@ -34,15 +36,15 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements protected int mMaxHeight; protected int mMaxWidth; + protected int mPreviewFormat = Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA; + private Bitmap mCacheBitmap; - public OpenCvCameraBridgeViewBase(Context context, AttributeSet attrs) { - super(context,attrs); + super(context, attrs); getHolder().addCallback(this); mMaxWidth = MAX_UNSPECIFIED; mMaxHeight = MAX_UNSPECIFIED; - } 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 STARTED = 1; - private static final String TAG = "SampleCvBase"; + + private static final String TAG = "OpenCvCameraBridge"; private CvCameraViewListener mListener; private int mState = STOPPED; @@ -90,8 +82,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements private boolean mEnabled; private boolean mSurfaceExist; - - private Object mSyncObject = new Object(); 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. - * 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() { 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 - * 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() { synchronized(mSyncObject) { @@ -145,7 +134,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements } } - public void setCvCameraViewListener(CvCameraViewListener 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. * As an example - we set setMaxFrameSize(200,200) and we have 176x152 and 320x240 sizes. The * 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 maxHeight - the maxumum height allowed for camera frame + * @param maxHeight - the maximum height allowed for camera frame */ public void setMaxFrameSize(int maxWidth, int maxHeight) { mMaxWidth = maxWidth; mMaxHeight = maxHeight; } + public void SetCaptureFormat(int format) + { + mPreviewFormat = format; + } + /** * Called when mSyncObject lock is held */ @@ -201,7 +194,6 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements }; } - private void processExitState(int state) { switch(state) { case STARTED: @@ -221,23 +213,32 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements /* 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() { + /* 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() { - disconnectCamera(); if (mCacheBitmap != null) { mCacheBitmap.recycle(); } } - /** * 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 @@ -247,23 +248,32 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements protected void deliverAndDrawFrame(Mat frame) { Mat modified; - if (mListener != null) { - modified = mListener.onCameraFrame(frame); - } else { - modified = frame; - } + if (mListener != null) { + modified = mListener.onCameraFrame(frame); + } else { + modified = frame; + } - if (modified != null) { + boolean bmpValid = true; + if (modified != null) { + try { 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) { - Canvas canvas = getHolder().lockCanvas(); - if (canvas != null) { - canvas.drawBitmap(mCacheBitmap, (canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2, null); - getHolder().unlockCanvasAndPost(canvas); - } + if (bmpValid && mCacheBitmap != null) { + Canvas canvas = getHolder().lockCanvas(); + 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); + getHolder().unlockCanvasAndPost(canvas); } + } } /** @@ -273,21 +283,25 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements * @param width - the width 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 */ 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 int getWidth(Object obj); public int getHeight(Object obj); }; - /** * 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 @@ -297,7 +311,7 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements * @param surfaceHeight * @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 calcHeight = 0; @@ -315,6 +329,7 @@ public abstract class OpenCvCameraBridgeViewBase extends SurfaceView implements } } } - return new FrameSize(calcWidth, calcHeight); + + return new Size(calcWidth, calcHeight); } } diff --git a/modules/java/generator/src/java/framework+OpenCvJavaCameraView.java b/modules/java/generator/src/java/framework+OpenCvJavaCameraView.java index 39f4b2eaa2..05e44463cb 100644 --- a/modules/java/generator/src/java/framework+OpenCvJavaCameraView.java +++ b/modules/java/generator/src/java/framework+OpenCvJavaCameraView.java @@ -17,6 +17,7 @@ import android.view.SurfaceHolder; import org.opencv.core.CvType; import org.opencv.core.Mat; import org.opencv.core.Size; +import org.opencv.highgui.Highgui; import org.opencv.imgproc.Imgproc; /** @@ -41,13 +42,11 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements public static class JavaCameraSizeAccessor implements ListItemAccessor { - @Override public int getWidth(Object obj) { Camera.Size size = (Camera.Size) obj; return size.width; } - @Override public int getHeight(Object obj) { Camera.Size size = (Camera.Size) obj; return size.height; @@ -122,8 +121,8 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements AllocateCache(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - SurfaceTexture tex = new SurfaceTexture(MAGIC_TEXTURE_ID); - getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); + SurfaceTexture tex = new SurfaceTexture(MAGIC_TEXTURE_ID); + getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); mCamera.setPreviewTexture(tex); } else mCamera.setPreviewDisplay(null); @@ -176,7 +175,7 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements Log.d(TAG, "Notify thread"); synchronized (this) { this.notify(); - } + } Log.d(TAG, "Wating for thread"); mThread.join(); } catch (InterruptedException e) { @@ -189,7 +188,6 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements releaseCamera(); } - @Override 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, "Frame size is " + frame.length); @@ -213,26 +211,34 @@ public class OpenCvJavaCameraView extends OpenCvCameraBridgeViewBase implements mHeight = h; } - @Override public void run() { - do { - synchronized (OpenCvJavaCameraView.this) { - try { - OpenCvJavaCameraView.this.wait(); - } catch (InterruptedException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + do { + synchronized (OpenCvJavaCameraView.this) { + try { + OpenCvJavaCameraView.this.wait(); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - if (!mStopThread) { - Mat frameMat = new Mat(); - Imgproc.cvtColor(mBaseMat, frameMat, Imgproc.COLOR_YUV2RGBA_NV21, 4); + if (!mStopThread) { + Mat frameMat = new Mat(); + switch (mPreviewFormat) { + case Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA: + 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); frameMat.release(); - } - } while (!mStopThread); - Log.d(TAG, "Finish processing thread"); + } + } while (!mStopThread); + Log.d(TAG, "Finish processing thread"); } } } diff --git a/modules/java/generator/src/java/framework+OpenCvNativeCameraView.java b/modules/java/generator/src/java/framework+OpenCvNativeCameraView.java index 36e69498cc..90f5d8a0ea 100644 --- a/modules/java/generator/src/java/framework+OpenCvNativeCameraView.java +++ b/modules/java/generator/src/java/framework+OpenCvNativeCameraView.java @@ -66,13 +66,11 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase { public static class OpenCvSizeAccessor implements ListItemAccessor { - @Override public int getWidth(Object obj) { Size size = (Size)obj; return (int)size.width; } - @Override public int getHeight(Object obj) { Size size = (Size)obj; return (int)size.height; @@ -112,6 +110,7 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase { private class CameraWorker implements Runnable { private Mat mRgba = new Mat(); + private Mat mGray = new Mat(); private int mWidth; private int mHeight; @@ -120,7 +119,6 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase { mHeight = h; } - @Override public void run() { Mat modified; @@ -130,9 +128,20 @@ public class OpenCvNativeCameraView extends OpenCvCameraBridgeViewBase { Log.e(TAG, "Camera frame grab failed"); break; } - mCamera.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); - deliverAndDrawFrame(mRgba); + 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);