Now we are going to basically take this post, where we detected the faces with OpenCV in Android, and replace the face detection portion (CascadeClassifier + detectMultiScale) and replace it for FaceDetector.findFaces method in Android SDK. So, everything else is the same as that post, only thing is that we need to:
- Convert Mat to Bitmap on the right format for the face detection method (RGB_565).
- Do the face detection with the Android SDK.
Note: it seems that the FaceDetector used here is not the one my built-in camera app is using. I know this from simple performance evaluation. For instance, if I rotate the camera, the camera app still detects my face but FaceDetector loses it. It seems that there is one more way in the SDK to detect faces starting from Android 4.0 which I have not tried (so, don't now its performance). Still, probably that is not what is used in the camera app. This post here points to the same and has no answer, in case anybody wants to get some StackOverflow points :). I agree though that using the built-in camera app would likely narrow my software down to my phone.
_3DActivity.java
/*
* Working demo of face detection (remember to put the camera in horizontal)
* using OpenCV/CascadeClassifier.
* Posted in http://cell0907.blogspot.com/2014/01/detecting-faces-in-android-with-opencv.html
*/
package com.cell0907.td1;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Core;
import org.opencv.core.CvException;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import org.opencv.core.Point;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.media.FaceDetector;
import android.media.FaceDetector.Face;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SurfaceView;
import android.view.WindowManager;
public class _3DActivity extends Activity implements CvCameraViewListener2 {
private static final int VIEW_MODE_CAMERA = 0;
private static final int VIEW_MODE_GRAY = 1;
private static final int VIEW_MODE_FACES = 2;
private MenuItem mItemPreviewRGBA;
private MenuItem mItemPreviewGrey;
private MenuItem mItemPreviewFaces;
private int mViewMode;
private Mat mRgba;
private Mat mGrey;
private int screen_w, screen_h;
private Tutorial3View mOpenCvCameraView;
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
// Load native library after(!) OpenCV initialization
mOpenCvCameraView.enableView();
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
public _3DActivity() {
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.tutorial2_surface_view);
mOpenCvCameraView = (Tutorial3View) findViewById(R.id.tutorial2_activity_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
@Override
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
public void onCameraViewStarted(int width, int height) {
screen_w=width;
screen_h=height;
mRgba = new Mat(screen_w, screen_h, CvType.CV_8UC4);
mGrey = new Mat(screen_w, screen_h, CvType.CV_8UC1);
Log.v("MyActivity","Height: "+height+" Width: "+width);
}
public void onCameraViewStopped() {
mRgba.release();
mGrey.release();
}
public Mat onCameraFrame(CvCameraViewFrame inputFrame) {
long startTime = System.nanoTime();
long endTime;
boolean show=true;
mRgba=inputFrame.rgba();
if (mViewMode==VIEW_MODE_CAMERA) {
endTime = System.nanoTime();
if (show==true) Log.v("MyActivity","Elapsed time: "+ (float)(endTime - startTime)/1000000+"ms");
return mRgba;
}
if (mViewMode==VIEW_MODE_GRAY){
Imgproc.cvtColor( mRgba, mGrey, Imgproc.COLOR_BGR2GRAY);
endTime = System.nanoTime();
if (show==true) Log.v("MyActivity","Elapsed time: "+ (float)(endTime - startTime)/1000000+"ms");
return mGrey;
}
// REDUCE THE RESOLUTION TO EXPEDITE THINGS
Mat low_res = new Mat(screen_w, screen_h, CvType.CV_8UC4);
Imgproc.resize(mRgba,low_res,new Size(),0.25,0.25,Imgproc.INTER_LINEAR);
Bitmap bmp = null;
try {
bmp = Bitmap.createBitmap(low_res.width(), low_res.height(), Bitmap.Config.RGB_565);
Utils.matToBitmap(low_res, bmp);
}
catch (CvException e){Log.v("MyActivity",e.getMessage());}
int maxNumFaces = 1; // Set this to whatever you want
FaceDetector fd = new FaceDetector((int)(screen_w/4),(int)(screen_h/4),
maxNumFaces);
Face[] faces = new Face[maxNumFaces];
try {
int numFacesFound = fd.findFaces(bmp, faces);
if (numFacesFound<maxNumFaces) maxNumFaces=numFacesFound;
for (int i = 0; i < maxNumFaces; ++i) {
Face face = faces[i];
PointF MidPoint = new PointF();
face.getMidPoint(MidPoint);
/* Log.v("MyActivity","Face " + i + " found with " + face.confidence() + " confidence!");
Log.v("MyActivity","Face " + i + " eye distance " + face.eyesDistance());
Log.v("MyActivity","Face " + i + " midpoint (between eyes) " + MidPoint);*/
Point center= new Point(4*MidPoint.x, 4*MidPoint.y);
Core.ellipse( mRgba, new Point(center.x,center.y), new Size(8*face.eyesDistance(), 8*face.eyesDistance()), 0, 0, 360, new Scalar( 255, 0, 255 ), 4, 8, 0 );
}
} catch (IllegalArgumentException e) {
// From Docs:
// if the Bitmap dimensions don't match the dimensions defined at initialization
// or the given array is not sized equal to the maxFaces value defined at
// initialization
Log.v("MyActivity","Argument dimensions wrong");
}
if (mViewMode==VIEW_MODE_FACES) {
endTime = System.nanoTime();
if (show==true) Log.v("MyActivity","Elapsed time: "+ (float)(endTime - startTime)/1000000+"ms");
return mRgba;
//return low_res;
}
return mRgba;
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
mItemPreviewRGBA = menu.add("RGBA");
mItemPreviewGrey = menu.add("Grey");
mItemPreviewFaces = menu.add("Faces");
return true;
}
public boolean onOptionsItemSelected(MenuItem item) {
if (item == mItemPreviewRGBA) {
mViewMode = VIEW_MODE_CAMERA;
} else if (item == mItemPreviewGrey) {
mViewMode = VIEW_MODE_GRAY;
} else if (item == mItemPreviewFaces) {
mViewMode = VIEW_MODE_FACES;
}
return true;
}
}
For the rest of the files, please check the original post.
Just a final note... Somebody may wonder why I am mixing OpenCV with face detection from Android SDK. I am using OpenCV because it allows me to display something completely unrelated to what the camera is capturing (I need that for my final app). Although I found a method to do that without OpenCV I think it doesn't work with all the devices out there. And I use the face detection from Android SDK because I think it is more robust and still works, for instance, when turning the head... The weird thing is that it doesn't seem to work as good as the one I get on my camera app (the one that comes from factory with my phone, and HTC One). I also thought it would be faster, but actually looks slower...
PS.: Reference I used...
No comments:
Post a Comment