Android人脸检测1(静态图片)
搭建Android人脸识别环境花了很长时间(可以查看之前的文章),解决Android开发中的杂七杂八小问题也耗时不少.
今天记录一下,点击选择照片或者拍照上传照片进行人脸检测的小demo.
(android.media.FaceDetector;方法)
先看效果图:
手机在电脑拍摄的图片:
要点说明:
参考: http://blog.csdn.net/zhandoushi1982/article/details/8613916
1, 必须要把bitmap转换RGB_565才能检测
bitmap565 = bitmap.copy(Bitmap.Config.RGB_565, true);
2, 给bitmap画框
Canvas canvas = new Canvas(bitmap565);
参考: https://stackoverflow.com/questions/4918079/android-drawing-a-canvas-to-an-imageview
3, 调用系统相册相机需要配置权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
4, 调用 FaceDetector 感觉很慢,而且会识别多余人脸,最后附图.
5, 后续做动态人脸检测.
代码:
package com.***.facedetection; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PointF; import android.media.FaceDetector; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.TextView; import android.widget.Toast; import java.io.File; public class MainActivity extends AppCompatActivity { private static String CAMERAIMAGENAME = "image.jpg"; private customImageButton imageButton; private TextView textView; private Bitmap bitmap; private Bitmap resizeBitmap; private int numberOfFaceDetected; private FaceDetector.Face[] myFace; private Bitmap bitmap565; private Toast toast; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); textView = (TextView) findViewById(R.id.tv_face); imageButton = (customImageButton) findViewById(R.id.iv_face); imageButton.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); } /** * 点击添加照片事件 * * @param v */ public void onClick(View v) { int bt_id = v.getId(); switch (bt_id) { case R.id.addPic: // 添加照片 // 打开本地相册 Intent intent1 = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI); startActivityForResult(intent1, 101); break; case R.id.takePhoto: // 拍照 // 打开本地相机 Intent intent2 = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE); Uri imageUri = Uri.fromFile(new File(Environment.getExternalStorageDirectory(), CAMERAIMAGENAME)); intent2.putExtra(MediaStore.EXTRA_OUTPUT, imageUri); startActivityForResult(intent2, 102); break; default: break; } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // 加判断 不选择照片或者不拍照时不闪退 //Log.e("data", String.valueOf(data)); //if (data == null) //return; bitmap = null; switch (requestCode) { // 选择图片库的图片 case 101: if (resultCode == RESULT_OK) { try { Uri uri = data.getData(); bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri); } catch (Exception e) { e.printStackTrace(); } } break; // 表示调用本地照相机拍照 case 102: if (resultCode == RESULT_OK) { //Bundle bundle = data.getExtras(); //bm = (Bitmap) bundle.get("data"); bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory() + "/" + CAMERAIMAGENAME); } break; default: break; } Log.e("bitmap", String.valueOf(bitmap)); if (bitmap == null) { toast = Toast.makeText(MainActivity.this, "未选择图像", Toast.LENGTH_SHORT); toast.show(); return; } // 转换 释放 bitmap565 = bitmap.copy(Bitmap.Config.RGB_565, true); if (!bitmap.isRecycled()) bitmap.recycle(); // 识别图片 detectFace(); // 画框 drawFace(); // 将照片剪裁 bitmap将被释放重新赋值 int ibWidth = imageButton.getWidth(); int ibHeight = imageButton.getHeight(); resizeBitmap = imageButton.cropBitmap(bitmap565, ibWidth, ibHeight); imageButton.setBitmap(resizeBitmap); } private void detectFace() { int numberOfFace = 12; FaceDetector myFaceDetect; int imageWidth = bitmap565.getWidth(); int imageHeight = bitmap565.getHeight(); myFace = new FaceDetector.Face[numberOfFace]; myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace); numberOfFaceDetected = myFaceDetect.findFaces(bitmap565, myFace); textView.setText(String.format("检测到%1$d个人脸", numberOfFaceDetected)); } private void drawFace() { Canvas canvas = new Canvas(bitmap565); // canvas.drawBitmap(bitmap565, 0, 0, null); Paint myPaint = new Paint(); myPaint.setColor(Color.GREEN); myPaint.setStyle(Paint.Style.STROKE); myPaint.setStrokeWidth(3); for (int i = 0; i < numberOfFaceDetected; i++) { FaceDetector.Face face = myFace[i]; PointF myMidPoint = new PointF(); face.getMidPoint(myMidPoint); float myEyesDistance = face.eyesDistance(); canvas.drawRect((int) (myMidPoint.x - myEyesDistance * 1.5), (int) (myMidPoint.y - myEyesDistance * 1.5), (int) (myMidPoint.x + myEyesDistance * 1.5), (int) (myMidPoint.y + myEyesDistance * 1.8), myPaint); } } }
自定义ImageButton类,可以按比例缩放bitmap适应ImageButton居中显示:
package com.***.facedetection; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.Matrix; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; public class customImageButton extends LinearLayout { private TextView _textView; private ImageView _imageView; public customImageButton(Context context, AttributeSet attrs) { super(context, attrs); _imageView = new ImageView(context, attrs); _imageView.setPadding(2, 2, 2, 2); _textView = new TextView(context, attrs); _textView.setBackgroundColor(Color.TRANSPARENT); _textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); _textView.setPadding(0, 0, 0, 0); setClickable(true); setFocusable(true); setOrientation(LinearLayout.VERTICAL); addView(_textView); addView(_imageView); } public void setText(String text) { _textView.setText(text); } public void setButtonEnable(Boolean bool) { _imageView.setEnabled(bool); } public void clearnImage() { _textView.setVisibility(View.VISIBLE); _imageView.setImageDrawable(null); } public void setBitmap(Bitmap bm) { _textView.setVisibility(View.GONE); _imageView.setImageDrawable(null); _imageView.setImageBitmap(bm); } public Bitmap cropBitmap(Bitmap bm, int ivbWidth, int ivbHeight) { Bitmap resizeBmp = null; try { Matrix matrix = new Matrix(); float scale; if (ivbWidth <= ivbHeight) { scale = (float) ivbWidth / bm.getWidth(); matrix.postScale(scale, scale); //长和宽放大缩小的比例 resizeBmp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); } else { scale = (float) ivbHeight / bm.getHeight(); matrix.postScale(scale, scale); resizeBmp = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); } Log.e("scale", scale + ""); if (!bm.isRecycled()) bm.recycle(); } catch (Exception e) { e.printStackTrace(); } return resizeBmp; } }
布局:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.***.facedetection.MainActivity"> <com.***.facedetection.customImageButton android:id="@+id/iv_face" android:layout_width="match_parent" android:layout_height="450dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <TextView android:id="@+id/tv_face" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="20dp" android:text="未检测到人脸" android:textColor="@color/colorAccent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toTopOf="@+id/takePhoto" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <Button android:id="@+id/takePhoto" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginBottom="10dp" android:onClick="onClick" android:text="拍照" android:textSize="16sp" app:layout_constraintBottom_toTopOf="@+id/addPic" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> <Button android:id="@+id/addPic" android:layout_width="0dp" android:layout_height="wrap_content" android:onClick="onClick" android:text="选择图片" android:textSize="16sp" android:layout_marginBottom="10dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" /> </android.support.constraint.ConstraintLayout>
检测多余人脸: