2 Star 18 Fork 0

blacksmoon / ArcSoft3.0NodeJs 版本实现

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
MIT

ArcSoft3.0_Nodejs

一、项目说明

虹软官网传送门 ,有不同平台和不同版本的sdk,有需要的根据业务下载。 此次项目支持windows和linux系统,mac 由于 禁用electron打包的应用。

  1. 项目由electron-vue脚手架创建。
  2. 在主线程中实现与虹软SDK交互,如果还需要和render层交互,还需使用app.on来接收render层传过来的业务。
  3. vue打包时,需要在package.json中配置包含路径。
  4. 采用ffi库调用C++库,ref资料1 ref资料2 ref资料3 其它的请自行百度,此处就不细细阐述了。
  5. 图片处理有两种,一种是opencv4nodejs(node版本大于10.x,我用的是12的最后一版本,最新版本的用的python3.3,编译问题太多),一种是jimp,都有方法实现,我推荐opencv,处理速度快,但是配置环境略复杂。 资料看官方的npm即可,其余资料参考python调用opencv的方法类似。
  6. 此次主要针对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

【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\bin
OPENCV_INCLUDE_DIR=E:\commonsoft\opencv\build\include
OPENCV_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=1
npm i -g opencv4nodejs

【20201208重要说明】 此处很重要,不然 很多报错,比如 无法解析外部参数 ffi-napi 等其它包不要rebuild electron-rebuild编译opencv4nodejs

【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
    └─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)

八、开源说明

  • 开源不易,请使用代码时,注明引用,谢谢~
  • 如果你觉得我的代码帮到了你,请捐赠以表示支持,谢谢~ 输入图片说明
The MIT License (MIT) Copyright (c) 2020 BlacksMoon Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

简介

采用ffi调用虹软3.0免费版本动态库,node 调用 C++ 实例。 展开 收起
JavaScript
MIT
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
JavaScript
1
https://gitee.com/BlacksMoon/arc_soft_node_js_3.0.git
git@gitee.com:BlacksMoon/arc_soft_node_js_3.0.git
BlacksMoon
arc_soft_node_js_3.0
ArcSoft3.0NodeJs 版本实现
master

搜索帮助

53164aa7 5694891 3bd8fe86 5694891