海康SDK人脸摄像头对接

1、前言

最近有个项目要用到人脸识别,由于很多原因最后决定采购海康的人脸识别摄像头(支持人脸抓拍+人脸比对等功能),项目中要集成的功能包括:人脸识别结果的返回和人员信息的下发配置。

2、开发环境

  • ubuntu18.04系统
  • CH-HCNetSDKV6.1.4.42_build20200527_linux64
  • C++11
    吐槽一下:海康摄像头目前的SDK只提供了linux x86版本的32位和64位的版本,并没有提供linux arm的sdk,这个真是让人摸不着头脑

3、功能开发

  • 海康提供的example


    example

    参考这个例子基本上就可以把登录问题搞定了

  • 参考开发文档


#include <stdio.h>
#include <iostream>
#include "Windows.h"
#include "HCNetSDK.h"
using namespace std;

//时间解析宏定义
#define GET_YEAR(_time_)      (((_time_)>>26) + 2000) 
#define GET_MONTH(_time_)     (((_time_)>>22) & 15)
#define GET_DAY(_time_)       (((_time_)>>17) & 31)
#define GET_HOUR(_time_)      (((_time_)>>12) & 31) 
#define GET_MINUTE(_time_)    (((_time_)>>6)  & 63)
#define GET_SECOND(_time_)    (((_time_)>>0)  & 63)

BOOL CALLBACK MessageCallback(LONG lCommand, NET_DVR_ALARMER *pAlarmer, char *pAlarmInfo, DWORD dwBufLen, void* pUser)
{
    switch(lCommand) 
    {       
        case COMM_SNAP_MATCH_ALARM: //人脸比对结果信息
        {
            NET_VCA_FACESNAP_MATCH_ALARM struFaceMatchAlarm = {0};
            memcpy(&struFaceMatchAlarm, pAlarmInfo, sizeof(NET_VCA_FACESNAP_MATCH_ALARM));
            
            NET_DVR_TIME struAbsTime = {0};
            struAbsTime.dwYear = GET_YEAR(struFaceMatchAlarm.struSnapInfo.dwAbsTime);
            struAbsTime.dwMonth = GET_MONTH(struFaceMatchAlarm.struSnapInfo.dwAbsTime);
            struAbsTime.dwDay = GET_DAY(struFaceMatchAlarm.struSnapInfo.dwAbsTime);
            struAbsTime.dwHour = GET_HOUR(struFaceMatchAlarm.struSnapInfo.dwAbsTime);
            struAbsTime.dwMinute = GET_MINUTE(struFaceMatchAlarm.struSnapInfo.dwAbsTime);
            struAbsTime.dwSecond = GET_SECOND(struFaceMatchAlarm.struSnapInfo.dwAbsTime);

            printf("人脸比对结果上传[0x%x]:[%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d]fSimilarity[%f]FaceID[%d]BlackListID[%d]"
            "Sex[%d]Glasses[%d]Age[%d]MatchPicNum[%d]PicTransType[%d]\n", lCommand, 
            struAbsTime.dwYear, struAbsTime.dwMonth, struAbsTime.dwDay, struAbsTime.dwHour, struAbsTime.dwMinute, 
            struAbsTime.dwSecond, struFaceMatchAlarm.fSimilarity, struFaceMatchAlarm.struSnapInfo.dwSnapFacePicID,
            struFaceMatchAlarm.struBlackListInfo.struBlackListInfo.dwRegisterID, struFaceMatchAlarm.struSnapInfo.bySex,
            struFaceMatchAlarm.struSnapInfo.byGlasses, struFaceMatchAlarm.struSnapInfo.byAge, 
            struFaceMatchAlarm.byMatchPicNum, struFaceMatchAlarm.byPicTransType);
    

            //保存抓拍图片
            if (struFaceMatchAlarm.dwSnapPicLen > 0 && struFaceMatchAlarm.pSnapPicBuffer  != NULL && struFaceMatchAlarm.byPicTransType == 0)
            {      
                char cFilename[256] = {0};
                HANDLE hFile;
                DWORD dwReturn;

                char chTime[128];
                sprintf(chTime,"%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",struAbsTime.dwYear,struAbsTime.dwMonth,struAbsTime.dwDay,struAbsTime.dwHour,struAbsTime.dwMinute,struAbsTime.dwSecond);

                sprintf(cFilename, "FaceSnapPic[%s][%s].jpg",struFaceMatchAlarm.struSnapInfo.struDevInfo.struDevIP.sIpV4, chTime);
              
                hFile = CreateFile(cFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (hFile == INVALID_HANDLE_VALUE)
                {
                    break;
                }
                WriteFile(hFile, struFaceMatchAlarm.pSnapPicBuffer, struFaceMatchAlarm.dwSnapPicLen, &dwReturn, NULL);
                CloseHandle(hFile);
                hFile = INVALID_HANDLE_VALUE;
            }

            
            //保存黑名单人脸图片
            if (struFaceMatchAlarm.struBlackListInfo.dwBlackListPicLen > 0 && struFaceMatchAlarm.struBlackListInfo.pBuffer1 != NULL)
            {      
                char cFilename[256] = {0};
                HANDLE hFile;
                DWORD dwReturn;

                char chTime[128];
                sprintf(chTime,"%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d",struAbsTime.dwYear,struAbsTime.dwMonth,struAbsTime.dwDay,struAbsTime.dwHour,struAbsTime.dwMinute,struAbsTime.dwSecond);

                sprintf(cFilename, "FaceBlackListPic[%s].jpg", chTime);
              
                hFile = CreateFile(cFilename, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
                if (hFile == INVALID_HANDLE_VALUE)
                {
                    break;
                }
                WriteFile(hFile, struFaceMatchAlarm.struBlackListInfo.pBuffer1, struFaceMatchAlarm.struBlackListInfo.dwBlackListPicLen, &dwReturn, NULL);
                CloseHandle(hFile);
                hFile = INVALID_HANDLE_VALUE;
            }           
        }
        break;
        default:
        printf("其他报警,报警信息类型: 0x%x\n", lCommand);
        break;
    }

    return TRUE;
}

void main() {
    //---------------------------------------
    // 初始化
    NET_DVR_Init();
    //设置连接时间与重连时间
    NET_DVR_SetConnectTime(2000, 1);
    NET_DVR_SetReconnect(10000, true);

    //---------------------------------------
    // 注册设备
    LONG lUserID;

    //登录参数,包括设备地址、登录用户、密码等
    NET_DVR_USER_LOGIN_INFO struLoginInfo = {0};
    struLoginInfo.bUseAsynLogin = 0; //同步登录方式
    strcpy(struLoginInfo.sDeviceAddress, "192.0.0.64"); //设备IP地址
    struLoginInfo.wPort = 8000; //设备服务端口
    strcpy(struLoginInfo.sUserName, "admin"); //设备登录用户名
    strcpy(struLoginInfo.sPassword, "abcd1234"); //设备登录密码
  
    //设备信息, 输出参数
    NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = {0};

    lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);
    if (lUserID < 0)
    {
        printf("Login failed, error code: %d\n", NET_DVR_GetLastError());
        NET_DVR_Cleanup();
        return;
    }
  
    //设置报警回调函数
    NET_DVR_SetDVRMessageCallBack_V31(MessageCallback, NULL);
  
    //启用布防
    LONG lHandle;
    NET_DVR_SETUPALARM_PARAM  struAlarmParam={0};
    struAlarmParam.dwSize=sizeof(struAlarmParam);
    //其他报警布防参数不需要设置

    lHandle = NET_DVR_SetupAlarmChan_V41(lUserID, & struAlarmParam);
    if (lHandle < 0)
    {
        printf("NET_DVR_SetupAlarmChan_V41 error, %d\n", NET_DVR_GetLastError());
        NET_DVR_Logout(lUserID);
        NET_DVR_Cleanup(); 
        return;
    }
  
    Sleep(50000); //等待过程中,如果设备上传报警信息,在报警回调函数里面接收和处理报警信息

    //撤销布防上传通道
    if (!NET_DVR_CloseAlarmChan_V30(lHandle))
    {
        printf("NET_DVR_CloseAlarmChan_V30 error, %d\n", NET_DVR_GetLastError());
        NET_DVR_Logout(lUserID);
        NET_DVR_Cleanup(); 
        return;
    }
  
    //注销用户
    NET_DVR_Logout(lUserID);
    //释放SDK资源
    NET_DVR_Cleanup();
    return;
}

参考这段代码就可以把获取人脸对比信息的搞定了。

  • 参考流程写一段上传人脸图片入库的代码,这里默认库已经建好了,且只有唯一一个库的ID=1,现在就是往里面写入发送图片就可以了。
    NET_DVR_Init();
    NET_DVR_SetExceptionCallBack_V30(0, NULL, g_ExceptionCallBack, (void *)this);

    NET_DVR_SetConnectTime(3000, 2);
    NET_DVR_SetReconnect(60000, false);
    hikSnapInfo *data_info = new hikSnapInfo;

    NET_DVR_DEVICEINFO_V40 strutDeviceInfo{0};
    NET_DVR_USER_LOGIN_INFO structLoginInfo{0};

    structLoginInfo.bUseAsynLogin = false;
    structLoginInfo.wPort = port;
    memcpy(structLoginInfo.sDeviceAddress, camera_ip.c_str(), NET_DVR_DEV_ADDRESS_MAX_LEN);
    memcpy(structLoginInfo.sUserName, camera_username.c_str(), NAME_LEN);
    memcpy(structLoginInfo.sPassword, camera_password.c_str(), NAME_LEN);
    data_info->iUserID = NET_DVR_Login_V40(&structLoginInfo, &strutDeviceInfo);

    string set_res = "";

    if (data_info->iUserID < 0)
    {
        LOG(ERROR) << "Login failed, error code:" << NET_DVR_GetLastError() << ";ip:" << camera_ip << ";user_name:" << camera_username << ";password:" << camera_password;
        NET_DVR_Cleanup();
        delete data_info;
        data_info = nullptr;
        return JsonReturn(1001, "Login failed");
    }
    else
    {
        LOG(INFO) << "Login " << camera_ip << ":" << port << " success";
    }

    NET_DVR_XML_CONFIG_INPUT input_param;
    string search_library_cmd = "GET /ISAPI/Intelligent/FDLib/1";
    input_param.lpRequestUrl = const_cast<char *>(search_library_cmd.c_str());
    input_param.dwSize = sizeof(input_param);
    input_param.dwRequestUrlLen = search_library_cmd.size();
    input_param.lpInBuffer = NULL;
    input_param.dwInBufferSize = 0;

    NET_DVR_XML_CONFIG_OUTPUT output_param;
    int out_size = 512;
    char *save_output = new char[out_size];
    output_param.dwSize = sizeof(output_param);

    output_param.lpOutBuffer = save_output;
    output_param.dwOutBufferSize = sizeof(char) * out_size;
    output_param.lpStatusBuffer = NULL;
    output_param.dwStatusSize = 0;

    //first search default face library
    bool find_re = NET_DVR_STDXMLConfig(data_info->iUserID, &input_param, &output_param);
    if (find_re)
    {
        printf("%s\n", save_output);
        LOG(INFO) << "search face library success then do upload face";

        NET_DVR_FACELIB_COND facelib_cond;
        facelib_cond.dwSize = sizeof(facelib_cond);
        string face_id = "1";
        memcpy(facelib_cond.szFDID, face_id.c_str(), face_id.size());
        facelib_cond.byConcurrent = 0;
        facelib_cond.byCover = 0;
        facelib_cond.byCustomFaceLibID = 0;

        //init upload face
        int upload_handle = NET_DVR_UploadFile_V40(data_info->iUserID, IMPORT_DATA_TO_FACELIB, &facelib_cond, sizeof(facelib_cond), NULL, NULL, 0);
        if (upload_handle == -1)
        {
            LOG(ERROR) << "init upload failed code:" << NET_DVR_GetLastError();
            return JsonReturn(1001, "init upload failed");
        }
        else
        {
            LOG(INFO) << "upload file beign ....";
            vector<PersonInfo> persons_upload_info;
            cJSON *root = cJSON_Parse(person_info.c_str());
            cJSON *json_person_info = cJSON_GetObjectItem(root, "persons");
            if (json_person_info == nullptr)
            {
                LOG(ERROR) << "person info has problem";
                return JsonReturn(1001, "person info has problem");
            }
            else
            {
                cJSON *child_person = json_person_info->child;
                while (child_person != nullptr)
                {
                    PersonInfo person_obj;
                    cJSON *json_id = cJSON_GetObjectItem(child_person, "id");
                    if (json_id == nullptr)
                    {
                        LOG(ERROR) << "ID json not exists please check config json file";
                        return JsonReturn(1001, "person info has problem");
                    }
                    person_obj.id = json_id->valuestring;

                    cJSON *json_image = cJSON_GetObjectItem(child_person, "image");
                    if (json_image == nullptr)
                    {
                        LOG(ERROR) << "image json not exists please check config json file";
                        return JsonReturn(1001, "person info has problem");
                    }
                    string image_path = json_image->valuestring;

                    cJSON *json_name = cJSON_GetObjectItem(child_person, "name");
                    if (json_name == nullptr)
                    {
                        LOG(ERROR) << "name json not exists please check config json file";
                        return JsonReturn(1001, "person info has problem");
                    }
                    string person_name = json_name->valuestring;
                    LOG(INFO) << "person id is : " << person_obj.id << " :" << image_path << " : " << person_name;

                    child_person = child_person->next;
                    stringstream buffer;
                    ifstream in(image_path);
                    buffer.clear();
                    buffer.str("");
                    buffer << in.rdbuf();
                    string contents(buffer.str());
                    string image_name = BaseName(image_path);
                    if (contents.size() > 1000)
                    {
                        //todo this only consider the jpg format
                        NET_DVR_SEND_PARAM_IN param_in;
                        param_in.pSendData = reinterpret_cast<unsigned char *>(const_cast<char *>(contents.c_str()));
                        param_in.dwSendDataLen = contents.size();
                        LOG(INFO) << "image size is :" << param_in.dwSendDataLen;
                        param_in.byPicType = 1;
                        param_in.byPicURL = 0;
                        param_in.byUploadModeling = 0;
                        param_in.dwPicMangeNo = 0;
                        param_in.dwPicDisplayTime = 0;
                        memcpy(param_in.sPicName, image_name.c_str(), NAME_LEN);
                        string xml_header = "<FaceAppendData>";
                        string name_data = "<name>" + person_name + "</name>";
                        string certificate_number = "<certificateNumber>" + person_obj.id + "</certificateNumber>";
                        //todo may be need to save
                        //string person_info_extend = "<PersonInfoExtendList><PersonInfoExtend><id>" + person_obj.id + "</id></PersonInfoExtend></PersonInfoExtendList>";
                        string xml_end = "</FaceAppendData>";
                        string append_data = xml_header + name_data + certificate_number + xml_end;
                        param_in.pSendAppendData = reinterpret_cast<unsigned char *>(const_cast<char *>(append_data.c_str()));
                        param_in.dwSendAppendDataLen = append_data.size();

                        NET_DVR_TIME_V30 net_time;
                        struct tm *t;
                        time_t tt;
                        time(&tt);
                        t = localtime(&tt);
                        net_time.wYear = t->tm_year + 1900;
                        net_time.byMonth = t->tm_mon;
                        net_time.byDay = t->tm_mday;
                        net_time.byHour = t->tm_hour;
                        net_time.byMinute = t->tm_min;
                        net_time.bySecond = t->tm_sec;
                        param_in.struTime = net_time;
                        int re = NET_DVR_UploadSend(upload_handle, &param_in, NULL);
                        if (re == -1)
                        {
                            LOG(ERROR) << "send data occurs problem " << NET_DVR_GetLastError();
                        }
                        else
                        {
                            LOG(INFO) << " do face uplaod .... ";
                            unsigned int progress = 0;
                            while (true)
                            {
                                int state = NET_DVR_GetUploadState(upload_handle, &progress);
                                if (state == -1)
                                {
                                    LOG(ERROR) << "get upload state occurs problem " << NET_DVR_GetLastError();
                                    break;
                                }
                                if (state != 2)
                                {
                                    if (state == 1)
                                    {
                                        person_obj.status = 1;
                                        NET_DVR_UPLOAD_FILE_RET upload_ret;
                                        NET_DVR_GetUploadResult(upload_handle, &upload_ret, sizeof(upload_ret));
                                        person_obj.pic_id = reinterpret_cast<char *>(upload_ret.sUrl);
                                        LOG(INFO) << "upload one face image success " << person_obj.id << "and pic id is :" << person_obj.pic_id;
                                    }
                                    else
                                    {
                                        person_obj.status = 0;
                                        if (state == 39 || state == 40 || state == 41)
                                        {
                                            LOG(ERROR) << "extract face feature occurs problem";
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        LOG(INFO) << "imagae size is too small" << contents.size();
                        person_obj.status = 0;
                    }
                    persons_upload_info.push_back(person_obj);
                }
            }
            set_res = GenerateResult(1000, persons_upload_info);
        }
        NET_DVR_UploadClose(upload_handle);
    }
    else
    {
        LOG(ERROR) << "search error code:" << NET_DVR_GetLastError();
        return JsonReturn(1001, "Please first create library");
    }
    delete[] save_output;
    return set_res;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,377评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,390评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,967评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,344评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,441评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,492评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,497评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,274评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,732评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,008评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,184评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,837评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,520评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,156评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,407评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,056评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,074评论 2 352

推荐阅读更多精彩内容