在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:ArcSoft3.0NodeJs 版本实现开源软件地址:https://gitee.com/BlacksMoon/arc_soft_node_js_3.0开源软件介绍:ArcSoft3.0_Nodejs一、项目说明虹软官网传送门 ,有不同平台和不同版本的sdk,有需要的根据业务下载。此次项目支持windows和linux系统,mac 由于 禁用electron打包的应用。
二、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:/Python27npm config set python C:/python3.8.53、安装gypnpm install node-gyp -g或者npm install --global node-gyp@latest4、安装ffi refnpm install ffi -gnpm install ref -g【20201208重要说明】node.js调用C++动态库依赖node-ffi库,因node-ffi支持的node版本版本过低,在electron高版本中无法使用;有一位国外作者提供了 node-ffi-napi 的库来支持高版本的node.js,推荐大家使用。即在package.json中替换为:{ "ffi-napi": "^3.1.0", "ref-array-napi": "^1.2.1", "ref-napi": "^3.0.1", "ref-struct-napi": "^1.1.1",}成功编译 三、opencv4nodejs的安装手动安装opencv的环境,设置环境变量OPENCV_BIN_DIR=E:\commonsoft\opencv\build\x64\vc14\binOPENCV_INCLUDE_DIR=E:\commonsoft\opencv\build\includeOPENCV_LIB_DIR=E:\commonsoft\opencv\build\x64\vc14\lib【20201208】在package.json中添加``` bash"opencv4nodejs": { "disableAutoBuild": 1, "opencvIncludeDir": "E:\\commonsoft\\opencv\\build\\include", "opencvLibDir": "E:\\commonsoft\\opencv\\build\\x64\\vc14\\lib", "opencvBinDir": "E:\\commonsoft\\opencv\\build\\x64\\vc14\\bin" } 此处这么安装,成功率90% set OPENCV4NODEJS_DISABLE_AUTOBUILD=1npm i -g opencv4nodejs 【20201208重要说明】此处很重要,不然 很多报错,比如 无法解析外部参数ffi-napi 等其它包不要rebuild 【20201208重要说明】如果要单独用node xxx.js执行,则npm i 的版本的就可以,否则报node version against。 四、代码结构├─.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 └─unitmodual文件夹为人脸识别工作目录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 dependenciesnpm install# serve with hot reload at localhost:9080npm run dev# build electron application for productionnpm run build# run unit & end-to-end testsnpm 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_t4、调用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,将指针拷贝至bufferconst 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) 八、开源说明
|
请发表评论