zoukankan      html  css  js  c++  java
  • 虹软SDK在nodejs中的集成

    ==虹软官网地址==

    http://www.arcsoft.com.cn

    在官网注册账号,并且申请人脸识别激活码, 选择SDK版本和运行系统(windows/linux/android/ios) ,我们选择windows做测试,申请类型选择1:N ,功能模块包括人脸检测、人脸跟踪、人脸识别。申请之后会获取APP_ID 和SDK_Key,在代码中会用到。

    ==虹软SDK人脸检测目的==

    主要是与face++人脸检测做对比,看能否在face++人脸检测之前选择虹软事先检测一下。

    ==c++部分功能实现==


    选择 Qtcreator 4.2.1 ,新建c++ 库。
    设置Qt .pro文件

    #不加载Qt库
    QT       -= core gui
    #生成库名字
    TARGET = detect_lib
    #定义生成lib
    TEMPLATE = lib
    
    DEFINES += DETECT_LIB_LIBRARY
    SOURCES += detect_lib.cpp
    #加载虹软sdk头文件
    HEADERS += detect_lib.h 
        inc/amcomdef.h 
        inc/ammem.h 
        inc/arcsoft_fsdk_face_detection.h 
        inc/asvloffscreen.h 
        inc/merror.h
    
    unix {
        target.path = /usr/lib
        INSTALLS += target
    }
    
    unix|win32: LIBS += -L$$PWD/lib/ -llibarcsoft_fsdk_face_detection
    
    INCLUDEPATH += $$PWD/.
    DEPENDPATH += $$PWD/.

    上面是.pro文件,主要是一些配置信息,如生成库名字 加载虹软SDK 和头文件...


    下面是detect_lib.h文件 主要供nodejs调用的接口文件。

    #ifndef DETECT_LIB_H
    #define DETECT_LIB_H
    
    #   ifdef __cplusplus
    #   define EXTERN_NAME extern "C"
    #   else
    #   define EXTERN_NAME extern
    #   endif
    
    #if defined(WIN32)
    #   define Q_DECL_EXPORT __declspec(dllexport)
    #   define Q_DECL_IMPORT __declspec(dllexport)
    #if defined(DETECT_LIB_LIBRARY)
    #   define DETECT_LIBSHARED_EXPORT EXTERN_NAME Q_DECL_EXPORT
    #   else
    #   define DETECT_LIBSHARED_EXPORT EXTERN_NAME Q_DECL_IMPORT
    #endif
    #else
    #   define DETECT_LIBSHARED_EXPORT EXTERN_NAME
    #endif
    
    DETECT_LIBSHARED_EXPORT int add(int a,int b);
    
    DETECT_LIBSHARED_EXPORT int detect(unsigned char * data,int width,int height);
    
    #endif // DETECT_LIB_H

    接口add 函数 主要做测试用

    int detect(unsigned char * data,int width,int height);

    检测人脸函数, data:rgb像素值,width:图片宽度,height:图片高度


    detect_lib.cpp

    #include "detect_lib.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <Windows.h>
    #include "inc/arcsoft_fsdk_face_detection.h"
    #include "inc/merror.h"
    
    //申请引擎使用的空间
    #define WORKBUF_SIZE        (40*1024*1024)
    
    char* APPID = const_cast<char*>("4KjUsRayGjxVv2UrajQBcgB2RKB3JFxGu5HZCrv7T6no");
    char* SDKKey = const_cast<char*>("BdFg8U29aDvUKdScmJcCZpep2xqYmrx4NouJ7iGm5BuX");
    
    void changeFormat(unsigned char * data,unsigned char ** destData,int width,int height)
    {
        *destData = new unsigned char[width * height * 3];
        int num = 0;
        for(int i = 0 ;i < width * height ;i ++)
        {
            int index = 4 * i;
    
                (*destData) [num ++]  = data[index +2];
                (*destData) [num ++]  = data[index +1];
                (*destData) [num ++]  = data[index +0];
    
        }
    }
    
    void charToUint (char* data,uint8_t ** imageData,int height,int width){
    
        int lineByte = (width * 24 / 8 + 3) / 4 * 4;
        *imageData = (uint8_t *)malloc(lineByte  * (height));
        char * tImageData = (char *)malloc(lineByte  * (height));
        int num = 0;
        for(int i = 0 ;i < width * height*4 ;i++){
            if((i+1) % 4 != 0){
                tImageData[num] = data[i];
                num ++;
            }
        }
        for (int i = 0; i < height; i++)
        {
            for (int j = 0; j < width; j++)
            {
                memcpy((*imageData) + i * width * 3 + j * 3, (uint8_t *)tImageData + ((height - 1) - i) * lineByte + j * 3, 3);
            }
        }
        free(tImageData);
    }
    
    int add(int a,int b){
        return a + b;
    }
    
    
    
    int detect(unsigned char * data,int width,int height)
    {
        /* 初始化引擎和变量 */
        MRESULT nRet = MERR_UNKNOWN;
        MHandle hEngine = nullptr;
        MInt32 nScale = 32;
        MInt32 nMaxFace = 10;
        MByte *pWorkMem = (MByte *)malloc(WORKBUF_SIZE);
        if (pWorkMem == nullptr)
        {
            return -1;
        }
        nRet = AFD_FSDK_InitialFaceEngine(APPID, SDKKey, pWorkMem, WORKBUF_SIZE, &hEngine, AFD_FSDK_OPF_0_HIGHER_EXT, nScale, nMaxFace);
        if (nRet != MOK)
        {
            return -1;
        }
        /* 打印版本信息 */
        const AFD_FSDK_Version * pVersionInfo = nullptr;
        pVersionInfo = AFD_FSDK_GetVersion(hEngine);
        fprintf(stdout, "%d %d %d %d
    ", pVersionInfo->lCodebase, pVersionInfo->lMajor, pVersionInfo->lMinor, pVersionInfo->lBuild);
        fprintf(stdout, "%s
    ", pVersionInfo->Version);
        fprintf(stdout, "%s
    ", pVersionInfo->BuildDate);
        fprintf(stdout, "%s
    ", pVersionInfo->CopyRight);
    
        /* 读取静态图片信息,并保存到ASVLOFFSCREEN结构体 (以ASVL_PAF_RGB24_B8G8R8格式为例) */
        ASVLOFFSCREEN offInput = { 0 };
        //offInput.u32PixelArrayFormat = ASVL_PAF_RGB32_R8G8B8;
        offInput.u32PixelArrayFormat = ASVL_PAF_RGB24_B8G8R8;
    
    //    offInput.ppu8Plane[0] = nullptr;
        offInput.i32Width = width;
        offInput.i32Height = height;
    //    charToUint(data,(uint8_t**)&offInput.ppu8Plane[0],height,width);
        //readBmp24(INPUT_IMAGE_PATH, (uint8_t**)&offInput.ppu8Plane[0], &offInput.i32Width, &offInput.i32Height);
        unsigned char *dstdata = nullptr;
        changeFormat(data,&dstdata,width,height);
        offInput.ppu8Plane[0] = (MUInt8*) dstdata;
        if (!offInput.ppu8Plane[0])
        {
            //fprintf(stderr, "Fail to ReadBmp(%s)
    ", INPUT_IMAGE_PATH);
            AFD_FSDK_UninitialFaceEngine(hEngine);
            free(pWorkMem);
            return -1;
        }
        else
        {
            fprintf(stdout, "Picture width : %d , height : %d 
    ", offInput.i32Width, offInput.i32Height);
        }
        offInput.pi32Pitch[0] = offInput.i32Width * 3;
    
        /* 人脸检测 */
        LPAFD_FSDK_FACERES    FaceRes = nullptr;
        nRet = AFD_FSDK_StillImageFaceDetection(hEngine, &offInput, &FaceRes);
        int nface = 0;
        if (nRet != MOK)
        {
            fprintf(stderr, "Face Detection failed, error code: %d
    ", nRet);
        }
        else
        {
            nface = FaceRes->nFace;
            fprintf(stdout, "The number of face: %d
    ", FaceRes->nFace);
            for (int i = 0; i < FaceRes->nFace; ++i)
            {
                fprintf(stdout, "Face[%d]: rect[%d,%d,%d,%d], Face orient: %d
    ", i, FaceRes->rcFace[i].left, FaceRes->rcFace[i].top, FaceRes->rcFace[i].right, FaceRes->rcFace[i].bottom, FaceRes->lfaceOrient[i]);
            }
        }
    
        /* 释放引擎和内存 */
        nRet = AFD_FSDK_UninitialFaceEngine(hEngine);
        if (nRet != MOK)
        {
            fprintf(stderr, "UninitialFaceEngine failed , errorcode is %d 
    ", nRet);
        }
        //free(offInput.ppu8Plane[0]);
        delete offInput.ppu8Plane[0];
        free(pWorkMem);
        return nface;
    }

    2.nodejs集成

    nodejs 使用node-gyp模块集成c++模块
    1.新建binding.gyp文件

    {
    "targets": [
    {
    "target_name": "detect",
    "sources": [ "detect_lib.h","detect.cpp" ],
    'library_dirs': ['./'],
    "include_dirs" : ["<!(node -e "require('nan')")","./"],
    'libraries': ['-ldetect_lib',]
    }
    ]
    }

    这是gyp配置文件,

    target_name表示生成.node文件的名字,

    source是在家c++的文件(.h,.cpp,.c)

    library_dirs:库目录设置

    include_dirs:头文件目录,除了头文件放置目录, 还包括会使用到nan模块

    libraries:库名字

    新建ArcDetect.cpp node的v8引擎接口文件

    #include <nan.h>
    #include "detect_lib.h"
    using namespace Nan ;
    using namespace v8;
    
    
    class DetectWorker : public AsyncWorker {
    public:
    DetectWorker(Callback *callback, unsigned char* buffer,int width,int height)
    : AsyncWorker(callback), p_buffer(buffer), m_width(width),m_height(height) {m_num = 0;}
    ~DetectWorker() {}
    
    //这个函数运行在工作线程,而不是v8线程,所以不能访问v8的数据
    void Execute () {
    
    //m_num = add(12,3);
    m_num = detect(p_buffer,m_width,m_height);
    // m_num = 5;
    
    }
    
    //这个是libuv的回调函数,在这里可以使用v8的数据
    void HandleOKCallback () {
    
    Local<Object> bmpData = NewBuffer(m_num).ToLocalChecked();
    Local<Value> argv[] = {
    Nan::Null()
    ,Uint32::New(v8::Isolate::GetCurrent(),m_num)
    };
    
    
    callback->Call(2, argv);
    };
    
    private:
    unsigned char * p_buffer;
    int m_width;
    int m_height;
    int m_num;
    };
    
    
    NAN_METHOD(detect){
    unsigned char * buffer = (unsigned char*) node::Buffer::Data(info[0]->ToObject());
    int width = info[1]->Uint32Value();
    int height = info[2]->Uint32Value();
    
    Callback *callback = new Callback(info[3].As<Function>());
    AsyncQueueWorker(new DetectWorker(callback, buffer,width ,height));
    }
    
    NAN_MODULE_INIT(Init)
    {
    Nan::Set(target,New<String>("detect").ToLocalChecked(),
    GetFunction(New<FunctionTemplate>(detect)).ToLocalChecked());
    }
    
    NODE_MODULE(detect, Init)

    NAN_METHOD(detect) 表示定义接口detect ,js可以直接调用,
    这里主要是node中的buffer直接以字节的方式传递给c++。也是nodejs与c++交互的重要方式。

    将编译好的dll 和虹软sdk dll 和detect_lib.h拷贝到当前目录,然后通过node-gyp configure 和node-gyp build 生成.node

    至此.node库编译完成,可以使用require直接饮用该.node 如:var detect = require('./build/Release/detect.node');

  • 相关阅读:
    有个名字叫随便乱记——css3
    CSS3伸缩布局
    路政整理
    GIst
    SVN回滚版本
    你需要知道的CSS3 动画技术
    iScroll框架的使用和修改
    CSS3阴影 box-shadow的使用和技巧总结
    Javascript异步编程的4种方法
    zepto学习零碎
  • 原文地址:https://www.cnblogs.com/laien/p/8610313.html
Copyright © 2011-2022 走看看