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