Android實戰技巧之三十:臉部偵測-靜態,android實戰技巧
最近微軟的how-old.net把Face Service技術又大大的火了一把。通過大資料和複雜的演算法,能夠神奇的預測出照片中人物的性別和年齡。雖然錯誤率也不低,但是大家都抱著玩一玩樂一樂的心態把照片傳上去讓機器來評鑑一下自己的顏齡。
Face Service演算法是高深複雜的,面對著電腦視覺的種種數學公式,我就已經投降了。先來簡單的玩玩臉部偵測吧。Android早已提供了FaceDetector類,今天就來看看如何使用這個類臉部偵測吧。
流程:
1.開啟檔案夾選擇照片
2.將照片載入到bitmap中並縮放到設定的寬高
3.用FaceDetector來檢測人臉,得到Face類數組(多臉部偵測)
4.在照片bitmap檢測到的人臉上面畫上方框和年齡
一、選擇照片
將Intent設定Type和Action,啟動activity選擇照片並得到照片的uri。
Intent intent = new Intent(); intent.setType("image/*"); intent.setAction(Intent.ACTION_GET_CONTENT); startActivityForResult(intent, OPEN_PHOTO_FOLDER_REQUEST_CODE);
二、載入照片到bitmap並縮放
建立一個類FDView繼承自View,就像上一篇文章一樣,對bitmap的修改用到了canvas的知識。
有兩種辦法將照片載入到bitmap中:
1.通過uri用stream的方式
public void initBitmap(Uri uri,int width,int height) { try { ContentResolver resolver = mContext.getContentResolver(); BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565;//need this config Bitmap bitmap = BitmapFactory.decodeStream(resolver.openInputStream(uri), null, options); mBitmap = ThumbnailUtils.extractThumbnail(bitmap, width, height);//scale the bitmap detectFace(); } catch (Exception ex) { Log.e(TAG,"exception: "+ex.getMessage()); } }
2.用照片的真實路徑載入
獲得真實路徑:
private void initFRViewWithPath(Uri uri) { String[] projection = {MediaStore.Images.Media.DATA};// Cursor cursor = managedQuery(uri, projection, null, null, null);//deprecated CursorLoader cursorLoader = new CursorLoader(this,uri,projection,null,null,null); Cursor cursor = cursorLoader.loadInBackground(); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); String path = cursor.getString(column_index); Log.e(TAG,"real path: "+path); mFRView.initBitmap(path,mFRView.getWidth(),mFRView.getHeight()); }
decodeFile:
public void initBitmap(String path,int width,int height) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inPreferredConfig = Bitmap.Config.RGB_565; mBitmap = BitmapFactory.decodeFile(path, options); mBitmap = ThumbnailUtils.extractThumbnail(mBitmap,width,height);//scale the bitmap detectFace(); }
三、臉部偵測
private void detectFace() { if(mBitmap != null) { mImageWidth = mBitmap.getWidth(); mImageHeight = mBitmap.getHeight(); mFaces = new FaceDetector.Face[NUMBER_OF_FACES]; mFaceDetector = new FaceDetector(mImageWidth, mImageHeight, NUMBER_OF_FACES); mNumberOfFaceDetected = mFaceDetector.findFaces(mBitmap, mFaces); invalidate(); } }
四、人臉上畫框
在onDraw中用canvas將檢測到的人臉畫上框並寫上年齡。
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(mBitmap != null) { canvas.drawBitmap(mBitmap, 0, 0, null); Paint paint = new Paint(); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(2); paint.setTextSize(50); for(int i=0; i < mNumberOfFaceDetected; i++){ FaceDetector.Face face = mFaces[i]; PointF pointF = new PointF(); face.getMidPoint(pointF); mEyesDistance = face.eyesDistance(); canvas.drawRect( (int)(pointF.x - mEyesDistance), (int)(pointF.y - mEyesDistance/2), (int)(pointF.x + mEyesDistance), (int)(pointF.y + mEyesDistance*3/2), paint); canvas.drawText("28",pointF.x,pointF.y - mEyesDistance/2-5,paint); } } }
最終:
源碼請參考我的開源demo:https://code.csdn.net/lincyang/androidwidgetdemo