Android实现人脸识别的详细过程

来源:互联网 发布:日本留学生中国知乎 编辑:程序博客网 时间:2024/06/05 17:27
照相时,在预览画面上提示用户人脸的位置,并完成自动对焦等,是个错的应用; 下面是实现细节,我们知道在android的代码中已有人脸识别的底层算法代码,而且在framework层也封了调用的API函数
  • extern/neven 目录下是实现人脸识别的算法代码。
  • 添加获取照相时预览图片数据,可以在onPreviewFrame回调函数中得。在开始预览的地方,用
  • mCameraDevice.setPreviewCallback(mPreviewCallback);设置预览回调函数。
  1. import android.media.FaceDetector;

  2. import android.media.FaceDetector.Face;

  3. //Harrison add 

  4. private void DrawRectOnFace() {

  5.   if (numberOfFaceDetected != 0) {

  6.    Face mFace1 = mFace[0];

  7.    PointF midPoint = new PointF(); 

  8.    mFace1.getMidPoint(midPoint);

  9.      if ((Math.abs(mPreMidPoint.x-midPoint.x) < 50) && (Math.abs(mPreMidPoint.y-midPoint.y) < 50)) {

  10.     Log.i("Harrison", "not draw Rect .");

  11.     return ;

  12.    }

  13.    mPreMidPoint.x = midPoint.x;

  14.    mPreMidPoint.y = midPoint.y;

  15.    mFindFaceView.setVisibility(View.VISIBLE);

  16.   } else {

  17.    mPreMidPoint.x = 0;

  18.    mPreMidPoint.y = 0;

  19.    mFindFaceView.clearDraw();

  20.    mFindFaceView.setVisibility(View.GONE);

  21.    return;

  22.   }

  23.   mFindFaceView.drawRects(mFace, numberOfFaceDetected);

  24. }

  25. //调用API找人脸,需要import进软件包哦!
  26. private void FindFacesInBitmap(Bitmap myBitmap) {

  27.   imageWidth = myBitmap.getWidth();

  28.   imageHeight = myBitmap.getHeight();

  29.   Log.i("Harrison", "imageWidth="+imageWidth+",  imageHeight="+imageHeight);

  30.   mFace = new FaceDetector.Face[numberOfFace];

  31.   mFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);

  32.   numberOfFaceDetected = mFaceDetect.findFaces(myBitmap, mFace);

  33.   Log.i("Harrison", "numberOfFaceDetected="+numberOfFaceDetected);

  34. }


  35. private Bitmap rotateMyBitmap(Bitmap bitmap) {
  36.   int width = bitmap.getWidth();  

  37.   int height = bitmap.getHeight();   
  38.   Matrix matrix = new Matrix();  

  39.   matrix.postRotate(90);
  40.   Bitmap rotateBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);



  41.   return rotateBitmap;

  42. }
  43. private Bitmap scaleMyBitmap(Bitmap bitmap) {
  44.   int width = bitmap.getWidth();  

  45.   int height = bitmap.getHeight();   



  46.   int nWidth = mFindFaceView.getFaceViewWidth();;  

  47.   int nHeight = mFindFaceView.getFaceViewHeight();   

  48. // Log.i("Harrison", "nWidth="+nWidth+",  nHeight"+nHeight);

  49.    

  50.   float scaleWidth = ((float) nWidth)/width;   

  51.   float scaleHeight = ((float)nHeight)/height;  

  52.   

  53.   Matrix matrix = new Matrix();  

  54.   matrix.postScale(scaleWidth, scaleHeight);  



  55.   Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

  56.   

  57.   return resizedBitmap;

  58. }
  59. //处理图片格式,一般摄像头抓到的数据为ImageFormat.NV21,不同的格式,需要调整的。
  60. private void decodeToBitMap(byte[] data, android.hardware.Camera _camera) {

  61.   mCameraDevice.setPreviewCallback(null);

  62.   Size size = mCameraDevice.getParameters().getPreviewSize();

  63.   //FileOutputStream outStream = null;

  64.   try {

  65.    YuvImage image = new YuvImage(data, ImageFormat.NV21, size.width, size.height, null);
  66.    if (image != null) {

  67.     ByteArrayOutputStream stream = new ByteArrayOutputStream();

  68.     image.compressToJpeg(new Rect(0, 0, size.width, size.height), 80, stream);
  69.   //  outStream = new FileOutputStream(String.format("/sdcard/%d.jpg", System.currentTimeMillis()));

  70.   //  outStream.write(stream.toByteArray());

  71.   //  outStream.close();

  72.   //  Log.i("Harrison", "write file to sdcard.");

  73. //在我的手机上有两种预览模式,发现全屏模式时需要调整图片的大小才能正确定位。
  74.     Bitmap myBitmap=BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());

  75.      stream.close();

  76.     if (mPreviewLayoutProxy.getFullScreenMode()) { // fullscreen mode 

  77.      Bitmap tmpScaleBmp=null;

  78.      Bitmap tmpRotateBmp=null;
  79. //手机是竖屏横排是与其别的哦

  80.      if (((mOrientation/90) == 0) || ((mOrientation/90) == 2)) {  

  81.       tmpRotateBmp = rotateMyBitmap(myBitmap);

  82.       tmpScaleBmp = scaleMyBitmap(tmpRotateBmp);

  83.       FindFacesInBitmap(tmpScaleBmp);

  84.       if (tmpRotateBmp != null) {

  85.        tmpRotateBmp.recycle();

  86.        tmpRotateBmp = null;

  87.       }

  88.      } else {

  89.       FindFacesInBitmap(scaleMyBitmap(myBitmap));

  90.      }

  91.      if (tmpScaleBmp != null) {

  92.       tmpScaleBmp.recycle();

  93.       tmpScaleBmp = null;

  94.      }

  95.     } else { //normal mode

  96.      FindFacesInBitmap(myBitmap);

  97.     }

  98.     DrawRectOnFace();

  99.     if (myBitmap != null) {

  100.      myBitmap.recycle();

  101.      myBitmap = null;

  102.     }

  103.    }

  104.   } catch (Exception ex) {

  105.    Log.e("Sys", "Error:" + ex.getMessage());

  106.   } 

  107.   mCameraDevice.setPreviewCallback(mPreviewCallback);

  108. }



  109. private  final class PostPreviewCallback implements PreviewCallback {

  110.   @Override

  111.   public void onPreviewFrame(byte[] data, android.hardware.Camera camera) {
  112.      decodeToBitMap(data, camera);

  113.    }

  114. }
