最近微軟的 how-old.net 把人臉識別技術(shù)又大大的火了一把。通過大數(shù)據(jù)和復(fù)雜的算法,能夠神奇的預(yù)測出照片中人物的性別和年齡。雖然錯誤率也不低,但是大家都抱著玩一玩樂一樂的心態(tài)把照片傳上去讓機(jī)器來鑒定一下自己的顏齡。
http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/30-1.png" alt="fig.1" />
人臉識別算法是高深復(fù)雜的,面對著計算機(jī)視覺的種種數(shù)學(xué)公式,我就已經(jīng)投降了。先來簡單的玩玩人臉檢測吧。Android 早已提供了 FaceDetector 類,今天就來看看如何使用這個類人臉檢測吧。
流程:
1.打開文件夾選擇照片
2.將照片加載到 bitmap 中并縮放到設(shè)置的寬高
3.用 FaceDetector 來檢測人臉,得到 Face 類數(shù)組(多人臉檢測)
4.在照片 bitmap 檢測到的人臉上面畫上方框和年齡
將 Intent 設(shè)置 Type 和 Action,啟動 activity 選擇照片并得到照片的 uri。
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(intent, OPEN_PHOTO_FOLDER_REQUEST_CODE);
新建一個類 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);
}
}
}
最終效果圖:
http://wiki.jikexueyuan.com/project/android-actual-combat-skills/images/30-2.png" alt="fig.2" />
源碼請參考我的開源 demo:[https://code.csdn.net/lincyang/androidwidgetdemo]()