diff --git a/samples/android/tutorial-4-mixed/AndroidManifest.xml b/samples/android/tutorial-4-mixed/AndroidManifest.xml index 51460d34b3..54a172f61f 100644 --- a/samples/android/tutorial-4-mixed/AndroidManifest.xml +++ b/samples/android/tutorial-4-mixed/AndroidManifest.xml @@ -22,7 +22,7 @@ android:largeScreens="true" android:anyDensity="true" /> - + diff --git a/samples/android/tutorial-4-mixed/jni/jni_part.cpp b/samples/android/tutorial-4-mixed/jni/jni_part.cpp index 43015df6d6..6b0b48ee86 100644 --- a/samples/android/tutorial-4-mixed/jni/jni_part.cpp +++ b/samples/android/tutorial-4-mixed/jni/jni_part.cpp @@ -8,7 +8,7 @@ using namespace std; using namespace cv; extern "C" { -JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4View_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba) +JNIEXPORT void JNICALL Java_org_opencv_samples_tutorial4_Sample4Mixed_FindFeatures(JNIEnv*, jobject, jlong addrGray, jlong addrRgba) { Mat* pMatGr=(Mat*)addrGray; Mat* pMatRgb=(Mat*)addrRgba; diff --git a/samples/android/tutorial-4-mixed/res/layout/tutorial4_surface_view.xml b/samples/android/tutorial-4-mixed/res/layout/tutorial4_surface_view.xml new file mode 100644 index 0000000000..0a4ac0ff44 --- /dev/null +++ b/samples/android/tutorial-4-mixed/res/layout/tutorial4_surface_view.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4Mixed.java b/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4Mixed.java index ece3c20f99..4a73b7bba7 100644 --- a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4Mixed.java +++ b/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4Mixed.java @@ -3,10 +3,15 @@ package org.opencv.samples.tutorial4; import org.opencv.android.BaseLoaderCallback; import org.opencv.android.LoaderCallbackInterface; import org.opencv.android.OpenCVLoader; +import org.opencv.core.CvType; +import org.opencv.core.Mat; +import org.opencv.framework.OpenCvJavaCameraView; +import org.opencv.framework.OpenCvNativeCameraView; +import org.opencv.framework.OpenCvCameraBridgeViewBase.CvCameraViewListener; +import org.opencv.highgui.Highgui; +import org.opencv.imgproc.Imgproc; import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; import android.os.Bundle; import android.util.Log; import android.view.Menu; @@ -14,16 +19,27 @@ import android.view.MenuItem; import android.view.Window; import android.view.WindowManager; -public class Sample4Mixed extends Activity { +public class Sample4Mixed extends Activity implements CvCameraViewListener { private static final String TAG = "OCVSample::Activity"; - private MenuItem mItemPreviewRGBA; - private MenuItem mItemPreviewGray; - private MenuItem mItemPreviewCanny; - private MenuItem mItemPreviewFeatures; - private Sample4View mView; + private static final int VIEW_MODE_RGBA = 0; + private static final int VIEW_MODE_GRAY = 1; + private static final int VIEW_MODE_CANNY = 2; + private static final int VIEW_MODE_FEATURES = 5; - private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) { + private int mViewMode; + private Mat mRgba; + private Mat mIntermediateMat; + private Mat mGrayMat; + + private MenuItem mItemPreviewRGBA; + private MenuItem mItemPreviewGray; + private MenuItem mItemPreviewCanny; + private MenuItem mItemPreviewFeatures; + + private OpenCvJavaCameraView mOpenCvCameraView; + + private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) { @Override public void onManagerConnected(int status) { switch (status) { @@ -34,39 +50,7 @@ public class Sample4Mixed extends Activity { // Load native library after(!) OpenCV initialization System.loadLibrary("mixed_sample"); - // Create and set View - mView = new Sample4View(mAppContext); - setContentView(mView); - - // Check native OpenCV camera - if( !mView.openCamera() ) { - AlertDialog ad = new AlertDialog.Builder(mAppContext).create(); - ad.setCancelable(false); // This blocks the 'BACK' button - ad.setMessage("Fatal error: can't open camera!"); - ad.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - finish(); - } - }); - ad.show(); - } - } break; - - /** OpenCV loader cannot start Google Play **/ - case LoaderCallbackInterface.MARKET_ERROR: - { - Log.d(TAG, "Google Play service is not accessible!"); - AlertDialog MarketErrorMessage = new AlertDialog.Builder(mAppContext).create(); - MarketErrorMessage.setTitle("OpenCV Manager"); - MarketErrorMessage.setMessage("Google Play service is not accessible!\nTry to install the 'OpenCV Manager' and the appropriate 'OpenCV binary pack' APKs from OpenCV SDK manually via 'adb install' command."); - MarketErrorMessage.setCancelable(false); // This blocks the 'BACK' button - MarketErrorMessage.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { - finish(); - } - }); - MarketErrorMessage.show(); + mOpenCvCameraView.enableView(); } break; default: { @@ -80,25 +64,6 @@ public class Sample4Mixed extends Activity { Log.i(TAG, "Instantiated new " + this.getClass()); } - @Override - protected void onPause() { - Log.i(TAG, "called onPause"); - if (null != mView) - mView.releaseCamera(); - super.onPause(); - } - - @Override - protected void onResume() { - Log.i(TAG, "called onResume"); - super.onResume(); - - Log.i(TAG, "Trying to load OpenCV library"); - if (!OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mOpenCVCallBack)) { - Log.e(TAG, "Cannot connect to OpenCV Manager"); - } - } - /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { @@ -106,6 +71,11 @@ public class Sample4Mixed extends Activity { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + + setContentView(R.layout.tutorial4_surface_view); + + mOpenCvCameraView = (OpenCvJavaCameraView)findViewById(R.id.tutorial4_activity_surface_view); + mOpenCvCameraView.setCvCameraViewListener(this); } @Override @@ -119,17 +89,88 @@ public class Sample4Mixed extends Activity { } @Override + public void onPause() + { + mOpenCvCameraView.disableView(); + super.onPause(); + } + + @Override + public void onResume() + { + super.onResume(); + OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_2, this, mLoaderCallback); + } + + public void onDestroy() { + super.onDestroy(); + mOpenCvCameraView.disableView(); + } + + public void onCameraViewStarted(int width, int height) { + mRgba = new Mat(height, width, CvType.CV_8UC4); + mIntermediateMat = new Mat(height, width, CvType.CV_8UC4); + mGrayMat = new Mat(height, width, CvType.CV_8UC1); + } + + public void onCameraViewStopped() { + mRgba.release(); + mGrayMat.release(); + mIntermediateMat.release(); + } + + public Mat onCameraFrame(Mat inputFrame) { + final int viewMode = mViewMode; + + Log.d(TAG, "Input format: " + inputFrame); + + switch (viewMode) { + case VIEW_MODE_GRAY: + // input frame has gray scale format + Imgproc.cvtColor(inputFrame, mRgba, Imgproc.COLOR_GRAY2RGBA, 4); + break; + case VIEW_MODE_RGBA: + // input frame has RBGA format + inputFrame.copyTo(mRgba); + break; + case VIEW_MODE_CANNY: + // input frame has gray scale format + Imgproc.Canny(inputFrame, mIntermediateMat, 80, 100); + Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4); + break; + case VIEW_MODE_FEATURES: + // input frame has RGBA format + //Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGB, 4); + inputFrame.copyTo(mRgba); + Imgproc.cvtColor(mRgba, mGrayMat, Imgproc.COLOR_RGBA2GRAY); + FindFeatures(mGrayMat.getNativeObjAddr(), mRgba.getNativeObjAddr()); + break; + } + + Log.d(TAG, "Output format: " + mRgba); + + return mRgba; + } + public boolean onOptionsItemSelected(MenuItem item) { Log.i(TAG, "called onOptionsItemSelected; selected item: " + item); + if (item == mItemPreviewRGBA) { - mView.setViewMode(Sample4View.VIEW_MODE_RGBA); + mOpenCvCameraView.SetCaptureFormat(Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); + mViewMode = VIEW_MODE_RGBA; } else if (item == mItemPreviewGray) { - mView.setViewMode(Sample4View.VIEW_MODE_GRAY); + mOpenCvCameraView.SetCaptureFormat(Highgui.CV_CAP_ANDROID_GREY_FRAME); + mViewMode = VIEW_MODE_GRAY; } else if (item == mItemPreviewCanny) { - mView.setViewMode(Sample4View.VIEW_MODE_CANNY); + mOpenCvCameraView.SetCaptureFormat(Highgui.CV_CAP_ANDROID_GREY_FRAME); + mViewMode = VIEW_MODE_CANNY; } else if (item == mItemPreviewFeatures) { - mView.setViewMode(Sample4View.VIEW_MODE_FEATURES); + mViewMode = VIEW_MODE_FEATURES; + mOpenCvCameraView.SetCaptureFormat(Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA); } + return true; } + + public native void FindFeatures(long matAddrGr, long matAddrRgba); } diff --git a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4View.java b/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4View.java deleted file mode 100644 index 2b44ecac98..0000000000 --- a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/Sample4View.java +++ /dev/null @@ -1,116 +0,0 @@ -package org.opencv.samples.tutorial4; - -import org.opencv.android.Utils; -import org.opencv.core.CvType; -import org.opencv.core.Mat; -import org.opencv.imgproc.Imgproc; - -import android.content.Context; -import android.graphics.Bitmap; -import android.util.Log; - -class Sample4View extends SampleViewBase { - private static final String TAG = "OCVSample::View"; - - public static final int VIEW_MODE_RGBA = 0; - public static final int VIEW_MODE_GRAY = 1; - public static final int VIEW_MODE_CANNY = 2; - public static final int VIEW_MODE_FEATURES = 5; - - private Mat mYuv; - private Mat mRgba; - private Mat mGraySubmat; - private Mat mIntermediateMat; - private Bitmap mBitmap; - private int mViewMode; - - public Sample4View(Context context) { - super(context); - } - - @Override - protected void onPreviewStarted(int previewWidth, int previewHeight) { - Log.i(TAG, "called onPreviewStarted("+previewWidth+", "+previewHeight+")"); - - // initialize Mats before usage - mYuv = new Mat(getFrameHeight() + getFrameHeight() / 2, getFrameWidth(), CvType.CV_8UC1); - mGraySubmat = mYuv.submat(0, getFrameHeight(), 0, getFrameWidth()); - - mRgba = new Mat(); - mIntermediateMat = new Mat(); - - mBitmap = Bitmap.createBitmap(previewWidth, previewHeight, Bitmap.Config.ARGB_8888); - } - - @Override - protected void onPreviewStopped() { - Log.i(TAG, "called onPreviewStopped"); - - if (mBitmap != null) { - mBitmap.recycle(); - mBitmap = null; - } - - synchronized (this) { - // Explicitly deallocate Mats - if (mYuv != null) - mYuv.release(); - if (mRgba != null) - mRgba.release(); - if (mGraySubmat != null) - mGraySubmat.release(); - if (mIntermediateMat != null) - mIntermediateMat.release(); - - mYuv = null; - mRgba = null; - mGraySubmat = null; - mIntermediateMat = null; - } - - } - - - @Override - protected Bitmap processFrame(byte[] data) { - mYuv.put(0, 0, data); - - final int viewMode = mViewMode; - - switch (viewMode) { - case VIEW_MODE_GRAY: - Imgproc.cvtColor(mGraySubmat, mRgba, Imgproc.COLOR_GRAY2RGBA, 4); - break; - case VIEW_MODE_RGBA: - Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGB, 4); - break; - case VIEW_MODE_CANNY: - Imgproc.Canny(mGraySubmat, mIntermediateMat, 80, 100); - Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4); - break; - case VIEW_MODE_FEATURES: - Imgproc.cvtColor(mYuv, mRgba, Imgproc.COLOR_YUV420sp2RGB, 4); - FindFeatures(mGraySubmat.getNativeObjAddr(), mRgba.getNativeObjAddr()); - break; - } - - Bitmap bmp = mBitmap; - - try { - Utils.matToBitmap(mRgba, bmp); - } catch(Exception e) { - Log.e("org.opencv.samples.puzzle15", "Utils.matToBitmap() throws an exception: " + e.getMessage()); - bmp.recycle(); - bmp = null; - } - - return bmp; - } - - public native void FindFeatures(long matAddrGr, long matAddrRgba); - - public void setViewMode(int viewMode) { - Log.i(TAG, "called setViewMode("+viewMode+")"); - mViewMode = viewMode; - } -} diff --git a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/SampleViewBase.java b/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/SampleViewBase.java deleted file mode 100644 index cddb22f056..0000000000 --- a/samples/android/tutorial-4-mixed/src/org/opencv/samples/tutorial4/SampleViewBase.java +++ /dev/null @@ -1,229 +0,0 @@ -package org.opencv.samples.tutorial4; - -import java.io.IOException; -import java.util.List; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.ImageFormat; -import android.graphics.SurfaceTexture; -import android.hardware.Camera; -import android.hardware.Camera.PreviewCallback; -import android.os.Build; -import android.util.Log; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -public abstract class SampleViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable { - private static final String TAG = "OCVSample::BaseView"; - - private Camera mCamera; - private SurfaceHolder mHolder; - private int mFrameWidth; - private int mFrameHeight; - private byte[] mFrame; - private volatile boolean mThreadRun; - private byte[] mBuffer; - private SurfaceTexture mSf; - - - 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) { - mSf = new SurfaceTexture(10); - mCamera.setPreviewTexture( mSf ); - } - else - mCamera.setPreviewDisplay(null); - } - - public boolean openCamera() { - Log.i(TAG, "Opening Camera"); - mCamera = null; - - try { - mCamera = Camera.open(); - } - catch (Exception e){ - Log.e(TAG, "Camera is not available (in use or does not exist): " + e.getLocalizedMessage()); - } - - if(mCamera == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) { - for (int camIdx = 0; camIdx < Camera.getNumberOfCameras(); ++camIdx) { - try { - mCamera = Camera.open(camIdx); - } - catch (RuntimeException e) { - Log.e(TAG, "Camera #" + camIdx + "failed to open: " + e.getLocalizedMessage()); - } - } - } - - if(mCamera == null) { - Log.e(TAG, "Can't open any camera"); - return false; - } - - 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); - } - }); - - return true; - } - - public void releaseCamera() { - Log.i(TAG, "Releasing Camera"); - mThreadRun = false; - synchronized (this) { - if (mCamera != null) { - mCamera.stopPreview(); - mCamera.release(); - mCamera = null; - } - } - onPreviewStopped(); - } - - public synchronized void setupCamera(int width, int height) { - if (mCamera != null) { - Log.i(TAG, "Setup Camera - " + width + "x" + height); - Camera.Parameters params = mCamera.getParameters(); - List 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 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 copied */ - mFrame = new byte [size]; - mCamera.addCallbackBuffer(mBuffer); - - /* Notify that the preview is about to be started and deliver preview size */ - onPreviewStarted(params.getPreviewSize().width, params.getPreviewSize().height); - - try { - setPreview(); - } catch (IOException e) { - Log.e(TAG, "mCamera.setPreviewDisplay/setPreviewTexture fails: " + e); - } - - /* Now we can start a preview */ - mCamera.startPreview(); - } - } - - public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) { - Log.i(TAG, "called surfaceChanged"); - // stop preview before making changes - try { - mCamera.stopPreview(); - } catch (Exception e){ - // ignore: tried to stop a non-existent preview - } - - // start preview with new settings - setupCamera(width, height); - } - - public void surfaceCreated(SurfaceHolder holder) { - Log.i(TAG, "called surfaceCreated"); - (new Thread(this)).start(); - } - - public void surfaceDestroyed(SurfaceHolder holder) { - Log.i(TAG, "called surfaceDestroyed"); - } - - /* 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 being 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 onPreviewStarted(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 resources used during the preview can be released. - */ - protected abstract void onPreviewStopped(); - - public void run() { - mThreadRun = true; - Log.i(TAG, "Started processing thread"); - while (mThreadRun) { - Bitmap bmp = null; - - synchronized (this) { - try { - this.wait(); - if (!mThreadRun) - break; - bmp = processFrame(mFrame); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - if (bmp != null) { - Canvas canvas = mHolder.lockCanvas(); - if (canvas != null) { - canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR); - canvas.drawBitmap(bmp, (canvas.getWidth() - getFrameWidth()) / 2, (canvas.getHeight() - getFrameHeight()) / 2, null); - mHolder.unlockCanvasAndPost(canvas); - } - } - } - Log.i(TAG, "Finished processing thread"); - } -} \ No newline at end of file