前段时间经理让做一个截取人脸部分的Demo,花了不少时间才算搞定,闲来无事,总结一下。
android是通过检测两眼的位置来判断和获取人脸位置,两眼之间的距离和位置,通过API可以直接得到,代码如下:
1 package org.yanzi.testfacedetect; 2 3 import org.yanzi.util.DecodeBitmapUtils; 4 import org.yanzi.util.ImageUtil; 5 import org.yanzi.util.MyToast; 6 7 import android.app.Activity; 8 import android.content.Intent; 9 import android.database.Cursor; 10 import android.graphics.Bitmap; 11 import android.graphics.Bitmap.Config; 12 import android.graphics.BitmapFactory; 13 import android.graphics.Canvas; 14 import android.graphics.Color; 15 import android.graphics.Paint; 16 import android.graphics.Point; 17 import android.graphics.PointF; 18 import android.graphics.Rect; 19 import android.media.FaceDetector; 20 import android.media.FaceDetector.Face; 21 import android.net.Uri; 22 import android.os.Bundle; 23 import android.os.Handler; 24 import android.os.Message; 25 import android.provider.MediaStore; 26 import android.util.DisplayMetrics; 27 import android.util.Log; 28 import android.view.Menu; 29 import android.view.View; 30 import android.view.View.OnClickListener; 31 import android.view.ViewGroup; 32 import android.view.ViewGroup.LayoutParams; 33 import android.widget.Button; 34 import android.widget.ImageView; 35 import android.widget.ProgressBar; 36 import android.widget.RelativeLayout; 37 import android.widget.Toast; 38 39 public class MainActivity extends Activity { 40 static final String tag = "yan"; 41 ImageView imgView = null; 42 FaceDetector faceDetector = null; 43 FaceDetector.Face[] face; 44 Button detectFaceBtn = null, btn_startContent; 45 final int N_MAX = 2; 46 ProgressBar progressBar = null; 47 private ImageView imgviewCrop; 48 49 private String lastPicUri = null; 50 51 Bitmap srcImg = null; 52 Bitmap srcFace = null; 53 Thread checkFaceThread = new Thread() { 54 55 @Override 56 public void run() { 57 // TODO Auto-generated method stub 58 59 } 60 61 }; 62 63 class MyThread extends Thread { 64 @Override 65 public void run() { 66 super.run(); 67 Bitmap faceBitmap = detectFace(); 68 if (faceBitmap == null) { 69 mainHandler.sendEmptyMessage(3); 70 return; 71 } 72 mainHandler.sendEmptyMessage(2); 73 Message m = new Message(); 74 m.what = 0; 75 m.obj = faceBitmap; 76 mainHandler.sendMessage(m); 77 } 78 } 79 80 Handler mainHandler = new Handler() { 81 82 @Override 83 public void handleMessage(Message msg) { 84 // TODO Auto-generated method stub 85 // super.handleMessage(msg); 86 switch (msg.what) { 87 case 0: 88 Bitmap b = (Bitmap) msg.obj; 89 // imgView.setImageBitmap(b); 90 imgviewCrop.setImageBitmap(b); 91 MyToast.showToast(getApplicationContext(), "检测完毕"); 92 detectFaceBtn.setClickable(false); 93 break; 94 case 1: 95 showProcessBar(); 96 break; 97 case 2: 98 progressBar.setVisibility(View.GONE); 99 // detectFaceBtn.setClickable(false); 100 break; 101 case 3: 102 Toast.makeText(MainActivity.this, "图片不符合要求,请重新选择", 103 Toast.LENGTH_SHORT).show(); 104 progressBar.setVisibility(View.GONE); 105 break; 106 default: 107 break; 108 } 109 } 110 111 }; 112 113 @Override 114 protected void onCreate(Bundle savedInstanceState) { 115 super.onCreate(savedInstanceState); 116 setContentView(R.layout.activity_main); 117 initUI(); 118 119 detectFaceBtn.setOnClickListener(new OnClickListener() { 120 121 @Override 122 public void onClick(View v) { 123 // TODO Auto-generated method stub 124 mainHandler.sendEmptyMessage(1); 125 new MyThread().start(); 126 } 127 }); 128 129 btn_startContent = (Button) findViewById(R.id.btn_startContent); 130 btn_startContent.setOnClickListener(new OnClickListener() { 131 132 @Override 133 public void onClick(View v) { 134 Intent getImage = new Intent(Intent.ACTION_GET_CONTENT); 135 getImage.addCategory(Intent.CATEGORY_OPENABLE); 136 getImage.setType("image/jpeg"); 137 startActivityForResult(getImage, 0); 138 } 139 }); 140 141 } 142 143 @Override 144 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 145 // TODO Auto-generated method stub 146 super.onActivityResult(requestCode, resultCode, data); 147 148 if (data == null || resultCode != RESULT_OK) { 149 return; 150 } 151 String picture = getFilePath(data.getData()); 152 if (picture == null) { 153 154 Log.e(getClass().getName(), "目前只能取回相机里照片"); 155 return; 156 } 157 showPhoto(imgView, picture); 158 detectFaceBtn.setClickable(true); 159 } 160 161 /** 162 * 目前只能取回相机里照片 163 * 164 * @param uri 165 * @return 166 */ 167 private String getFilePath(Uri uri) { 168 String[] filePathColumn = { MediaStore.Images.Media.DATA }; 169 Cursor cursor = getContentResolver().query(uri, filePathColumn, null, 170 null, null); 171 if (cursor == null) { 172 return null; 173 } 174 cursor.moveToFirst(); 175 int columnIndex = cursor.getColumnIndex(filePathColumn[0]); 176 String picturePath = cursor.getString(columnIndex); 177 cursor.close(); 178 return picturePath; 179 } 180 181 public void showPhoto(ImageView photo, String picturePath) { 182 if ("".equals(picturePath)) 183 return; 184 Bitmap bitmap = BitmapFactory.decodeByteArray( 185 DecodeBitmapUtils.decodeBitmap(picturePath), 0, 186 DecodeBitmapUtils.decodeBitmap(picturePath).length); 187 // photo.setImageDrawable(new BitmapDrawable(bitmap)); 188 // photo.setSrcImage(bitmap); 189 photo.setImageBitmap(bitmap); 190 initSrcImg(bitmap); 191 } 192 193 @Override 194 public boolean onCreateOptionsMenu(Menu menu) { 195 // Inflate the menu; this adds items to the action bar if it is present. 196 getMenuInflater().inflate(R.menu.main, menu); 197 return true; 198 } 199 200 public void initUI() { 201 202 detectFaceBtn = (Button) findViewById(R.id.btn_detect_face); 203 imgView = (ImageView) findViewById(R.id.imgview); 204 imgviewCrop = (ImageView) findViewById(R.id.imgviewCrop); 205 206 initSrcImg(null); 207 208 } 209 210 private void initSrcImg(Bitmap bp) { 211 LayoutParams params = imgView.getLayoutParams(); 212 DisplayMetrics dm = getResources().getDisplayMetrics(); 213 int w_screen = dm.widthPixels; 214 // int h = dm.heightPixels; 215 if (bp == null) { 216 srcImg = BitmapFactory.decodeResource(getResources(), 217 R.drawable.kunlong); 218 } else { 219 srcImg = bp; 220 } 221 initFaceDetect(); 222 223 int h = srcImg.getHeight(); 224 int w = srcImg.getWidth(); 225 float r = (float) h / (float) w; 226 params.width = w_screen; 227 params.height = (int) (params.width * r); 228 imgView.setLayoutParams(params); 229 imgView.setImageBitmap(srcImg); 230 } 231 232 public void initFaceDetect() { 233 this.srcFace = srcImg.copy(Config.RGB_565, true); 234 int w = srcFace.getWidth(); 235 int h = srcFace.getHeight(); 236 Log.i(tag, "待检测图像: w = " + w + "h = " + h); 237 faceDetector = new FaceDetector(w, h, N_MAX); 238 face = new FaceDetector.Face[N_MAX]; 239 } 240 241 public boolean checkFace(Rect rect) { 242 int w = rect.width(); 243 int h = rect.height(); 244 int s = w * h; 245 Log.i(tag, "人脸 宽w = " + w + "高h = " + h + "人脸面积 s = " + s); 246 if (s < 10000) { 247 Log.i(tag, "无效人脸,舍弃."); 248 return false; 249 } else { 250 Log.i(tag, "有效人脸,保存."); 251 return true; 252 } 253 } 254 255 public Bitmap detectFace() { 256 // Drawable d = getResources().getDrawable(R.drawable.face_2); 257 // Log.i(tag, "Drawable尺寸 w = " + d.getIntrinsicWidth() + "h = " + 258 // d.getIntrinsicHeight()); 259 // BitmapDrawable bd = (BitmapDrawable)d; 260 // Bitmap srcFace = bd.getBitmap(); 261 262 int nFace = faceDetector.findFaces(srcFace, face); 263 Log.i(tag, "检测到人脸:n = " + nFace); 264 for (int i = 0; i < nFace; i++) { 265 Face f = face[i]; 266 PointF midPoint = new PointF(); 267 float dis = f.eyesDistance(); 268 f.getMidPoint(midPoint); 269 int dd = (int) (dis); 270 Point eyeLeft = new Point((int) (midPoint.x - dis / 2), 271 (int) midPoint.y); 272 Point eyeRight = new Point((int) (midPoint.x + dis / 2), 273 (int) midPoint.y); 274 Rect faceRect = new Rect((int) (midPoint.x - dd), 275 (int) (midPoint.y - dd), (int) (midPoint.x + dd), 276 (int) (midPoint.y + dd)); 277 Log.i(tag, "左眼坐标 x = " + eyeLeft.x + "y = " + eyeLeft.y); 278 if (checkFace(faceRect)) { 279 Canvas canvas = new Canvas(srcFace); 280 Paint p = new Paint(); 281 p.setAntiAlias(true); 282 p.setStrokeWidth(8); 283 p.setStyle(Paint.Style.STROKE); 284 p.setColor(Color.GREEN); 285 canvas.drawCircle(eyeLeft.x, eyeLeft.y, 20, p); 286 canvas.drawCircle(eyeRight.x, eyeRight.y, 20, p); 287 canvas.drawRect(faceRect, p); 288 } 289 if (i == 0) { 290 int xLeft = (int) (midPoint.x - f.eyesDistance() * 2); 291 int yLeft = (int) (midPoint.y - f.eyesDistance() * 2); 292 Bitmap bitmap = Bitmap.createBitmap(srcImg, xLeft >= 0 ? xLeft 293 : 0, yLeft >= 0 ? yLeft : 0, 294 (int) f.eyesDistance() * 4, (int) f.eyesDistance() * 4, 295 null, true); 296 return bitmap; 297 } 298 } 299 300 ImageUtil.saveJpeg(srcFace); 301 Log.i(tag, "保存完毕"); 302 303 // 将绘制完成后的faceBitmap返回 304 // return srcFace; 305 return null; 306 307 } 308 309 public void showProcessBar() { 310 RelativeLayout mainLayout = (RelativeLayout) findViewById(R.id.layout_main); 311 progressBar = new ProgressBar(MainActivity.this, null, 312 android.R.attr.progressBarStyleLargeInverse); // ViewGroup.LayoutParams.WRAP_CONTENT 313 RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams( 314 ViewGroup.LayoutParams.WRAP_CONTENT, 315 ViewGroup.LayoutParams.WRAP_CONTENT); 316 params.addRule(RelativeLayout.ALIGN_PARENT_TOP, RelativeLayout.TRUE); 317 params.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE); 318 progressBar.setVisibility(View.VISIBLE); 319 // progressBar.setLayoutParams(params); 320 mainLayout.addView(progressBar, params); 321 322 } 323 324 }