dev
houxiao
2017-04-21 f757a27218a09fd24a852f34b6490d32fe237017
dev

git-svn-id: http://192.168.1.226/svn/proxy@525 454eff88-639b-444f-9e54-f578c98de674
5个文件已修改
431 ■■■■ 已修改文件
FaceServer/STFaceCache.cpp 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
FaceServer/STFaceCache.h 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
FaceServer/main_face_daemon.cpp 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
FaceServer/sample_face_search.cpp 111 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
FaceServer/sample_face_search.h 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
FaceServer/STFaceCache.cpp
@@ -7,18 +7,64 @@
#include <dirent.h>
#include "sample_face_search.h"
#include <cv_face.h>
struct STFaceContext
struct STFaceCacheContext
{
    int dbid;
    std::string dbfn;
    stface_handles handles;
    cv_handle_t handle_verify;
    cv_handle_t handle_detect;
    STFaceCacheContext() : handle_verify(nullptr), handle_detect(nullptr)
    {
    }
};
typedef std::map<int, STFaceContext> stface_ctx_map_t; // <dbid, ctx>
struct STFaceDBContext
{
    int dbid;
    std::string dbfname;
    std::string dbfpath;
    stface_handles handles;
    bool dbLoadOK;
    STFaceDBContext() : dbid(0), dbfname(), dbfpath(), handles(), dbLoadOK(false)
    {}
    bool init_db(const STFaceCacheContext& ctx)
    {
        handles.handle_verify = ctx.handle_verify;
        handles.handle_detect = ctx.handle_detect;
        dbLoadOK = stface_db_load(handles, db_full_path().c_str());
        dbLoadOK &= (handles.handle_db != nullptr);
        return dbLoadOK;
    }
    void close_db()
    {
        handles.handle_verify = nullptr;
        handles.handle_detect = nullptr;
        cv_verify_destroy_db(handles.handle_db);
        handles.handle_db = nullptr;
        dbLoadOK = false;
    }
    std::string db_full_path() const
    {
        if (dbfpath.empty() || dbfname.empty())
            return "";
        std::string fn(dbfpath);
        fn.append("/");
        fn.append(dbfname);
        return fn;
    }
};
typedef std::map<int, STFaceDBContext> stface_ctx_map_t; // <dbid, ctx>
STFaceCache::STFaceCache(const std::string& _stfacedbPath)
    : stfacedbPath(_stfacedbPath), stfaceModels(STFACESDK_BASE "/models"), _cacheContext(new stface_ctx_map_t)
    : stfacedbPath(_stfacedbPath), stfaceModels(STFACESDK_BASE "/models"),
    _dbContext(new stface_ctx_map_t), _cacheContext(new STFaceCacheContext)
{
    LOG_INFO << "st face db: " << stfacedbPath << LOG_ENDL;
    LOG_INFO << "st face sdk models: " << stfaceModels << LOG_ENDL;
@@ -26,13 +72,50 @@
STFaceCache::~STFaceCache()
{
    delete (stface_ctx_map_t*)_cacheContext;
    delete (stface_ctx_map_t*)_dbContext;
    _dbContext = nullptr;
    delete (STFaceCacheContext*)_cacheContext;
    _cacheContext = nullptr;
}
bool STFaceCache::init()
{
    STFaceCacheContext& cacheContext(*(STFaceCacheContext*)_cacheContext);
    cv_result_t cv_result = cv_face_create_detector(&cacheContext.handle_detect, nullptr, CV_DETECT_ENABLE_ALIGN_21);
    if (cv_result != CV_OK)
    {
        LOGP(ERROR, "create detect handle failed, error code %d\n", cv_result);
        return false;
    }
    std::string modelsFile(stfaceModels);
    modelsFile.append("/verify.model");
    cv_result = cv_verify_create_handle(&cacheContext.handle_verify, modelsFile.c_str());
    if (cv_result != CV_OK)
    {
        LOGP(ERROR, "create verify handle failed, error code %d\n", cv_result);
        return false;
    }
    return true;
}
void STFaceCache::finit()
{
    STFaceCacheContext& cacheContext(*(STFaceCacheContext*)_cacheContext);
    cv_face_destroy_detector(cacheContext.handle_detect);
    cv_verify_destroy_handle(cacheContext.handle_verify);
    cacheContext.handle_detect = nullptr;
    cacheContext.handle_verify = nullptr;
}
bool STFaceCache::load_dbs()
{
    stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
    stface_ctx_map_t& dbContext(*(stface_ctx_map_t*)_dbContext);
    STFaceCacheContext& cacheContext(*(STFaceCacheContext*)_cacheContext);
    
    DIR* dp = opendir(stfacedbPath.c_str());
    if (dp != NULL)
@@ -42,9 +125,18 @@
        {
            //puts(ep->d_name);
            
            STFaceContext ctx;
            ctx.dbfn = ep->d_name;
            ctx.dbid = strtol(ctx.dbfn.c_str(), nullptr, 10);
            STFaceDBContext ctx;
            ctx.dbfname = ep->d_name;
            ctx.dbfpath = stfacedbPath;
            ctx.dbid = strtol(ctx.dbfname.c_str(), nullptr, 10);
            if (ctx.dbfname.find(".stfacedb") == std::string::npos)
                continue;
            if (ctx.dbid == 0)
                continue;
            dbContext.insert(std::make_pair(ctx.dbid, ctx));
        }
        closedir(dp);
    }
@@ -53,16 +145,123 @@
        LOG_ERROR << "Couldn't open the directory." << LOG_ENDL;
        return false;
    }
    for (stface_ctx_map_t::iterator iterCtx = dbContext.begin(); iterCtx != dbContext.end(); ++iterCtx)
    {
        STFaceDBContext& ctx(iterCtx->second);
        bool ret = ctx.init_db(cacheContext);
        LOG_INFO << "init stface db dbid=" << ctx.dbid << ", ret=" << ret << LOG_ENDL;
    }
}
void STFaceCache::close_dbs()
{
    stface_ctx_map_t& dbContext(*(stface_ctx_map_t*)_dbContext);
    for (stface_ctx_map_t::iterator iterCtx = dbContext.begin(); iterCtx != dbContext.end(); ++iterCtx)
    {
        STFaceDBContext& ctx(iterCtx->second);
        ctx.close_db();
    }
}
FDP_FaceDetectResult STFaceCache::detect(const STFaceImage& img)
{
    stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
    stface_ctx_map_t& dbContext(*(stface_ctx_map_t*)_dbContext);
    if (img.db_id == 0)
    {
        // search all db
        //#todo
    }
    else
    {
        stface_ctx_map_t::iterator iterCtx = dbContext.find(img.db_id);
        if (iterCtx == dbContext.end())
        {
            LOG_WARN << "no db find dbid=" << img.db_id << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        STFaceDBContext& ctx(iterCtx->second);
        if (!ctx.dbLoadOK)
        {
            LOG_WARN << "dbLoadOK return false" << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        top_idx_score_vect_t result;
        if (!stface_search_db(ctx.handles, img, result))
        {
            LOG_WARN << "stface_search_db return false" << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        if (result.empty())
        {
            LOG_INFO << "stface_search_db return empty" << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        LOGP(INFO, "stface_search_db return dbid=%d, idx=%d, score=%f", img.db_id, result[0].idx, result[0].score);
        return FDP_FaceDetectResult(img.db_id, result[0].idx);
    }
    return FDP_FaceDetectResult(0, 0);
}
FDP_FaceDetectResult STFaceCache::save(const STFaceImage& img)
FDP_FaceDetectResult STFaceCache::add(const STFaceImage& img)
{
    stface_ctx_map_t& cacheContext(*(stface_ctx_map_t*)_cacheContext);
    return FDP_FaceDetectResult(0, 0);
    stface_ctx_map_t& dbContext(*(stface_ctx_map_t*)_dbContext);
    STFaceCacheContext& cacheContext(*(STFaceCacheContext*)_cacheContext);
    if (img.db_id == 0)
    {
        LOG_WARN << "db_id=0 not ok" << LOG_ENDL;
        return FDP_FaceDetectResult(0, 0);
    }
    stface_ctx_map_t::iterator iterCtx = dbContext.find(img.db_id);
    if (iterCtx == dbContext.end())
    {
        // create db
        STFaceDBContext ctx;
        char dbfname[50];
        sprintf(dbfname, "%d.stfacedb", img.db_id);
        ctx.dbfname = dbfname;
        ctx.dbfpath = stfacedbPath;
        ctx.dbid = img.db_id;
        if (!stface_db_create(ctx.handles, ctx.db_full_path().c_str()))
        {
            LOG_WARN << "stface_db_create return false" << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        if (!ctx.init_db(cacheContext))
        {
            LOG_WARN << "ctx.init_db return false" << LOG_ENDL;
            return FDP_FaceDetectResult(0, 0);
        }
        dbContext.insert(std::make_pair(ctx.dbid, ctx));
        iterCtx = dbContext.find(img.db_id);
    }
    if (iterCtx == dbContext.end())
    {
        LOG_ERROR << "no stfacedb found" << LOG_ENDL;
        return FDP_FaceDetectResult(0, 0);
    }
    STFaceDBContext& ctx(iterCtx->second);
    if (!ctx.dbLoadOK)
    {
        LOG_WARN << "dbLoadOK return false" << LOG_ENDL;
        return FDP_FaceDetectResult(0, 0);
    }
    int idx = stface_db_add(ctx.handles, img);
    LOG_INFO << "stface_db_add dbid=" << img.db_id << ", idx=" << idx << LOG_ENDL;
    return FDP_FaceDetectResult(img.db_id, idx);
}
FaceServer/STFaceCache.h
@@ -4,15 +4,7 @@
#include <string>
#include "face_daemon_proto.h"
struct STFaceImage
{
    int32_t db_id;
    int16_t mb_type; // MB_Frame::MBFType
    int16_t width;
    int16_t height;
    uint32_t size;
    const uint8_t* buff;
};
struct STFaceImage;
class STFaceCache
{
@@ -20,13 +12,21 @@
    STFaceCache(const std::string& _stfacedbPath);
    ~STFaceCache();
    
    bool init();
    void finit();
    bool load_dbs();
    void close_dbs();
    FDP_FaceDetectResult detect(const STFaceImage& img);
    FDP_FaceDetectResult save(const STFaceImage& img);
    FDP_FaceDetectResult add(const STFaceImage& img);
    //#todo need a delete img, if business not linked faceid and its personid
    // they can delete it and save/find again!
    
private:
    const std::string stfacedbPath;
    const std::string stfaceModels;
    void* _dbContext;
    void* _cacheContext;
};
FaceServer/main_face_daemon.cpp
@@ -4,6 +4,7 @@
#include "ev_server.h" 
#include "ev_proto.h"
#include "face_daemon_proto.h"
#include "sample_face_search.h"
#include "STFaceCache.h"
#include <PbFaceList.pb.h>
@@ -27,9 +28,9 @@
bool send_SensetimeFaceDetectResultJson(EVClientStub& client, const fdr_vec_t& result)
{
    std::stringstream ss;
    ss << "{" << std::endl;
    ss << "\"ret\":" << WRAPPER_TEXT(0) << "," << std::endl;
    ss << "\"count\":" << WRAPPER_TEXT(result.size()) << "," << std::endl;
    ss << "{" << LOG_ENDL;
    ss << "\"ret\":" << WRAPPER_TEXT(0) << "," << LOG_ENDL;
    ss << "\"count\":" << WRAPPER_TEXT(result.size()) << "," << LOG_ENDL;
    ss << "\"result\":[";
    for(fdr_vec_t::const_iterator iter = result.begin(); iter != result.end(); ++iter)
    {
@@ -37,7 +38,7 @@
        if (iter != std::prev(result.end()))
            ss << ",";
    }
    ss << "]" << std::endl;
    ss << "]" << LOG_ENDL;
    ss << "}";
    std::string output(ss.str());//#todo avoid copy
@@ -55,7 +56,7 @@
{
    //#test send //00038300FE4B0000+pb
    //EVPHeader* evpHeader = (EVPHeader*)client.recvBuff;
    //LOG_DEBUG << "cmd=" << evpHeader->cmd << ", size=" << evpHeader->size << ", \t" << (char*)(evpHeader + sizeof(EVPHeader)) << std::endl;
    //LOG_DEBUG << "cmd=" << evpHeader->cmd << ", size=" << evpHeader->size << ", \t" << (char*)(evpHeader + sizeof(EVPHeader)) << LOG_ENDL;
    //return true;
    
    EVPHeader* evpHeader = (EVPHeader*)client.recvBuff;
@@ -109,7 +110,7 @@
    EVPHeader* evpHeader = (EVPHeader*)client.recvBuff;
    if (evpHeader->size != client.recvBuffSize)
    {
        LOG_WARN << "Truncated buffer " << (evpHeader->size - client.recvBuffSize) << " bytes" << std::endl;
        LOG_WARN << "Truncated buffer " << (evpHeader->size - client.recvBuffSize) << " bytes" << LOG_ENDL;
        return false;
    }
@@ -120,7 +121,7 @@
        return ev_proc_SensetimeFaceDetectPB(client);
    break;
    default:
        LOG_WARN << "Unknown command" << std::endl;
        LOG_WARN << "Unknown command" << LOG_ENDL;
        ev_send_status_packet(client, EVPStatus::EVPS_COMMAND_ERROR);
        return false;
    break;
@@ -137,7 +138,7 @@
    EVPHeader* evpHeader = (EVPHeader*)client.recvBuff;
    if (evpHeader->size != client.recvBuffSize)
    {
        LOG_WARN << "Truncated buffer " << (evpHeader->size - client.recvBuffSize) << " bytes" << std::endl;
        LOG_WARN << "Truncated buffer " << (evpHeader->size - client.recvBuffSize) << " bytes" << LOG_ENDL;
        return false;
    }
@@ -147,7 +148,7 @@
        return ev_dispatcher_proto_pb(client);
    break;
    default:
        LOG_WARN << "Unknown proto" << std::endl;
        LOG_WARN << "Unknown proto" << LOG_ENDL;
        ev_send_status_packet(client, EVPStatus::EVPS_PROTO_ERROR);
        return false;
    break;
@@ -163,6 +164,23 @@
    
    signal(SIGINT, _sigint);
    if (!g_STFaceCache.init())
    {
        LOG_WARN << "g_STFaceCache.init return false" << LOG_ENDL;
        return EXIT_FAILURE;
    }
    if (!g_STFaceCache.load_dbs())
    {
        LOG_WARN << "g_STFaceCache.load_dbs return false" << LOG_ENDL;
        return EXIT_FAILURE;
    }
    evclient_proc = ev_dispatcher_proto;
    return server_main(argc, argv);
    int ec = server_main(argc, argv);
    g_STFaceCache.close_dbs();
    g_STFaceCache.finit();
    return ec;
}
FaceServer/sample_face_search.cpp
@@ -1,4 +1,5 @@
#include "sample_face_search.h"
#include "STFaceCache.h"
#include <logger.h>
#include <vector>
@@ -35,15 +36,17 @@
                        bgr_image.cols, bgr_image.rows, bgr_image.step,
                        p_face, &p_feature, nullptr);
        if (st_result != CV_OK) {
            LOGP(INFO, "cv_verify_get_feature failed, error code %d\n", st_result);
            LOGP(DEBUG, "cv_verify_get_feature failed, error code %d\n", st_result);
        }
    } else {
        LOGP(INFO, "can't find face in %s", image_path);
        LOGP(DEBUG, "can't find face in %s", image_path);
    }
    // release the memory of face
    cv_face_release_detector_result(p_face, face_count);
    return p_feature;
}
cv_feature_t *stface_extract_feature(stface_handles& handles, const STFaceImage& image);//#todo
int stface_db_add(stface_handles& handles, const char *image_path) {
    cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
@@ -53,50 +56,52 @@
    int idx;
    cv_result_t cv_result = cv_verify_add_face(handles.handle_db, p_feature, &idx);
    if (cv_result != CV_OK) {
        LOGP(INFO, "cv_verify_add_face failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_add_face failed, error code %d\n", cv_result);
    }
    cv_verify_release_feature(p_feature);
    return idx;
}
int stface_db_add(stface_handles& handles, const STFaceImage& image);//#todo
bool stface_db_del(stface_handles& handles, int idx) {
    if (idx < 0) {
        LOGP(INFO, "invalid idx!\n");
        LOGP(DEBUG, "invalid idx!\n");
        return false;
    }
    cv_result_t cv_result = CV_OK;
    cv_result = cv_verify_delete_face(handles.handle_db, idx);
    if (cv_result != CV_OK) {
        LOGP(INFO, "cv_verify_delete_face failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_delete_face failed, error code %d\n", cv_result);
    }
    else {
        LOGP(INFO, "delete succeed\n");
        LOGP(DEBUG, "delete succeed\n");
    }
}
bool stface_db_save(stface_handles& handles, char *db_path) {
bool stface_db_save(stface_handles& handles, const char *db_path) {
    cv_result_t cv_result = CV_OK;
    cv_result = cv_verify_save_db(handles.handle_db, db_path);
    if (cv_result != CV_OK) {
        LOGP(INFO, "cv_verify_save_db failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_save_db failed, error code %d\n", cv_result);
        return false;
    }
    else {
        LOGP(INFO, "save done!\n");
        LOGP(DEBUG, "save done!\n");
    }
    return true;
}
bool stface_db_load(stface_handles& handles, char *db_path) {
bool stface_db_load(stface_handles& handles, const char *db_path) {
    cv_result_t cv_result = CV_OK;
    cv_result = cv_verify_load_db(handles.handle_db, db_path);
    if (cv_result != CV_OK) {
        LOGP(INFO, "cv_verify_load_db failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_load_db failed, error code %d\n", cv_result);
        return false;
    }
    else {
        LOGP(INFO, "load done!\n");
        LOGP(DEBUG, "load done!\n");
    }
    return true;
@@ -106,7 +111,7 @@
    bool bresult = true;
    FILE *fp_path = fopen(image_list, "r");
    if(!fp_path) {
        LOGP(INFO, "failed to load %s\n", image_list);
        LOGP(DEBUG, "failed to load %s\n", image_list);
        return false;
    }
    std::vector<cv_feature_t *> list_feature;
@@ -118,12 +123,12 @@
            bresult = false;
            break;
        }
        LOGP(INFO, "extracting %s\n", image_path);
        LOGP(DEBUG, "extracting %s\n", image_path);
        // get the face feature
        cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
        if (!p_feature) {
            LOGP(INFO, "failed to extract image: %s\n", image_path);
            LOGP(DEBUG, "failed to extract image: %s\n", image_path);
            continue;
        }
        list_feature.push_back(p_feature);
@@ -134,7 +139,7 @@
    cv_verify_create_db(&handles.handle_db);
    cv_result = cv_verify_build_db(handles.handle_db, &list_feature[0], list_feature.size());
    if (cv_result != CV_OK) {
        LOGP(INFO, "cv_verify_build_db failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_build_db failed, error code %d\n", cv_result);
        bresult = false;
    }
    cv_verify_save_db(handles.handle_db, output_db_path);
@@ -149,14 +154,14 @@
bool stface_search_db(stface_handles& handles, char *image_path) {
    FILE *fp_path = fopen(image_path, "r");
    if (fp_path == nullptr) {
        LOGP(INFO, "invalid path !\n");
        LOGP(DEBUG, "invalid path !\n");
        return false;
    }
    fclose(fp_path);
    cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
    if (p_feature == nullptr) {
        LOGP(INFO, "extract failed !\n");
        LOGP(DEBUG, "extract failed !\n");
        return false;
    }
@@ -170,12 +175,12 @@
    if (cv_result == CV_OK) {
        for (unsigned int t = 0; t < result_length; t++) {
            // const cv_feature_t item = result[t].item;
            LOGP(INFO, "%d\t", top_idxs[t]);
            LOGP(INFO, "%0.2f\n", top_scores[t]);
            LOGP(DEBUG, "%d\t", top_idxs[t]);
            LOGP(DEBUG, "%0.2f\n", top_scores[t]);
        }
    }
    else {
        LOGP(INFO, "cv_verify_search_face failed, error code %d\n", cv_result);
        LOGP(DEBUG, "cv_verify_search_face failed, error code %d\n", cv_result);
    }
    if (top_idxs) {
        delete[]top_idxs;
@@ -188,16 +193,18 @@
    return true;
}
bool stface_search_db(stface_handles& handles, const STFaceImage& image, top_idx_score_vect_t& result);//#todo
bool stface_search_list(stface_handles& handles, char *image_path, char *list_path) {
    cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
    if (p_feature == nullptr) {
        LOGP(INFO, "failed to extract image: %s\n", image_path);
        LOGP(DEBUG, "failed to extract image: %s\n", image_path);
        return false;
    }
    FILE *fp_path = fopen(list_path, "r");
    if(!fp_path) {
        LOGP(INFO, "failed to load %s\n", list_path);
        LOGP(DEBUG, "failed to load %s\n", list_path);
        return false;
    }
    std::vector<cv_feature_t *> list_feature;
@@ -208,12 +215,12 @@
        if (num != 1) {
            break;
        }
        LOGP(INFO, "extracting %s\n", image_path);
        LOGP(DEBUG, "extracting %s\n", image_path);
        // get the face feature
        cv_feature_t *p_feature = stface_extract_feature(handles, image_path);
        if (!p_feature) {
            LOGP(INFO, "failed to extract image: %s\n", image_path);
            LOGP(DEBUG, "failed to extract image: %s\n", image_path);
            continue;
        }
        list_feature.push_back(p_feature);
@@ -232,60 +239,60 @@
    if (cv_result == CV_OK) {
        for (unsigned int t = 0; t < result_length; t++) {
            LOGP(INFO, "%d\t", top_idxs[t]);
            LOGP(INFO, "%0.2f\n", top_scores[t]);
            LOGP(DEBUG, "%d\t", top_idxs[t]);
            LOGP(DEBUG, "%0.2f\n", top_scores[t]);
        }
    } else {
        LOGP(INFO, "search face failed");
        LOGP(DEBUG, "search face failed");
    }
    cv_verify_release_feature(p_feature);
    for (int i = 0; i < list_feature.size(); i++) {
        cv_verify_release_feature(list_feature[i]);
    }
    LOGP(INFO, "list search done!\n");
    LOGP(DEBUG, "list search done!\n");
    return true;
}
void stface_get_help() {
    LOGP(INFO, "Usage: help | Get cmd list\n");
    LOGP(INFO, "Usage: search p_image_colorpath | Search image in db\n");
    LOGP(INFO, "Usage: add p_image_colorpath | Add image in db, return idx in db, if idx < 0 means failed\n");
    LOGP(INFO, "Usage: del idx | Delete image in db\n");
    LOGP(INFO, "Usage: save db_file | Save current db in db_file\n");
    LOGP(INFO, "Usage: load db_file | Load db in db_file\n");
    LOGP(INFO, "Usage: gen p_image_colorlist db_file | Gen images in p_image_colorlist and save in db_file\n");
    LOGP(INFO, "Usage: exit | Exit the program\n");
    LOGP(DEBUG, "Usage: help | Get cmd list\n");
    LOGP(DEBUG, "Usage: search p_image_colorpath | Search image in db\n");
    LOGP(DEBUG, "Usage: add p_image_colorpath | Add image in db, return idx in db, if idx < 0 means failed\n");
    LOGP(DEBUG, "Usage: del idx | Delete image in db\n");
    LOGP(DEBUG, "Usage: save db_file | Save current db in db_file\n");
    LOGP(DEBUG, "Usage: load db_file | Load db in db_file\n");
    LOGP(DEBUG, "Usage: gen p_image_colorlist db_file | Gen images in p_image_colorlist and save in db_file\n");
    LOGP(DEBUG, "Usage: exit | Exit the program\n");
}
int stface_main(stface_handles& handles, int argc, char *argv[]) {
    cv_result_t cv_result = cv_face_create_detector(&handles.handle_detect, nullptr, CV_DETECT_ENABLE_ALIGN_21);
    if (cv_result != CV_OK){
        LOGP(INFO, "create detect handle failed, error code %d\n", cv_result);
        LOGP(DEBUG, "create detect handle failed, error code %d\n", cv_result);
    }
    cv_result = cv_verify_create_handle(&handles.handle_verify, "../../../models/verify.model");
    if (cv_result != CV_OK){
        LOGP(INFO, "create verify handle failed, error code %d\n", cv_result);
        LOGP(DEBUG, "create verify handle failed, error code %d\n", cv_result);
    }
    cv_result = cv_verify_create_db(&handles.handle_db);
    if (cv_result != CV_OK){
        LOGP(INFO, "create db handle failed, error code %d\n", cv_result);
        LOGP(DEBUG, "create db handle failed, error code %d\n", cv_result);
    }
    
    if (handles.handle_detect != nullptr && handles.handle_verify != nullptr && handles.handle_db != nullptr) {
        // stface_db_gen("list.txt","out.db");
        LOGP(INFO, "Database is empty at the beginning\n");
        LOGP(INFO, "Please input 'help' to get the cmd list\n");
        LOGP(DEBUG, "Database is empty at the beginning\n");
        LOGP(DEBUG, "Please input 'help' to get the cmd list\n");
        char input_code[256];
        char image_path[_MAX_PATH];
        char db_path[_MAX_PATH];
        char command[256];
        input_code[0] = 0;
        while (1) {
            LOGP(INFO, ">>");
            LOGP(DEBUG, ">>");
            if (!fgets(input_code, 256, stdin)) {
                LOGP(INFO, "read nothing\n");
                LOGP(DEBUG, "read nothing\n");
                continue;
            }
            int input_length = strlen(input_code);
@@ -302,7 +309,7 @@
            else if (strcmp(str_input_code.substr(0, 3).c_str(), "add") == 0) {
                int input_number = sscanf(input_code, "%s%s", command, image_path);
                if (input_number != 2) {
                    LOGP(INFO, "invalid! Usage: add p_image_colorpath\n");
                    LOGP(DEBUG, "invalid! Usage: add p_image_colorpath\n");
                    continue;
                }
                int idx = stface_db_add(handles, image_path);
@@ -312,7 +319,7 @@
                int idx = -1;
                int input_number = sscanf(input_code, "%s%d", image_path, &idx);
                if (input_number != 2) {
                    LOGP(INFO, "invalid! Usage: del idx(unsigned int\n");
                    LOGP(DEBUG, "invalid! Usage: del idx(unsigned int\n");
                    continue;
                }
                stface_db_del(handles, idx);
@@ -320,7 +327,7 @@
            else if (strcmp(str_input_code.substr(0, 4).c_str(), "save") == 0) {
                int input_number = sscanf(input_code, "%s%s", command, image_path);
                if (input_number != 2) {
                    LOGP(INFO, "invalid! Usage: save db_file\n");
                    LOGP(DEBUG, "invalid! Usage: save db_file\n");
                    continue;
                }
                stface_db_save(handles, image_path);
@@ -328,7 +335,7 @@
            else if (strcmp(str_input_code.substr(0, 4).c_str(), "load") == 0) {
                int input_number = sscanf(input_code, "%s%s", command, image_path);
                if (input_number != 2) {
                    LOGP(INFO, "invalid! Usage: load db_file\n");
                    LOGP(DEBUG, "invalid! Usage: load db_file\n");
                    continue;
                }
                stface_db_load(handles, image_path);
@@ -339,7 +346,7 @@
            else if (strcmp(str_input_code.substr(0, 3).c_str(), "gen") == 0) {
                int input_number = sscanf(input_code, "%s%s%s", command, image_path, db_path);
                if (input_number != 3) {
                    LOGP(INFO, "invalid! Usage: gen p_image_colorlist_file db_file\n");
                    LOGP(DEBUG, "invalid! Usage: gen p_image_colorlist_file db_file\n");
                    continue;
                }
                stface_db_gen(handles, image_path, db_path);
@@ -347,7 +354,7 @@
            else if (strcmp(str_input_code.substr(0, 6).c_str(), "search") == 0) {
                int input_number = sscanf(input_code, "%s%s", command, image_path);
                if (input_number != 2) {
                    LOGP(INFO, "invalid! Usage: search p_image_colorpath\n");
                    LOGP(DEBUG, "invalid! Usage: search p_image_colorpath\n");
                    continue;
                }
                stface_search_db(handles, image_path);
@@ -357,13 +364,13 @@
                int input_number = sscanf(input_code, "%s%s%s", command, search_path,
                    image_path);
                if (input_number != 3) {
                    LOGP(INFO, "invalid! Usage: listsearch p_image_colorsrcpath p_image_colorlistpath\n");
                    LOGP(DEBUG, "invalid! Usage: listsearch p_image_colorsrcpath p_image_colorlistpath\n");
                    continue;
                }
                stface_search_list(handles, search_path, image_path);
            }
            else {
                LOGP(INFO, "invalid cmd, please input 'help' to get the cmd list\n");
                LOGP(DEBUG, "invalid cmd, please input 'help' to get the cmd list\n");
            }
        }
    }
FaceServer/sample_face_search.h
@@ -1,6 +1,9 @@
#ifndef _SAMPLE_FACE_SEARCH_H_
#define _SAMPLE_FACE_SEARCH_H_
#include <stdint.h>
#include <vector>
typedef void* cv_handle_t;
struct cv_feature_t;
@@ -14,19 +17,45 @@
    {}
};
struct STFaceImage
{
    int32_t db_id;
    int16_t mb_type; // MB_Frame::MBFType
    int16_t width;
    int16_t height;
    uint32_t size;
    const uint8_t* buff;
};
struct TopIdxScore
{
    int idx;
    float score;
    TopIdxScore(int _idx, float _score) : idx(_idx), score(_score)
    {}
};
typedef std::vector<TopIdxScore> top_idx_score_vect_t;
cv_feature_t *stface_extract_feature(stface_handles& handles, const char *image_path);
cv_feature_t *stface_extract_feature(stface_handles& handles, const STFaceImage& image);
int stface_db_add(stface_handles& handles, const char *image_path);
int stface_db_add(stface_handles& handles, const STFaceImage& image);
bool stface_db_del(stface_handles& handles, int idx);
bool stface_db_save(stface_handles& handles, char *db_path);
bool stface_db_save(stface_handles& handles, const char *db_path);
bool stface_db_load(stface_handles& handles, char *db_path);
bool stface_db_load(stface_handles& handles, const char *db_path);
bool stface_db_create(stface_handles& handles, const char *db_path);
bool stface_db_gen(stface_handles& handles, char *image_list, char *output_db_path);
bool stface_search_db(stface_handles& handles, char *image_path);
bool stface_search_db(stface_handles& handles, const STFaceImage& image, top_idx_score_vect_t& result);
bool stface_search_list(stface_handles& handles, char *image_path, char *list_path);