Android中的人臉檢測的示例代碼(靜態(tài)和動態(tài))
(1)背景。
Google 于2006年8月收購Neven Vision 公司 (該公司擁有10多項(xiàng)應(yīng)用于移動設(shè)備領(lǐng)域的圖像識別的專利),以此獲得了圖像識別的技術(shù),并加入到android中。Android 中的人臉識別技術(shù),用到的底層庫:android/external/neven/,framework 層:frameworks/base/media/java/android/media/FaceDetector.java。
Java 層接口的限制:A,只能接受Bitmap 格式的數(shù)據(jù);B,只能識別雙眼距離大于20 像素的人臉像(當(dāng)然,這個(gè)可在framework層中修改);C,只能檢測出人臉的位置(雙眼的中心點(diǎn)及距離),不能對人臉進(jìn)行匹配(查找指定的臉譜)。
人臉識別技術(shù)的應(yīng)用:A,為Camera 添加人臉識別的功能,使得Camera 的取景器上能標(biāo)識出人臉范圍;如果硬件支持,可以對人臉進(jìn)行對焦。B,為相冊程序添加按人臉?biāo)饕鄡缘墓δ?,按人臉?biāo)饕鄡裕慈四樂纸M,搜索相冊。
(2)Neven庫給上層提供的主要方法:
A,android.media.FaceDetector .FaceDetector(int width, int height, int maxFaces):Creates a FaceDetector, configured with the size of the images to be analysed and the maximum number of faces that can be detected. These parameters cannot be changed once the object is constructed.
B,int android.media.FaceDetector .findFaces(Bitmap bitmap, Face [] faces):Finds all the faces found in a given Bitmap . The supplied array is populated with FaceDetector.Face s for each face found. The bitmap must be in 565 format (for now).
(3) 靜態(tài)圖片處理代碼實(shí)例:
通過對位圖的處理,捕獲位圖中的人臉,并以綠框顯示,有多個(gè)人臉就提示多個(gè)綠框。首先新建一個(gè)activity,由于位圖資源會用代碼顯示出來,所以不需在layout中使用widget。
package com.example.mydetect2;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;
import android.content.Context;
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; //人臉識別的關(guān)鍵類
import android.media.FaceDetector.Face;
import android.view.View;
public class MainActivity2 extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main_activity2);
setContentView(new myView(this)); //使用自建的view來顯示
Log.i("zhangcheng","MainActivity2 run here");
}
private class myView extends View{
private int imageWidth, imageHeight;
private int numberOfFace = 5; //最大檢測的人臉數(shù)
private FaceDetector myFaceDetect; //人臉識別類的實(shí)例
private FaceDetector.Face[] myFace; //存儲多張人臉的數(shù)組變量
float myEyesDistance; //兩眼之間的距離
int numberOfFaceDetected; //實(shí)際檢測到的人臉數(shù)
Bitmap myBitmap;
public myView(Context context){ //view類的構(gòu)造函數(shù),必須有
super(context);
BitmapFactory.Options BitmapFactoryOptionsbfo = new BitmapFactory.Options();
BitmapFactoryOptionsbfo.inPreferredConfig = Bitmap.Config.RGB_565; //構(gòu)造位圖生成的參數(shù),必須為565。類名+enum
myBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.baby, BitmapFactoryOptionsbfo);
imageWidth = myBitmap.getWidth();
imageHeight = myBitmap.getHeight();
myFace = new FaceDetector.Face[numberOfFace]; //分配人臉數(shù)組空間
myFaceDetect = new FaceDetector(imageWidth, imageHeight, numberOfFace);
numberOfFaceDetected = myFaceDetect.findFaces(myBitmap, myFace); //FaceDetector 構(gòu)造實(shí)例并解析人臉
Log.i("zhangcheng","numberOfFaceDetected is " + numberOfFaceDetected);
}
protected void onDraw(Canvas canvas){ //override函數(shù),必有
canvas.drawBitmap(myBitmap, 0, 0, null); //畫出位圖
Paint myPaint = new Paint();
myPaint.setColor(Color.GREEN);
myPaint.setStyle(Paint.Style.STROKE);
myPaint.setStrokeWidth(3); //設(shè)置位圖上paint操作的參數(shù)
for(int i=0; i < numberOfFaceDetected; i++){
Face face = myFace[i];
PointF myMidPoint = new PointF();
face.getMidPoint(myMidPoint);
myEyesDistance = face.eyesDistance(); //得到人臉中心點(diǎn)和眼間距離參數(shù),并對每個(gè)人臉進(jìn)行畫框
canvas.drawRect( //矩形框的位置參數(shù)
(int)(myMidPoint.x - myEyesDistance),
(int)(myMidPoint.y - myEyesDistance),
(int)(myMidPoint.x + myEyesDistance),
(int)(myMidPoint.y + myEyesDistance),
myPaint);
}
}
}
}
以上為activity,工程的xml文件沒有什么特殊地方。最后得到的結(jié)果如下,圖片資源是png的也可以。

