虹軟人臉識別ArcSoft3.0NodeJs 版本實現
ArcSoft3.0_Nodejs
一、專案說明
虹軟官網傳送門 ,有不同平臺和不同版本的sdk,有需要的根據業務下載。
此次專案支援windows和linux系統,mac 由於 禁用electron打包的應用。
- 專案由electron-vue腳手架建立。
- 在主執行緒中實現與虹軟SDK互動,如果還需要和render層互動,還需使用app.on來接收render層傳過來的業務。
- vue打包時,需要在package.json中配置包含路徑。
- 採用ffi庫呼叫C++庫,ref資料1
ref資料2
ref資料3
其它的請自行百度,此處就不細細闡述了。 - 圖片處理有兩種,一種是opencv4nodejs(node版本大於10.x,我用的是10的最後一版本,最新版本的用的python3.3,編譯問題太多),一種是jimp,都有方法實現,我推薦opencv,處理速度快,但是配置環境略複雜。
資料看官方的npm即可,其餘資料參考python呼叫opencv的方法類似。 - 此次主要針對window版本的dll,linux呼叫方法一樣,將路徑換位自己的路徑即可,檔名為.so
二、ffi安裝及環境安裝
1、安裝 Visual Studio 15 生成工具 2017
利用 微軟自帶的安裝exe 【vs_BuildTools.exe】
目錄:C:\Users\Administrator\.windows-build-tools,指令碼安裝時,會因為安裝包過大和網路問題,導致安裝失敗。
2、指定編譯MSBuild.exe位置,因為2019和上述裝的2017都有這個exe,最好使用2017的,2019我安裝失敗了。
npm config set msbuild_path "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\MSBuild\15.0\Bin\MSBuild.exe"
3、指定python版本,還是建議2.7,其他高版本問題太多,我的3.8.5(不推薦)
npm config set python C:/Python27
npm config set python C:/python3.8.5
3、安裝gyp
npm install node-gyp -g
或者
npm install --global node-gyp@latest
4、安裝ffi ref
npm install ffi -g
npm install ref -g
成功編譯
三、opencv4nodejs的安裝
手動安裝opencv的環境,設定環境變數
OPENCV_BIN_DIR=E:\commonsoft\opencv\build\x64\vc14\bin
OPENCV_INCLUDE_DIR=E:\commonsoft\opencv\build\include
OPENCV_LIB_DIR=E:\commonsoft\opencv\build\x64\vc14\lib
此處這麼安裝,成功率90%
set OPENCV4NODEJS_DISABLE_AUTOBUILD=1
npm i -g opencv4nodejs
四、程式碼結構
├─.electron-vue
├─.idea
├─build
│ └─icons
├─dist
│ ├─electron
│ └─web
├─images
├─src
│ ├─main
│ │ ├─inc
│ │ ├─lib
│ │ │ ├─X64
│ │ │ └─X86
│ │ └─modual
│ │ ├─img
│ │ │ ├─faces
│ │ │ └─test
│ │ └─log
│ └─renderer
│ ├─assets
│ ├─components
│ │ └─LandingPage
│ ├─router
│ └─store
│ └─modules
├─static
└─test
├─e2e
│ └─specs
└─unit
modual資料夾為人臉識別工作目錄
lib資料夾為放置dll檔案路徑的地方,x86 x64 為對應的版本
img 圖片路徑(faces 為 drawFace 的操作路徑 test 是 cvImages 的操作路徑)
五、程式碼呼叫例項及說明
const arc_face = require('./face_engine');
const path = require('path');
const config = require('./config');
const m = require('./logger');
const client = require('./clients');
const imageHelper = require('./face_cv_image');
const fsUtil = require('./fileUtils');
// 設定dll路徑
let dllPath = "";
if (process.env.NODE_ENV !== 'development') {
dllPath = require('path').join(__dirname, '../../main/lib/X64').replace(/\\/g, '\\\\')
}else{
dllPath = require('path').join(__dirname, '../lib/X64').replace(/\\/g, '\\\\')
}
// 新增DLL所在目錄到環境變數
process.env['PATH'] = `${process.env.PATH};${dllPath}`;
// 初始化介面
const arc = new arc_face(config.lib_win64);
Object.prototype.toString = function(){
return JSON.stringify(this);
};
Date.prototype.toLocaleString = function() {
return this.getFullYear() + "-" + (this.getMonth() + 1) + "-" + this.getDate() + " " + this.getHours() + ":" + this.getMinutes() + ":" + this.getSeconds();
};
this.test_arc = async () => {
try{
let dataInfo = arc.getActiveFileInfo();
if (null != dataInfo){
let start = new Date(parseInt(dataInfo.startTime) * 1000);
let end = new Date(parseInt(dataInfo.endTime) * 1000);
m.logger.info("expire date is from %s to %s, please check the date for expired.thank you.",
start.toLocaleString(),
end.toLocaleString()
);
if (new Date().getTime() > end){
m.logger.warn('your arc soft is expired,please change the file to continue use it,thank you.');
return;
}
}
client.get('active', (err, res) => {
// 啟用
if (!res || parseInt(res) !== 1){
let ib = arc.activeFaceEngine(config.appId,config.appKey);
client.set('active',ib?1:0);
}else{
m.logger.info("engine has already initialed, do not repeat active");
}
});
let version = arc.getVersion();
m.logger.info("current verson is %s",version.Version);
// 初始化引擎
arc.initialFaceEngine(16,50);
// 設定可信度
arc.setLiveParam(0.5,0.7);
let img_path1 = path.join(__dirname, './img/1.jpg');
let img_path2 = path.join(__dirname, './img/2.jpg');
let img_path3 = path.join(__dirname, './img/3.jpg');
// jimp 處理圖片
// let asvl1 = await imageHelper.parseImage(img_path1,false);
// let asvl2 = await imageHelper.parseImage(img_path2,false);
// let asvl3 = await imageHelper.parseImage(img_path3,false);
// opencv 處理圖片
let asvl1 = await imageHelper.cvImages(img_path1,false,path.join(__dirname, './img/test'));
let asvl2 = await imageHelper.cvImages(img_path2,false,path.join(__dirname, './img/test'));
let asvl3 = await imageHelper.cvImages(img_path3,false,path.join(__dirname, './img/test'));
// 檢測人臉
let data1 = arc.detectFacesEx(asvl1.imageData);
let data2 = arc.detectFacesEx(asvl2.imageData);
// 提取特徵值
let feature1 = arc.extractFeature(asvl1.imageData, data1.multi.faceRect[0], data1.multi.faceOrient[0]);
let feature2 = arc.extractFeature(asvl2.imageData, data2.multi.faceRect[0], data2.multi.faceOrient[0]);
if (!feature1 || !feature2){
m.logger.error("feature1 or feature2 is null. please check.");
return;
}
// console.log("feature1",feature1)
// console.log("feature2",feature2)
// 比較
let sim = arc.compareFeature(feature1.nav,feature2.nav);
if (sim < 0){
m.logger.info("similar is %d,is not the same person.",sim);
return;
}
if (sim > 0.8){
m.logger.info("similar is %d,is the same person.",sim);
}else{
m.logger.info("similar is %d,is not the same person.",sim);
}
// base64 轉 feature 測試 ,實際效果會差0.02
let f1 = arc.base64ToFeature(feature1.nab.featureBuffer);
let f2 = arc.base64ToFeature(feature2.nab.featureBuffer);
let ff = arc.compareFeature(f1,f2);
if (ff > 0.8){
m.logger.info("similar is %d,is the same person.",ff);
}else{
m.logger.info("similar is %d,is not the same person.",ff);
}
// 釋放人臉指標
arc.release(f1.feature);
arc.release(f2.feature);
// 單體檢測
let ib = arc.processEx(asvl3.imageData,false);
if (!ib){
m.logger.error("single process checked failed.");
return;
}
arc.getSexInfo();
arc.getAgeInfo();
arc.getAngleInfo();
arc.getLivenessScore(false);
// 測試畫框
let isIR = false;
let asvl5 = await imageHelper.cvImages(img_path1,isIR);
let infos = arc.detectFacesEx(asvl5.imageData);
let filePath = path.join(__dirname, './img/faces');
await fsUtil.dirExists(filePath);
imageHelper.drawFace(img_path1,infos.multi,true,filePath);
// detect 和 process 系列
let fileCv = path.join(__dirname, './img/test');
await fsUtil.dirExists(fileCv);
let asvl6 = await imageHelper.cvImages(img_path1,isIR,fileCv);
let faces = arc.detectFaces(asvl6,false);
let info = arc.processNone(asvl6,false);
arc.getLivenessScore(false);
// console.log('info',info);
// 釋放 函式中已經釋放呼叫的指標
arc.unInitialEngine();
client.quit();
}catch (e) {
m.logger.info("some error happened.%s",e.toString());
arc.unInitialEngine();
client.quit()
}
};
this.test_arc();
六、安裝及使用
# install dependencies
npm install
# serve with hot reload at localhost:9080
npm run dev
# build electron application for production
npm run build
# run unit & end-to-end tests
npm test
# 測試人臉部分
node face_test.js
七、常見問題
1、Dynamic Linking Error: Win32 error 126
這個錯誤有三種原因
(1)通常是傳入的 DLL 路徑錯誤,找不到 Dll 檔案,推薦使用絕對路徑。
(2)如果是在 x64 的node/electron下引用 32 位的 DLL,也會報這個錯,反之亦然。要確保 DLL 要求的 CPU 架構和你的執行環境相同。
DLL 還有引用其他 DLL 檔案,但是找不到引用的 DLL 檔案,可能是 VC 依賴庫或者多個 DLL 之間存在依賴關係。
設定dll的工作的環境變數
process.env['PATH'] = `${process.env.PATH};${'E:/arface_node/arface_nodejs/src/main/lib/X64'}` //新增DLL所在目錄到環境變數
Dynamic Linking Error: Win32 error 127:DLL
(3)沒有找到對應名稱的函式,需要檢查標頭檔案定義的函式名是否與 DLL 呼叫時寫的函式名是否相同。
2、electron-vue 執行問題,如果提示app of undefined 類似的問題,在建立窗體時加入如下模組
enableRemoteModule:true, // 加入此句就可以獲取app模組,就不會報錯了
3、在node裡面,指標 -> 快取(buffer),
如 let a = new (typedef.MInt32.size) 表示 a*,
a.deref() 可以取出指標中的值,
普通變數 b, 那 b.ref() 表示 b*
.size 相當於C++ 裡面的 size_t
4、呼叫C++ 第一步就是對應 資料型別
// ref提供了C++的基本資料型別和定義,nodejs引數型別和C語言引數型別轉換
const ref = require('ref');
typedef.MLong = ref.types.long;
typedef.UMLong = ref.types.uint32;
typedef.MFloat = ref.types.float;
// 提供 C++ 結構體定義方法
const StructType = require('ref-struct');
typedef.__tag_rect = StructType({
left: typedef.MInt32,
top: typedef.MInt32,
right: typedef.MInt32,
bottom: typedef.MInt32
});
// 提供 C++ 陣列定義方法
const ArrayType = require('ref-array');
ppu8Plane: ArrayType(ref.refType(typedef.MUInt8), 4),
ref.refType(XXX)表示指標
5、C++介面對映
// 一種是不帶回撥函式的,如下:
ffi.Library(libFile, {
// 對映的介面名稱 C++介面,對應的資料型別
ASFGetActiveFileInfo: [TypeDef.MRESULT,
[
TypeDef.LPASF_ActiveFileInfo // [out] 啟用檔案資訊
]
]
}
// 一種是帶回撥函式的呼叫
let libname = ffi.Library('./libname', {
'setCallback': ['void', ['pointer']]
});
let callback = ffi.Callback('void', ['int', 'string'],
function(id, name) {
console.log("id: ", id);
console.log("name: ", name);
});
libname.setCallback(callback);
// 退出時引用回撥指標以避免GC(垃圾回收)
process.on('exit', function() {
callback
});
6、指標拷貝操作,用到 linux 中的 libc 操作
分配指定大小的空間指標: libc.malloc(size);
初始化指標:libc.memset(*p,offset,size);
指標拷貝:libc.memcpy(*to, *from ,size);
7、結合node中的buffer,將指標拷貝至buffer
const arr = new Buffer(TypeDef.MByte.size);
for (let i = 0; i < _feature.featureSize; i++) {
libc.memcpy(arr.address(), feature.feature.address() + i * TypeDef.MByte.size, TypeDef.MByte.size);
this.pointers.push(feature.feature);
_normal.feature.push(ref.get(arr, 0, TypeDef.MByte));
}
arr.deref()即取出指標中的值
8、分配的指標空間一定要釋放
libc.free(*p)
相關文章
- 虹軟人臉識別—版本升級介面修改說明(C#)C#
- 虹軟人臉識別——官方 Qt Demo 移植到 LinuxQTLinux
- C# 離線人臉識別 虹軟ArcFace 2.0 demoC#
- 虹軟人臉識別SDK - Java服務端的那些事Java服務端
- 基於虹軟人臉識別,實現RTMP直播推流追蹤視訊中所有人臉資訊(C#)C#
- 虹軟人臉識別 - faceId及IR活體檢測的介紹
- 機器學習實戰-SVM模型實現人臉識別機器學習模型
- 純前端實現人臉識別-提取-合成前端
- 基於Android平臺實現人臉識別Android
- 如何用Excel 9步實現CNN人臉識別ExcelCNN
- 人臉識別技術,讓科幻成為現實
- opencv 人臉識別OpenCV
- OpenCV — 人臉識別OpenCV
- 如何理解並實現一個簡單的人臉識別演算法(下):人臉識別演算法
- matlab實現人臉識別(數學基礎原理)Matlab
- 手把手教你實現人臉識別,有手就行
- 64行程式碼實現簡單人臉識別行程
- 人臉識別技術,將電影變成現實
- 人臉檢測識別,人臉檢測,人臉識別,離線檢測,C#原始碼C#原始碼
- 【opencv3】 svm實現手寫體與人臉識別OpenCV
- 【ROS】OpenCV+ROS 實現人臉識別(Ubantu16.04)ROSOpenCV
- Mars演算法實踐——人臉識別演算法
- 人臉識別檢測專案實戰
- C#人臉識別入門篇-STEP BY STEP人臉識別--入門篇C#
- 智慧人臉識別門禁系統開發,人臉識別開鎖流程
- 人臉識別之特徵臉方法(Eigenface)特徵
- 前端人臉識別--兩張臉相似度前端
- 妙招:使用Python實現圖片在人臉識別並顯示Python
- Python實現人臉識別功能,face_recognition的使用 | 機器學習Python機器學習
- 手把手教你用 1 行命令實現人臉識別
- 人臉活體檢測人臉識別:眨眼+張口
- 支小蜜人臉識別消費系統助力學校食堂實現“刷臉吃飯”
- 乾貨 | AI人臉識別之人臉搜尋AI
- 美軍開發遠端人臉識別系統,實現1公里內目標識別
- 人臉識別智慧考勤系統開發_人臉識別考勤管理系統開發
- 如何快速實現人臉識別通道?一文了解具體技巧
- 模式識別hw2-------基於matconvnet,用CNN實現人臉圖片性別識別模式CNN
- 人臉識別技術應用