复制代码
我们知道,相机预览是用 SurfaceView来显示图片的;在我们画提示框时,不能直接用那个view的,会出现黑屏的状态,预览的画面也不流畅的。添加一个一样大小的SurfaceView来提示。
在xml布局中添加
  1. <SurfaceView android:id="@+id/camera_preview"

  2.                     android:layout_width="match_parent"

  3.                     android:layout_height="match_parent"/>

  4.    <!-- Harrison add finding faces Rectangle-->

  5.    <com.android.camera.FindFaceView

  6.     android:id="@+id/faces_rectangle"  

  7.        android:layout_width="fill_parent"  

  8.     android:layout_height="fill_parent" />

  9.    <!-- end add 20121119 -->
复制代码


我的画提示框代码:
  1. package com.android.camera;
  2. import android.content.Context;

  3. import android.graphics.Canvas;

  4. import android.graphics.Bitmap;

  5. import android.graphics.Color;

  6. import android.graphics.Paint;

  7. import android.graphics.Rect; 

  8. import android.graphics.Paint.Style;

  9. import android.graphics.PixelFormat;

  10. import android.graphics.PorterDuffXfermode;

  11. import android.graphics.PorterDuff;

  12. import android.util.AttributeSet;

  13. import android.util.Log;

  14. import android.view.SurfaceHolder;

  15. import android.view.SurfaceView;

  16. import android.view.View;

  17. import android.graphics.PointF;

  18. import android.media.FaceDetector;

  19. import android.media.FaceDetector.Face;
  20. public class FindFaceView extends SurfaceView implements SurfaceHolder.Callback{
  21. protected SurfaceHolder sh;

  22. private  SurfaceHolder mCameraSh;

  23. private int mWidth;

  24. private int mHeight;

  25. private float mEyesDistance;
  26. public FindFaceView(Context context, AttributeSet attrs) {

  27.   super(context, attrs);

  28.   // TODO Auto-generated constructor stub

  29.   sh = getHolder();

  30.   sh.addCallback(this);

  31.   sh.setFormat(PixelFormat.TRANSPARENT);

  32.   setZOrderOnTop(true);

  33. }
  34. public void surfaceChanged(SurfaceHolder arg0, int arg1, int w, int h) {

  35.   // TODO Auto-generated method stub

  36.   mWidth = w;

  37.   mHeight = h;

  38. }
  39. public void surfaceCreated(SurfaceHolder arg0) {

  40.   // TODO Auto-generated method stub
  41. }
  42. public void surfaceDestroyed(SurfaceHolder arg0) {

  43.   // TODO Auto-generated method stub
  44. }
  45. void setCameraPreviewSurfaceHolder(SurfaceHolder  sh) {

  46.   mCameraSh = sh;

  47. }

  48. public int getFaceViewWidth() {

  49.   return mWidth;

  50. }

  51. public int getFaceViewHeight() {

  52.   return mHeight;

  53. }
  54. void clearDraw() {

  55.   Canvas canvas = sh.lockCanvas();

  56.   Paint clipPaint = new Paint();

  57.   clipPaint.setAntiAlias(true);

  58.   clipPaint.setStyle(Paint.Style.STROKE);

  59.   clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

  60.   canvas.drawPaint(clipPaint);

  61.   sh.unlockCanvasAndPost(canvas);

  62. }


  63.      public void drawRects(FaceDetector.Face[] mFace, int numberOfFaceDetected) {

  64.   Canvas canvas = sh.lockCanvas();
  65.   Paint clipPaint = new Paint();

  66.   clipPaint.setAntiAlias(true);

  67.   clipPaint.setStyle(Paint.Style.STROKE);

  68.   clipPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));

  69.   canvas.drawPaint(clipPaint);



  70.   canvas.drawColor(Color.TRANSPARENT);

  71.   Paint p = new Paint();

  72.   p.setAntiAlias(true);

  73.   p.setColor(Color.RED);

  74.   p.setStyle(Style.STROKE);
  75.   for (int i = 0; i < numberOfFaceDetected; i++) {

  76. //  if (0 == i) {

  77. //   p.setColor(Color.WHITE);

  78. //  } else {

  79. //   p.setColor(Color.GRAY);

  80. //  }

  81.    Face face = mFace[i];

  82.    PointF myMidPoint = new PointF();

  83.    face.getMidPoint(myMidPoint);

  84.    mEyesDistance = face.eyesDistance();

  85.    Log.i("Harrison", "i="+i+"("+myMidPoint.x+", "+myMidPoint.y+")");

  86.    canvas.drawRect((int)(myMidPoint.x-mEyesDistance),

  87.      (int)(myMidPoint.y-mEyesDistance),

  88.      (int)(myMidPoint.x+mEyesDistance),

  89.      (int)(myMidPoint.y+mEyesDistance), 

  90.      p);

  91.   }

  92.   sh.unlockCanvasAndPost(canvas);

  93.   }
  94. //测试两个View是否错移

  95. public void drawBitmap(Bitmap myBitmap) {

  96.   Canvas canvas = sh.lockCanvas();

  97.   canvas.drawBitmap(myBitmap, 0, 0, null);

  98.   sh.unlockCanvasAndPost(canvas);

  99. // mImage.setImageBitmap(myBitmap);

  100. // mImage.invalidate();

  101. }

  102. public void doDraw() { 

  103.   Canvas canvas = sh.lockCanvas(); 

  104.   canvas.drawColor(Color.TRANSPARENT);// 这里是绘制背景 

  105.   Paint p = new Paint(); // 笔触 

  106.   p.setAntiAlias(true); // 反锯齿 

  107.   p.setColor(Color.RED); 

  108.   p.setStyle(Style.STROKE); 

  109.   canvas.drawLine(mWidth/2 - 100, 0, mWidth/2 - 100, mHeight, p); 

  110.   canvas.drawLine(mWidth/2 + 100, 0, mWidth/2 + 100, mHeight, p); 

  111.   // ------------------------

  112.   // 画边框--------------------- 

  113.   Rect rec = canvas.getClipBounds(); 

  114.   rec.bottom--; 

  115.   rec.right--; 

  116.   p.setColor(Color.GRAY);

  117.   // 颜色 

  118.   p.setStrokeWidth(5); 

  119.   canvas.drawRect(rec, p); 

  120.   // 提交绘制 

  121.   sh.unlockCanvasAndPost(canvas); 



  122. }
复制代码