Android人脸识别的初步学习,移动端开发技术创新
根據readme中的內容修改項目。
呀,報錯了…面對看不懂的錯誤,我們就…百度…
經過一番艱難險阻,我們的demo終于運行起來了,如下圖所示:
然而,當我一次又一次注冊人臉,無論是網絡上找到明星的照片,還是直接拍攝的圖片,甚至是表情包,都檢測不到人臉…我已經開始懷疑人臉長什么樣子了…
由于時間精力有限…我們直接進入源代碼的閱讀…
Demo代碼的閱讀
===================================================================
1. 代碼組成
人臉識別流程中應該包含以下幾個步驟
人臉檢測 (DetecteActivity)
即從攝像頭預覽中檢測到人臉的存在,并且使用一個矩形框出人臉的范圍。
人臉注冊 (RegisterActivity)
即將一張圖片中的人臉信息,提取出特征值,將該特征值與人員信息建立聯系。
人臉識別 (FR引擎)
2. 人臉注冊
人臉注冊是整個識別流程的基礎,Demo中人臉注冊的流程是在 RegsiterActivity 文件中處理的,該頁面啟動的時候接受 Intent 中傳來的 imagePath 信息(圖片地址);
第一步是獲取待注冊的照片,我們可以可以使用攝像頭,也可以使用照片。
獲取圖片后,將獲得的圖片轉為 Bitmap,然后將其轉化成 NV21 格式的 Byte 數組,因為我們使用的sdk只能處理 NV21 格式的數據,NV21 格式限制高度不能為奇數;
mBitmap = Application.decodeImage(mFilePath);
src.set(0,0,mBitma
p.getWidth(),mBitmap.getHeight());
mSurfaceView = (SurfaceView)this.findViewById(R.id.surfaceView);
mSurfaceView.getHolder().addCallback(this);
view = new Thread(new Runnable() {
@Override
public void run() {
//等待holder創建
while (mSurfaceHolder == null) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//創建字節數組 大小由拍照傳來的圖片尺寸決定
byte[] data = new byte[mBitmap.getWidth() * mBitmap.getHeight() * 3 / 2];
try {
//將bitmap轉換成nv21,結果保存到data數組中
ImageConverter convert = new ImageConverter();
convert.initial(mBitmap.getWidth(), mBitmap.getHeight(), ImageConverter.CP_PAF_NV21);
if (convert.convert(mBitmap, data)) {
Log.d(TAG, “convert ok!”);
}
convert.destroy();
} catch (Exception e) {
e.printStackTrace();
}
第二步:
AFD_FSDKFace是人臉識別的結果,定義如下:
public class AFD_FSDKFace {
android.graphics.Rect mRect;
int mDegree;
}
調用AFD_FSDK_StillImageFaceDetection返回檢測到的人臉信息
//創建FD人臉檢測引擎
AFD_FSDKEngine engine = new AFD_FSDKEngine();
AFD_FSDKVersion version = new AFD_FSDKVersion();
List<AFD_FSDKFace> result = new ArrayList<AFD_FSDKFace>(); //注冊結果? 人臉探測結果
//初始化引擎
AFD_FSDKError err = engine.AFD_FSDK_InitialFaceEngine(
FaceDB.appid, FaceDB.fd_key, AFD_FSDKEngine.AFD_OPF_0_HIGHER_EXT, 16, 300);
//錯誤碼
Log.d(TAG, "AFD_FSDK_InitialFaceEngine = " + err.getCode());
if (err.getCode() != AFD_FSDKError.MOK) {
//引擎初始化失敗
Message reg = Message.obtain();
reg.what = MSG_CODE;
reg.arg1 = MSG_EVENT_FD_ERROR;
reg.arg2 = err.getCode();
mUIHandler.sendMessage(reg);
}
err = engine.AFD_FSDK_GetVersion(version);
Log.d(TAG, “AFD_FSDK_GetVersion =” + version.toString() + ", " + err.getCode());
//FD人臉探測,轉化的nv21數據數組,傳入圖片的寬度、高度、NV21、探測結果
err = engine.AFD_FSDK_StillImageFaceDetection(data, mBitmap.getWidth(), mBitmap.getHeight(), AFD_FSDKEngine.CP_PAF_NV21, result);
Log.d(TAG, “AFD_FSDK_StillImageFaceDetection =” + err.getCode() + “<” + result.size());
至此我們就獲得了一張圖片中的全部人臉數據了,他們都被保存在result這個List列表中。
第三步:
使用 FR 人臉識別引擎識別該位置人臉中的特征信息。
if (!result.isEmpty()) {
//探測結果不為空-存在人臉 FR 人臉識別
AFR_FSDKVersion version1 = new AFR_FSDKVersion();
AFR_FSDKEngine engine1 = new AFR_FSDKEngine();
AFR_FSDKFace result1 = new AFR_FSDKFace();
AFR_FSDKError error1 = engine1.AFR_FSDK_InitialEngine(FaceDB.appid, FaceDB.fr_key);
Log.d(“com.arcsoft”, "AFR_FSDK_InitialEngine = " + error1.getCode());
if (error1.getCode() != AFD_FSDKError.MOK) {
//人臉識別引擎初始化失敗
Message reg = Message.obtain();
reg.what = MSG_CODE;
reg.arg1 = MSG_EVENT_FR_ERROR;
reg.arg2 = error1.getCode();
mUIHandler.sendMessage(reg);
}
error1 = engine1.AFR_FSDK_GetVersion(version1);
Log.d(“com.arcsoft”, “FR=” + version.toString() + “,” + error1.getCode()); //(210, 178 - 478, 446), degree = 1 780, 2208 - 1942, 3370
//提取人臉識別特征
error1 = engine1.AFR_FSDK_ExtractFRFeature(data, mBitmap.getWidth(), mBitmap.getHeight(), AFR_FSDKEngine.CP_PAF_NV21, new Rect(result.get(0).getRect()), result.get(0).getDegree(), result1);
Log.d(“com.arcsoft”, “Face=” + result1.getFeatureData()[0] + “,” + result1.getFeatureData()[1] + “,” + result1.getFeatureData()[2] + “,” + error1.getCode());
if(error1.getCode() == error1.MOK) {
//提取出了特征
mAFR_FSDKFace = result1.clone();
int width = result.get(0).getRect().width();
int height = result.get(0).getRect().height();
Bitmap face_bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas face_canvas = new Canvas(face_bitmap);
face_canvas.drawBitmap(mBitmap, result.get(0).getRect(), new Rect(0, 0, width, height), null);
Message reg = Message.obtain();
reg.what = MSG_CODE;
reg.arg1 = MSG_EVENT_REG;
reg.obj = face_bitmap;
mUIHandler.sendMessage(reg);
} else {
//沒有提取出特征
Message reg = Message.obtain();
reg.what = MSG_CODE;
reg.arg1 = MSG_EVENT_NO_FEATURE;
mUIHandler.sendMessage(reg);
}
error1 = engine1.AFR_FSDK_UninitialEngine();
Log.d(“com.arcsoft”, "AFR_FSDK_UninitialEngine : " + error1.getCode());
} else {
//人臉識別解決為空,不存在人臉
Message reg = Message.obtain();
reg.what = MSG_CODE;
reg.arg1 = MSG_EVENT_NO_FACE;
mUIHandler.sendMessage(reg);
}
err = engine.AFD_FSDK_UninitialFaceEngine();
Log.d(TAG, “AFD_FSDK_UninitialFaceEngine =” + err.getCode());
}
});
第四步:
到此我們已經獲得了整個人臉注冊流程中所需要的幾個關鍵值了:
人臉位置 Rect 及該 Rect 的 Bitmap;
人臉特征信息實例 mAFR_FSDKFace;
檢測到了人臉,我們可以輸入相應的描述信息,加入到人臉庫中。
public void addFace(String name, AFR_FSDKFace face) {
try {
//check if already registered.
boolean add = true;
for (FaceRegist frface : mRegister) {
if (frface.mName.equals(name)) {
frface.mFaceList.add(face);
add = false;
break;
}
}
if (add) { // not registered.
FaceRegist frface = new FaceRegist(name);
frface.mFaceList.add(face);
mRegister.add(frface);
}
//清空原有txt文件
if (saveInfo()) {
//update all names
//把當前內存里的新數據全部重新添加一次
FileOutputStream fs = new FileOutputStream(mDBPath + “/face.txt”, true);
ExtOutputStream bos = new ExtOutputStream(fs);
for (FaceRegist frface : mRegister) {
bos.writeString(frface.mName);
}
bos.close();
fs.close();
//save new feature
fs = new FileOutputStream(mDBPath + “/” + name + “.data”, true);
bos = new ExtOutputStream(fs);
bos.writeBytes(face.getFeatureData());
bos.close();
fs.close();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
銷毀人臉檢測引擎
err = engine.AFD_FSDK_UninitialFaceEngine();
Log.d(TAG, “AFD_FSDK_UninitialFaceEngine =” + err.getCode());
3. 實現人臉識別
初始化相機:引擎需要的圖像格式是NV21的,所以需要將攝像頭中的圖像格式預設置為NV21
@Override
public Camera setupCamera() {
// TODO Auto-generated method stub
mCamera = Camera.open(mCameraID);
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mWidth, mHeight);
parameters.setPreviewFormat(mFormat);
err = engine.AFD_FSDK_UninitialFaceEngine();
Log.d(TAG, “AFD_FSDK_UninitialFaceEngine =” + err.getCode());
3. 實現人臉識別
初始化相機:引擎需要的圖像格式是NV21的,所以需要將攝像頭中的圖像格式預設置為NV21
@Override
public Camera setupCamera() {
// TODO Auto-generated method stub
mCamera = Camera.open(mCameraID);
try {
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mWidth, mHeight);
parameters.setPreviewFormat(mFormat);
總結
以上是生活随笔為你收集整理的Android人脸识别的初步学习,移动端开发技术创新的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uIP无操作系统(裸机)移植
- 下一篇: 拯救老电脑,win10 LTSC版、黑苹