(4) 動態(tài)預(yù)覽識別人臉代碼實(shí)例
該過程用于后臺工作,沒有界面也沒有預(yù)覽。所以沒有采用上面那種處理位圖資源的方式。Import的類就不列出了,核心的代碼和流程如下:
A,打開攝像頭,獲得初步攝像頭回調(diào)數(shù)據(jù),用到是setpreviewcallback
protected Camera mCameraDevice = null;// 攝像頭對象實(shí)例 private long mScanBeginTime = 0; // 掃描開始時(shí)間 private long mScanEndTime = 0; // 掃描結(jié)束時(shí)間 private long mSpecPreviewTime = 0; // 掃描持續(xù)時(shí)間 private int orientionOfCamera ; //前置攝像頭layout角度 int numberOfFaceDetected; //最終識別人臉數(shù)目
public void startFaceDetection() {
try {
mCameraDevice = Camera.open(1); //打開前置
if (mCameraDevice != null)
Log.i(TAG, "open cameradevice success! ");
} catch (Exception e) { //Exception代替很多具體的異常
mCameraDevice = null;
Log.w(TAG, "open cameraFail");
mHandler.postDelayed(r,5000); //如果攝像頭被占用,人眼識別每5秒檢測看有沒有釋放前置
return;
}
Log.i(TAG, "startFaceDetection");
Camera.Parameters parameters = mCameraDevice.getParameters();
setCameraDisplayOrientation(1,mCameraDevice); //設(shè)置預(yù)覽方向
mCameraDevice.setPreviewCallback(new PreviewCallback(){
public void onPreviewFrame(byte[] data, Camera camera){
mScanEndTime = System.currentTimeMillis(); //記錄攝像頭返回?cái)?shù)據(jù)的時(shí)間
mSpecPreviewTime = mScanEndTime - mScanBeginTime; //從onPreviewFrame獲取攝像頭數(shù)據(jù)的時(shí)間
Log.i(TAG, "onPreviewFrame and mSpecPreviewTime = " + String.valueOf(mSpecPreviewTime));
Camera.Size localSize = camera.getParameters().getPreviewSize(); //獲得預(yù)覽分辨率
YuvImage localYuvImage = new YuvImage(data, 17, localSize.width, localSize.height, null);
ByteArrayOutputStream localByteArrayOutputStream = new ByteArrayOutputStream();
localYuvImage.compressToJpeg(new Rect(0, 0, localSize.width, localSize.height), 80, localByteArrayOutputStream); //把攝像頭回調(diào)數(shù)據(jù)轉(zhuǎn)成YUV,再按圖像尺寸壓縮成JPEG,從輸出流中轉(zhuǎn)成數(shù)組
byte[] arrayOfByte = localByteArrayOutputStream.toByteArray();
CameraRelease(); //及早釋放camera資源,避免影響camera設(shè)備的正常調(diào)用
StoreByteImage(arrayOfByte);
}
});
mCameraDevice.startPreview(); //該語句可放在回調(diào)后面,當(dāng)執(zhí)行到這里,調(diào)用前面的setPreviewCallback
mScanBeginTime = System.currentTimeMillis();// 記錄下系統(tǒng)開始掃描的時(shí)間
}
B,設(shè)置預(yù)覽方向的函數(shù)說明,該函數(shù)比較重要,因?yàn)榉较蛑苯佑绊慴itmap構(gòu)造時(shí)的矩陣旋轉(zhuǎn)角度,影響最終人臉識別的成功與否
public void setCameraDisplayOrientation(int paramInt, Camera paramCamera){
CameraInfo info = new CameraInfo();
Camera.getCameraInfo(paramInt, info);
int rotation = ((WindowManager)getSystemService("window")).getDefaultDisplay().getRotation(); //獲得顯示器件角度
int degrees = 0;
Log.i(TAG,"getRotation's rotation is " + String.valueOf(rotation));
switch (rotation) {
case Surface.ROTATION_0: degrees = 0; break;
case Surface.ROTATION_90: degrees = 90; break;
case Surface.ROTATION_180: degrees = 180; break;
case Surface.ROTATION_270: degrees = 270; break;
}
orientionOfCamera = info.orientation; //獲得攝像頭的安裝旋轉(zhuǎn)角度
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
paramCamera.setDisplayOrientation(result); //注意前后置的處理,前置是映象畫面,該段是SDK文檔的標(biāo)準(zhǔn)DEMO
}
C,對攝像頭回調(diào)數(shù)據(jù)進(jìn)行轉(zhuǎn)換并最終解成BITMAP后再人臉識別的過程
public void StoreByteImage(byte[] paramArrayOfByte){
mSpecStopTime = System.currentTimeMillis();
mSpecCameraTime = mSpecStopTime - mScanBeginTime;
Log.i(TAG, "StoreByteImage and mSpecCameraTime is " + String.valueOf(mSpecCameraTime));
BitmapFactory.Options localOptions = new BitmapFactory.Options();
Bitmap localBitmap1 = BitmapFactory.decodeByteArray(paramArrayOfByte, 0, paramArrayOfByte.length, localOptions);
int i = localBitmap1.getWidth();
int j = localBitmap1.getHeight(); //從上步解出的JPEG數(shù)組中接出BMP,即RAW->JPEG->BMP
Matrix localMatrix = new Matrix();
//int k = cameraResOr;
Bitmap localBitmap2 = null;
FaceDetector localFaceDetector = null;
switch(orientionOfCamera){ //根據(jù)前置安裝旋轉(zhuǎn)的角度來重新構(gòu)造BMP
case 0:
localFaceDetector = new FaceDetector(i, j, 1);
localMatrix.postRotate(0.0F, i / 2, j / 2);
localBitmap2 = Bitmap.createBitmap(i, j, Bitmap.Config.RGB_565);
break;
case 90:
localFaceDetector = new FaceDetector(j, i, 1); //長寬互換
localMatrix.postRotate(-270.0F, j / 2, i / 2); //正90度的話就反方向轉(zhuǎn)270度,一樣效果
localBitmap2 = Bitmap.createBitmap(i, j, Bitmap.Config.RGB_565);
break;
case 180:
localFaceDetector = new FaceDetector(i, j, 1);
localMatrix.postRotate(-180.0F, i / 2, j / 2);
localBitmap2 = Bitmap.createBitmap(i, j, Bitmap.Config.RGB_565);
break;
case 270:
localFaceDetector = new FaceDetector(j, i, 1);
localMatrix.postRotate(-90.0F, j / 2, i / 2);
localBitmap2 = Bitmap.createBitmap(j, i, Bitmap.Config.RGB_565); //localBitmap2應(yīng)是沒有數(shù)據(jù)的
break;
}
FaceDetector.Face[] arrayOfFace = new FaceDetector.Face[1];
Paint localPaint1 = new Paint();
Paint localPaint2 = new Paint();
localPaint1.setDither(true);
localPaint2.setColor(-65536);
localPaint2.setStyle(Paint.Style.STROKE);
localPaint2.setStrokeWidth(2.0F);
Canvas localCanvas = new Canvas();
localCanvas.setBitmap(localBitmap2);
localCanvas.setMatrix(localMatrix);
localCanvas.drawBitmap(localBitmap1, 0.0F, 0.0F, localPaint1); //該處將localBitmap1和localBitmap2關(guān)聯(lián)(可不要?)
numberOfFaceDetected = localFaceDetector.findFaces(localBitmap2, arrayOfFace); //返回識臉的結(jié)果
localBitmap2.recycle();
localBitmap1.recycle(); //釋放位圖資源
FaceDetectDeal(numberOfFaceDetected);
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Kotlin 使用Lambda來設(shè)置回調(diào)的操作
這篇文章主要介紹了Kotlin 使用Lambda來設(shè)置回調(diào)的操作方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android實(shí)現(xiàn)淘寶商品列表切換效果
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)淘寶商品列表切換效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-01-01
Android數(shù)據(jù)庫LitePal的基本用法詳解
這篇文章主要介紹了Android數(shù)據(jù)庫LitePal的基本用法詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
Android學(xué)習(xí)筆記之Shared Preference
在之前遇到有個(gè)需求是要改settings里面自動轉(zhuǎn)屏的首選項(xiàng),于是就學(xué)習(xí)了下Shared Preference。Shared Preference是一種簡單的、輕量級的鍵/值對機(jī)制,用于保存原始應(yīng)用程序數(shù)據(jù),最常見的就是首選項(xiàng)2013-09-09
Android帶數(shù)字或紅點(diǎn)的底部導(dǎo)航攔和聯(lián)網(wǎng)等待加載動畫示例
這篇文章主要介紹了Android帶數(shù)字或紅點(diǎn)的底部導(dǎo)航攔和聯(lián)網(wǎng)等待加載動畫示例,具有一定的參考價(jià)值,有興趣的同學(xué)可以了解一下。2017-03-03
Flutter路由的跳轉(zhuǎn)、動畫和傳參詳解(最簡單)
這篇文章主要給大家介紹了關(guān)于Flutter路由的跳轉(zhuǎn)、動畫和傳參的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01
Android 6.0調(diào)用相機(jī)圖冊崩潰的完美解決方案
這篇文章主要介紹了Android 6.0調(diào)用相機(jī)圖冊崩潰的完美解決方案,本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-09-09

