diff --git a/samples/android/face-detection/res/layout/face_detect_surface_view.xml b/samples/android/face-detection/res/layout/face_detect_surface_view.xml
new file mode 100644
index 0000000000..57027643a5
--- /dev/null
+++ b/samples/android/face-detection/res/layout/face_detect_surface_view.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/samples/android/face-detection/src/org/opencv/samples/fd/FdActivity.java b/samples/android/face-detection/src/org/opencv/samples/fd/FdActivity.java
index e6e6d59884..1009261fad 100644
--- a/samples/android/face-detection/src/org/opencv/samples/fd/FdActivity.java
+++ b/samples/android/face-detection/src/org/opencv/samples/fd/FdActivity.java
@@ -1,12 +1,26 @@
package org.opencv.samples.fd;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
+import org.opencv.core.Core;
+import org.opencv.core.Mat;
+import org.opencv.core.MatOfRect;
+import org.opencv.core.Rect;
+import org.opencv.core.Scalar;
+import org.opencv.core.Size;
+import org.opencv.framework.OpenCvJavaCameraView;
+import org.opencv.framework.OpenCvCameraBridgeViewBase.CvCameraViewListener;
+import org.opencv.imgproc.Imgproc;
+import org.opencv.objdetect.CascadeClassifier;
import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
+import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
@@ -14,19 +28,34 @@ import android.view.MenuItem;
import android.view.Window;
import android.view.WindowManager;
-public class FdActivity extends Activity {
- private static final String TAG = "OCVSample::Activity";
+public class FdActivity extends Activity implements CvCameraViewListener {
- private MenuItem mItemFace50;
- private MenuItem mItemFace40;
- private MenuItem mItemFace30;
- private MenuItem mItemFace20;
- private MenuItem mItemType;
- private int mDetectorType = 0;
- private String[] mDetectorName;
- private FdView mView;
+ private static final String TAG = "OCVSample::Activity";
+ private static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);
+ public static final int JAVA_DETECTOR = 0;
+ public static final int NATIVE_DETECTOR = 1;
- private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
+ private MenuItem mItemFace50;
+ private MenuItem mItemFace40;
+ private MenuItem mItemFace30;
+ private MenuItem mItemFace20;
+ private MenuItem mItemType;
+
+ private Mat mRgba;
+ private Mat mGray;
+ private File mCascadeFile;
+ private CascadeClassifier mJavaDetector;
+ private DetectionBasedTracker mNativeDetector;
+
+ private int mDetectorType = JAVA_DETECTOR;
+ private String[] mDetectorName;
+
+ private float mRelativeFaceSize = 0;
+ private int mAbsoluteFaceSize = 0;
+
+ private OpenCvJavaCameraView mOpenCvCameraView;
+
+ private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
@@ -34,44 +63,41 @@ public class FdActivity extends Activity {
{
Log.i(TAG, "OpenCV loaded successfully");
- // Load native libs after OpenCV initialization
+ // Load native library after(!) OpenCV initialization
System.loadLibrary("detection_based_tracker");
- // Create and set View
- mView = new FdView(mAppContext);
- mView.setDetectorType(mDetectorType);
- mView.setMinFaceSize(0.2f);
- setContentView(mView);
+ try {
+ // load cascade file from application resources
+ InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
+ File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
+ mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
+ FileOutputStream os = new FileOutputStream(mCascadeFile);
- // 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();
+ byte[] buffer = new byte[4096];
+ int bytesRead;
+ while ((bytesRead = is.read(buffer)) != -1) {
+ os.write(buffer, 0, bytesRead);
}
- });
- MarketErrorMessage.show();
+ is.close();
+ os.close();
+
+ mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
+ if (mJavaDetector.empty()) {
+ Log.e(TAG, "Failed to load cascade classifier");
+ mJavaDetector = null;
+ } else
+ Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
+
+ mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);
+
+ cascadeDir.delete();
+
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
+ }
+
+ mOpenCvCameraView.enableView();
} break;
default:
{
@@ -83,30 +109,12 @@ public class FdActivity extends Activity {
public FdActivity() {
mDetectorName = new String[2];
- mDetectorName[FdView.JAVA_DETECTOR] = "Java";
- mDetectorName[FdView.NATIVE_DETECTOR] = "Native (tracking)";
+ mDetectorName[JAVA_DETECTOR] = "Java";
+ mDetectorName[NATIVE_DETECTOR] = "Native (tracking)";
+
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) {
@@ -114,6 +122,75 @@ public class FdActivity extends Activity {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ setContentView(R.layout.face_detect_surface_view);
+
+ mOpenCvCameraView = (OpenCvJavaCameraView)findViewById(R.id.fd_activity_surface_view);
+ mOpenCvCameraView.setCvCameraViewListener(this);
+ }
+
+ @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) {
+ mGray = new Mat();
+ mRgba = new Mat();
+ }
+
+ public void onCameraViewStopped() {
+ mGray.release();
+ mRgba.release();
+ }
+
+ public Mat onCameraFrame(Mat inputFrame) {
+
+ inputFrame.copyTo(mRgba);
+ Imgproc.cvtColor(inputFrame, mGray, Imgproc.COLOR_RGBA2GRAY);
+
+ if (mAbsoluteFaceSize == 0) {
+ int height = mGray.rows();
+ if (Math.round(height * mRelativeFaceSize) > 0) {
+ mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
+ }
+ mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
+ }
+
+ MatOfRect faces = new MatOfRect();
+
+ if (mDetectorType == JAVA_DETECTOR) {
+ if (mJavaDetector != null)
+ mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
+ new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
+ }
+ else if (mDetectorType == NATIVE_DETECTOR) {
+ if (mNativeDetector != null)
+ mNativeDetector.detect(mGray, faces);
+ }
+ else {
+ Log.e(TAG, "Detection method is not selected!");
+ }
+
+ Rect[] facesArray = faces.toArray();
+ for (int i = 0; i < facesArray.length; i++)
+ Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
+
+ return mRgba;
}
@Override
@@ -131,18 +208,37 @@ public class FdActivity extends Activity {
public boolean onOptionsItemSelected(MenuItem item) {
Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
if (item == mItemFace50)
- mView.setMinFaceSize(0.5f);
+ setMinFaceSize(0.5f);
else if (item == mItemFace40)
- mView.setMinFaceSize(0.4f);
+ setMinFaceSize(0.4f);
else if (item == mItemFace30)
- mView.setMinFaceSize(0.3f);
+ setMinFaceSize(0.3f);
else if (item == mItemFace20)
- mView.setMinFaceSize(0.2f);
+ setMinFaceSize(0.2f);
else if (item == mItemType) {
mDetectorType = (mDetectorType + 1) % mDetectorName.length;
item.setTitle(mDetectorName[mDetectorType]);
- mView.setDetectorType(mDetectorType);
+ setDetectorType(mDetectorType);
}
return true;
}
+
+ private void setMinFaceSize(float faceSize) {
+ mRelativeFaceSize = faceSize;
+ mAbsoluteFaceSize = 0;
+ }
+
+ private void setDetectorType(int type) {
+ if (mDetectorType != type) {
+ mDetectorType = type;
+
+ if (type == NATIVE_DETECTOR) {
+ Log.i(TAG, "Detection Based Tracker enabled");
+ mNativeDetector.start();
+ } else {
+ Log.i(TAG, "Cascade detector enabled");
+ mNativeDetector.stop();
+ }
+ }
+ }
}
diff --git a/samples/android/face-detection/src/org/opencv/samples/fd/FdView.java b/samples/android/face-detection/src/org/opencv/samples/fd/FdView.java
deleted file mode 100644
index a9e4c2c095..0000000000
--- a/samples/android/face-detection/src/org/opencv/samples/fd/FdView.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package org.opencv.samples.fd;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import org.opencv.android.Utils;
-import org.opencv.core.Core;
-import org.opencv.core.Mat;
-import org.opencv.core.MatOfRect;
-import org.opencv.core.Rect;
-import org.opencv.core.Scalar;
-import org.opencv.core.Size;
-import org.opencv.highgui.Highgui;
-import org.opencv.highgui.VideoCapture;
-import org.opencv.objdetect.CascadeClassifier;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.util.Log;
-import android.view.SurfaceHolder;
-
-class FdView extends SampleCvViewBase {
- private static final String TAG = "OCVSample::View";
- private Mat mRgba;
- private Mat mGray;
- private File mCascadeFile;
- private CascadeClassifier mJavaDetector;
- private DetectionBasedTracker mNativeDetector;
-
- private static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);
-
- public static final int JAVA_DETECTOR = 0;
- public static final int NATIVE_DETECTOR = 1;
-
- private int mDetectorType = JAVA_DETECTOR;
-
- private float mRelativeFaceSize = 0;
- private int mAbsoluteFaceSize = 0;
-
- public void setMinFaceSize(float faceSize) {
- mRelativeFaceSize = faceSize;
- mAbsoluteFaceSize = 0;
- }
-
- public void setDetectorType(int type) {
- if (mDetectorType != type) {
- mDetectorType = type;
-
- if (type == NATIVE_DETECTOR) {
- Log.i(TAG, "Detection Based Tracker enabled");
- mNativeDetector.start();
- } else {
- Log.i(TAG, "Cascade detector enabled");
- mNativeDetector.stop();
- }
- }
- }
-
- public FdView(Context context) {
- super(context);
-
- try {
- // load cascade file from application resources
- InputStream is = context.getResources().openRawResource(R.raw.lbpcascade_frontalface);
- File cascadeDir = context.getDir("cascade", Context.MODE_PRIVATE);
- mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
- FileOutputStream os = new FileOutputStream(mCascadeFile);
-
- byte[] buffer = new byte[4096];
- int bytesRead;
- while ((bytesRead = is.read(buffer)) != -1) {
- os.write(buffer, 0, bytesRead);
- }
- is.close();
- os.close();
-
- mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
- if (mJavaDetector.empty()) {
- Log.e(TAG, "Failed to load cascade classifier");
- mJavaDetector = null;
- } else
- Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());
-
- mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);
-
- cascadeDir.delete();
-
- } catch (IOException e) {
- e.printStackTrace();
- Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
- }
-
- Log.i(TAG, "Instantiated new " + this.getClass());
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- Log.i(TAG, "called surfaceCreated");
- synchronized (this) {
- // initialize Mats before usage
- mGray = new Mat();
- mRgba = new Mat();
- }
-
- super.surfaceCreated(holder);
- }
-
- @Override
- protected Bitmap processFrame(VideoCapture capture) {
- capture.retrieve(mRgba, Highgui.CV_CAP_ANDROID_COLOR_FRAME_RGBA);
- capture.retrieve(mGray, Highgui.CV_CAP_ANDROID_GREY_FRAME);
-
- if (mAbsoluteFaceSize == 0) {
- int height = mGray.rows();
- if (Math.round(height * mRelativeFaceSize) > 0) {
- mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
- }
- mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
- }
-
- MatOfRect faces = new MatOfRect();
-
- if (mDetectorType == JAVA_DETECTOR) {
- if (mJavaDetector != null)
- mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
- new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
- }
- else if (mDetectorType == NATIVE_DETECTOR) {
- if (mNativeDetector != null)
- mNativeDetector.detect(mGray, faces);
- }
- else {
- Log.e(TAG, "Detection method is not selected!");
- }
-
- Rect[] facesArray = faces.toArray();
- for (int i = 0; i < facesArray.length; i++)
- Core.rectangle(mRgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
-
- Bitmap bmp = Bitmap.createBitmap(mRgba.cols(), mRgba.rows(), Bitmap.Config.ARGB_8888);
-
- try {
- Utils.matToBitmap(mRgba, bmp);
- } catch(Exception e) {
- Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
- bmp.recycle();
- bmp = null;
- }
-
- return bmp;
- }
-
- @Override
- public void run() {
- super.run();
-
- synchronized (this) {
- // Explicitly deallocate Mats
- if (mRgba != null)
- mRgba.release();
- if (mGray != null)
- mGray.release();
- if (mCascadeFile != null)
- mCascadeFile.delete();
- if (mNativeDetector != null)
- mNativeDetector.release();
-
- mRgba = null;
- mGray = null;
- mCascadeFile = null;
- }
- }
-}
diff --git a/samples/android/face-detection/src/org/opencv/samples/fd/SampleCvViewBase.java b/samples/android/face-detection/src/org/opencv/samples/fd/SampleCvViewBase.java
deleted file mode 100644
index 42d5b34e29..0000000000
--- a/samples/android/face-detection/src/org/opencv/samples/fd/SampleCvViewBase.java
+++ /dev/null
@@ -1,123 +0,0 @@
-package org.opencv.samples.fd;
-
-import java.util.List;
-
-import org.opencv.core.Size;
-import org.opencv.highgui.VideoCapture;
-import org.opencv.highgui.Highgui;
-
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.util.Log;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-
-public abstract class SampleCvViewBase extends SurfaceView implements SurfaceHolder.Callback, Runnable {
- private static final String TAG = "OCVSample::BaseView";
-
- private SurfaceHolder mHolder;
- private VideoCapture mCamera;
- private FpsMeter mFps;
-
- public SampleCvViewBase(Context context) {
- super(context);
- mHolder = getHolder();
- mHolder.addCallback(this);
- mFps = new FpsMeter();
- Log.i(TAG, "Instantiated new " + this.getClass());
- }
-
- public synchronized boolean openCamera() {
- Log.i(TAG, "Opening Camera");
- mCamera = new VideoCapture(Highgui.CV_CAP_ANDROID);
- if (!mCamera.isOpened()) {
- releaseCamera();
- Log.e(TAG, "Can't open native camera");
- return false;
- }
- return true;
- }
-
- public synchronized void releaseCamera() {
- Log.i(TAG, "Releasing Camera");
- if (mCamera != null) {
- mCamera.release();
- mCamera = null;
- }
- }
-
- public synchronized void setupCamera(int width, int height) {
- if (mCamera != null && mCamera.isOpened()) {
- Log.i(TAG, "Setup Camera - " + width + "x" + height);
- List sizes = mCamera.getSupportedPreviewSizes();
- int mFrameWidth = width;
- int mFrameHeight = height;
-
- // selecting optimal camera preview size
- {
- double minDiff = Double.MAX_VALUE;
- for (Size size : sizes) {
- if (Math.abs(size.height - height) < minDiff) {
- mFrameWidth = (int) size.width;
- mFrameHeight = (int) size.height;
- minDiff = Math.abs(size.height - height);
- }
- }
- }
-
- mCamera.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, mFrameWidth);
- mCamera.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, mFrameHeight);
- }
- }
-
- public void surfaceChanged(SurfaceHolder _holder, int format, int width, int height) {
- Log.i(TAG, "called surfaceChanged");
- 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");
- }
- protected abstract Bitmap processFrame(VideoCapture capture);
-
- public void run() {
- Log.i(TAG, "Started processing thread");
- mFps.init();
-
- while (true) {
- Bitmap bmp = null;
-
- synchronized (this) {
- if (mCamera == null)
- break;
-
- if (!mCamera.grab()) {
- Log.e(TAG, "mCamera.grab() failed");
- break;
- }
-
- bmp = processFrame(mCamera);
-
- mFps.measure();
- }
-
- if (bmp != null) {
- Canvas canvas = mHolder.lockCanvas();
- if (canvas != null) {
- canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
- canvas.drawBitmap(bmp, (canvas.getWidth() - bmp.getWidth()) / 2, (canvas.getHeight() - bmp.getHeight()) / 2, null);
- mFps.draw(canvas, (canvas.getWidth() - bmp.getWidth()) / 2, 0);
- mHolder.unlockCanvasAndPost(canvas);
- }
- bmp.recycle();
- }
- }
- Log.i(TAG, "Finished processing thread");
- }
-}
\ No newline at end of file