843 lines
27 KiB
C++
843 lines
27 KiB
C++
//#include <ShlObj.h>
|
|
#include <omp.h>
|
|
#include <iostream>
|
|
#include <filesystem>
|
|
#include "Inc/FaceDbMgr.h"
|
|
|
|
|
|
#define SEARCH_FACE_THRESHOLD 0.8 //A similarity threshold for default match
|
|
#define SAME_FACE_THRESHOLD 0.7 //A similarity threshold for entering the same person
|
|
#define FEATURE_NAME_MAX_LEN 64 //Max lenght for entering name
|
|
|
|
//创建人脸数据表 ID Feature Name VID Image GroupID EnterTime
|
|
#define FS_DB_CREATE_TABLE "CREATE TABLE table_features(ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,Feature blob NOT NULL,Name VARCHAR(64) NOT NULL,VID VARCHAR(64),Image blob NOT NULL,GroupID INTEGER NOT NULL,EnterTime datetime default(datetime('now','localtime')));"
|
|
//检查人脸数据表是否存在
|
|
#define FS_DB_CHECK_TABLE_EXIST "select count(*) from sqlite_master where type='table' and name = 'table_features';"
|
|
//给人脸数据表 ID字段加上索引
|
|
#define FS_DB_CREATE_ID_INDEX "CREATE UNIQUE INDEX id_index ON table_features(ID);"
|
|
//检查人脸数据表 ID字段是否有索引
|
|
#define FS_DB_CHECK_ID_INDEX_EXIST "select count(*) from sqlite_master where type='index' and name = 'id_index';"
|
|
//给人脸数据表 NAME字段加上索引
|
|
#define FS_DB_CREATE_NAME_INDEX "CREATE INDEX name_index ON table_features(Name);"
|
|
//检查人脸数据表 NAME字段是否有索引
|
|
#define FS_DB_CHECK_NAME_INDEX_EXIST "select count(*) from sqlite_master where type='index' and name = 'name_index';"
|
|
//查询人数据表 人脸特征总数
|
|
#define FS_DB_QUERY_FEATURES_SIZE "select count(*) from table_features;"
|
|
//查询分组下面的人脸特征总数
|
|
#define FS_DB_QUERY_GROUP_FEATURES_SIZE "select count(*) from table_features where GroupID=?;"
|
|
//添加人脸数据
|
|
#define FS_DB_INSERT_FEATURE_DATA "insert into table_features(Feature,Name,VID,Image,GroupID) values(?,?,?,?,?)"
|
|
|
|
#define FS_DB_CLEAR_TABLE_SEQUENCE "UPDATE sqlite_sequence SET seq = 0 WHERE name='table_features';"
|
|
|
|
//通过名字删除人脸
|
|
#define FS_DB_DELETE_FEATURE_BY_NAME "delete from table_features where Name=? and GroupID=?;" //The '?' in string can't be quoted with '',or it can't not be parsed by 'sqlite3_prepare'
|
|
//删除分组下面的所有人脸数据
|
|
#define FS_DB_DELETE_FEATURE_BY_GROUP "delete from table_features where GroupID=?;"
|
|
//查询所有人脸数据
|
|
#define FS_DB_QUERY_FEATURES_INFO "SELECT * FROM table_features;"
|
|
//通过Group Id 查询人脸数据
|
|
#define FS_DB_QUERY_FEATURES_INFO_BY_GROPU "SELECT * FROM table_features WHERE GroupID=?;"
|
|
//通过名字查询人脸数据
|
|
#define FS_DB_QUERY_FEATURES_INFO_BY_NAME "SELECT * FROM table_features WHERE NAME=? AND GroupID=?;"
|
|
//通过名字和组ID查询图片
|
|
#define FS_DB_QUERY_IMG_BY_NAME "SELECT Image FROM table_features WHERE NAME=? AND GroupID=?;"
|
|
|
|
|
|
#define FACEFEATURES_DEFAULT_SIZE 2000 //A default increase size
|
|
|
|
//分组表sql
|
|
//创建人脸分组索引表
|
|
#define FS_DB_CREATE_GROUP_TABLE "CREATE TABLE table_group(ID INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,Name VARCHAR(64) NOT NULL, Remarks VARCHAR(512),EnterTime datetime default(datetime('now','localtime')));"
|
|
//检查分组表是否存在
|
|
#define FS_DB_CHECK_GROUP_TABLE_EXIST "select count(*) from sqlite_master where type='table' and name = 'table_group';"
|
|
//给分组表添加名称索引
|
|
#define FS_DB_GROUP_CREATE_ID_INDEX "CREATE UNIQUE INDEX group_name_index ON table_group(Name);"
|
|
//查询分组总数
|
|
#define FS_DB_QUERY_GROUP_SIZE "select count(*) from table_group;"
|
|
//通过名字查询分组ID
|
|
#define FS_DB_QUERY_GROUP_ID_BY_NAME "select ID from table_group where Name=?;"
|
|
//通过名字查询分组信息
|
|
#define FS_DB_QUERY_GROUP_BY_NAME "select * from table_group where Name=?;"
|
|
//通过ID查询分组信息
|
|
#define FS_DB_QUERY_GROUP_BY_ID "select * from table_group where ID=?;"
|
|
|
|
//查询分组数据
|
|
#define FS_DB_QUERY_GROUP_DATA "select * from table_group;"
|
|
//通过名字删除分组表
|
|
#define FS_DB_DELETE_GROUP_BY_NAME "delete from table_group where Name=?;"
|
|
//插入一条分组数据
|
|
#define FS_DB_INSTER_GROUP_DATA "insert into table_group(Name,Remarks) values(?,?)"
|
|
|
|
|
|
FaceDbMgr* FaceDbMgr::m_instance = nullptr;
|
|
std::vector<DB_GROUP_OBJ> FaceDbMgr::m_groups;
|
|
std::map<int, std::vector<DB_FACE_OBJ>> FaceDbMgr::m_GroupDb;
|
|
|
|
static int _callback_exec(void * notused, int argc, char ** argv, char ** aszColName)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
float FaceDbMgr::FeatureCompare(const float* feature1, const float* feature2)
|
|
{
|
|
float tmp0 = 0, tmp1 = 0, tmp2 = 0;
|
|
for (int i = 0; i < 512; i++)
|
|
{
|
|
tmp0 += feature1[i] * feature2[i];
|
|
tmp1 += feature1[i] * feature1[i];
|
|
tmp2 += feature2[i] * feature2[i];
|
|
}
|
|
|
|
float score = (float(tmp0 / (sqrt(tmp1)* sqrt(tmp2))));
|
|
//return score;
|
|
//拉高分数
|
|
float max_score = log10f(1.01);
|
|
float min_score = log10f(0.02);
|
|
float ret, temp;
|
|
if (score <= 0) {
|
|
temp = fabs(score);
|
|
if (temp > 0.3) {
|
|
ret = 0.0001;
|
|
}
|
|
else {
|
|
ret = temp;
|
|
}
|
|
}
|
|
else {
|
|
temp = log10f(score + 0.01);
|
|
ret = fabsf(temp - min_score) / (max_score - min_score);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
FaceDbMgr* FaceDbMgr::GetInstance()
|
|
{
|
|
if (m_instance == nullptr)
|
|
{
|
|
m_instance = new FaceDbMgr();
|
|
}
|
|
return m_instance;
|
|
}
|
|
|
|
FaceDbMgr::FaceDbMgr(char * pcDbName)
|
|
{
|
|
/******************初始化错误映射表**********************/
|
|
//m_err_info[DB_ERR_SQL] = UnicodeToUtf8(L"数据库引擎内部SQL脚本错误");
|
|
//m_err_info[DB_ERR_BIND_SQL_DATA] = UnicodeToUtf8(L"数据库引擎内部绑定SQL参数错误");
|
|
//m_err_info[DB_ERR_SQL_EXE] = UnicodeToUtf8(L"数据库引擎内部执行SQL错误");
|
|
//m_err_info[DB_ERR_FEATURE_LEN] = UnicodeToUtf8(L"人脸特征长度错误");
|
|
//m_err_info[DB_ERR_NAME_FEATURE_EXIST] = UnicodeToUtf8(L"当前名字已经被注册");
|
|
//m_err_info[DB_ERR_GROUP_FEATURE_FULL] = UnicodeToUtf8(L"当前分组下的人脸注册数量已经达到上限");
|
|
//m_err_info[DB_ERR_GROUP_FULL] = UnicodeToUtf8(L"当前分组数量已经达到上限,无法创建新的分组");
|
|
//m_err_info[DB_ERR_ADD_FACE_FEATURE] = UnicodeToUtf8(L"录入人脸特征失败");
|
|
//m_err_info[DB_ERR_NON_GROUP] = UnicodeToUtf8(L"输入的分组名称不存在");
|
|
//m_err_info[DB_ERR_GROUP_REPEAT] = UnicodeToUtf8(L"当前分组名称已经被使用");
|
|
//m_err_info[DB_ERR_ADD_GROUP] = UnicodeToUtf8(L"添加分组失败");
|
|
//m_err_info[DB_ERR_NO_INIT] = UnicodeToUtf8(L"数据库引擎未初始化");
|
|
//m_err_info[DB_ERR_NO_DATA] = UnicodeToUtf8(L"未查询到数据");
|
|
//m_err_info[DB_ERR_OK] = UnicodeToUtf8(L"无错误");
|
|
|
|
|
|
/******************************************************/
|
|
|
|
|
|
m_bDbInit = false;
|
|
m_db = NULL;
|
|
|
|
|
|
std::string tempDbPath = std::string(std::experimental::filesystem::current_path().generic_string()) + std::string("/FaceDb/");
|
|
if (!std::experimental::filesystem::exists(std::experimental::filesystem::path(tempDbPath)))
|
|
{
|
|
std::experimental::filesystem::create_directory(std::experimental::filesystem::path(tempDbPath));
|
|
}
|
|
tempDbPath.append(pcDbName);
|
|
|
|
int res = 0;
|
|
res = sqlite3_open(tempDbPath.c_str(), &m_db);
|
|
if (res != SQLITE_OK)
|
|
{
|
|
std::cout << "Open DB " << tempDbPath.c_str() << "Failed. ErrCode is :" << res << std::endl;
|
|
return;
|
|
}
|
|
m_bDbInit = true;
|
|
|
|
//查询分组索引表是否存在
|
|
if (QueryTableSize(FS_DB_CHECK_GROUP_TABLE_EXIST) < 1)
|
|
{
|
|
//创建分组索引表
|
|
FeatureDBMgrExec(FS_DB_CREATE_GROUP_TABLE);
|
|
FeatureDBMgrExec(FS_DB_GROUP_CREATE_ID_INDEX);
|
|
|
|
}
|
|
if (QueryTableSize(FS_DB_CHECK_TABLE_EXIST) < 1)
|
|
{
|
|
//创建人脸数据表
|
|
FeatureDBMgrExec(FS_DB_CREATE_TABLE);
|
|
if (QueryTableSize(FS_DB_CHECK_NAME_INDEX_EXIST) < 1)
|
|
{//创建名字索引
|
|
res = FeatureDBMgrExec(FS_DB_CREATE_NAME_INDEX);
|
|
if (res != SQLITE_OK)
|
|
{
|
|
std::cout << "Create name_index Failed ...ErrCode:" << res << std::endl;
|
|
return;
|
|
}
|
|
res = FeatureDBMgrExec(FS_DB_CREATE_ID_INDEX);
|
|
if (res != SQLITE_OK)
|
|
{
|
|
std::cout << "Create id_index Failed ...ErrCode:" << res << std::endl;
|
|
return;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
std::cout << "Face DB Init Ok! " << std::endl;
|
|
|
|
{//加载人脸数据到内存
|
|
int group_num = QueryTableSize(FS_DB_QUERY_GROUP_SIZE);
|
|
if (group_num < 1) return; //没有分组,数据库没有人脸数据
|
|
QueryGroupDatas(m_groups);
|
|
std::cout << "group num: "<< m_groups.size() << std::endl;
|
|
for (auto& obj: m_groups)
|
|
{
|
|
std::vector<DB_FACE_OBJ> face_objs;
|
|
QueryFeatrueByGroup(obj, face_objs);
|
|
m_GroupDb[obj.group_id] = face_objs;
|
|
std::cout << "load group " << obj.group_name << ",face num: " << face_objs.size() << std::endl;
|
|
}
|
|
std::cout << "load data ok!" << std::endl;
|
|
}
|
|
}
|
|
|
|
FaceDbMgr::~FaceDbMgr()
|
|
{
|
|
if (m_db)
|
|
{
|
|
int res = sqlite3_close(m_db);
|
|
if (res == SQLITE_OK)
|
|
{
|
|
m_db = NULL;
|
|
}
|
|
else
|
|
{
|
|
std::cout << "Close DB Failed. ErrCode is : " << res << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool FaceDbMgr::IsDbInit()
|
|
{
|
|
return m_bDbInit;
|
|
}
|
|
|
|
int FaceDbMgr::FeatureDBMgrExec(const char * strSql)
|
|
{
|
|
if (!m_bDbInit)
|
|
{
|
|
return -1;//DB must be initialized
|
|
}
|
|
char * pErrMsg = NULL;
|
|
int res = sqlite3_exec(m_db, strSql, _callback_exec, 0, &pErrMsg);
|
|
return res;
|
|
}
|
|
|
|
/***************************************************************/
|
|
/* 查询数据数量 */
|
|
int FaceDbMgr::QueryTableSize(const char * strSql)
|
|
{
|
|
if (!m_bDbInit || strSql == NULL) return DB_ERR_NO_INIT;
|
|
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, strSql, strlen(strSql), &pstmt, 0);
|
|
if (ret != SQLITE_OK)
|
|
{
|
|
return 0;
|
|
}
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
return 0;
|
|
}
|
|
int countNum = sqlite3_column_int(pstmt, 0);
|
|
return countNum;
|
|
}
|
|
|
|
/* 通过名字查询查询数据数量 */
|
|
int FaceDbMgr::QueryTableSizeByName(const char * strSql, const char * strPersonName)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, strSql, strlen(strSql), &pstmt, 0);
|
|
if (ret != SQLITE_OK)
|
|
{
|
|
return DB_ERR_SQL;
|
|
}
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
|
|
ret = sqlite3_bind_text(pstmt, 1, strPersonName, strnlen_s(strPersonName, 64), NULL);
|
|
if (ret != SQLITE_OK)
|
|
{
|
|
return DB_ERR_BIND_SQL_DATA;
|
|
}
|
|
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
int countNum = sqlite3_column_int(pstmt, 0);
|
|
return countNum;
|
|
}
|
|
|
|
/* 查询所有的人脸特征数量*/
|
|
int FaceDbMgr::QueryAllFeatureSize()
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_FEATURES_SIZE, strlen(FS_DB_QUERY_FEATURES_SIZE), &pstmt, 0);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW) return DB_ERR_SQL_EXE;
|
|
return sqlite3_column_int(pstmt, 0);
|
|
}
|
|
|
|
/* 查询分组内所有的人脸特征数量 */
|
|
int FaceDbMgr::QueryGroupAllFeatureSize(int group_id)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_FEATURES_SIZE,
|
|
strlen(FS_DB_QUERY_GROUP_FEATURES_SIZE), &pstmt, 0);
|
|
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_bind_int(pstmt, 1, group_id);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
if (ret != SQLITE_DONE)
|
|
{
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
return DB_ERR_NO_DATA;
|
|
}
|
|
int num = sqlite3_column_int(pstmt, 0);
|
|
return num;
|
|
}
|
|
|
|
//通过组名查询组内注册人脸特征数量
|
|
int FaceDbMgr::QueryNameFeatureInGroupSize(std::string groupName, std::string faceName)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_FEATURES_SIZE,
|
|
strlen(FS_DB_QUERY_GROUP_FEATURES_SIZE), &pstmt, 0);
|
|
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_bind_text(pstmt, 1, groupName.c_str(), groupName.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_text(pstmt, 2, faceName.c_str(), faceName.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
if (ret == SQLITE_DONE)
|
|
{
|
|
return DB_ERR_NO_DATA;
|
|
}
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
int feature_num = sqlite3_column_int(pstmt, 0);
|
|
return feature_num;
|
|
}
|
|
|
|
//查询所有分组数量
|
|
int FaceDbMgr::QueryAllGroupSize()
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_SIZE, strlen(FS_DB_QUERY_GROUP_SIZE), &pstmt, 0);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_step(pstmt);
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
if (ret == SQLITE_DONE)
|
|
{
|
|
return DB_ERR_NO_DATA;
|
|
}
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
return sqlite3_column_int(pstmt, 0);
|
|
}
|
|
|
|
//通过组名字查询组ID
|
|
int FaceDbMgr::QueryGroupIdByName(std::string groupName)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_ID_BY_NAME, strlen(FS_DB_QUERY_GROUP_ID_BY_NAME), &pstmt, 0);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_bind_text(pstmt, 1, groupName.c_str(), groupName.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
ret = sqlite3_step(pstmt);
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
if (ret != SQLITE_ROW)
|
|
{
|
|
if (ret == SQLITE_DONE)
|
|
{
|
|
return DB_ERR_NO_DATA;
|
|
}
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
|
|
int group_id = sqlite3_column_int(pstmt, 0);
|
|
return group_id;
|
|
}
|
|
|
|
int FaceDbMgr::QueryGroupByName(std::string groupName, std::vector<DB_GROUP_OBJ>& objs)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_BY_NAME, strlen(FS_DB_QUERY_GROUP_BY_NAME), &pstmt, 0);
|
|
AutoDeleteStmt ads(pstmt);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_bind_text(pstmt, 1, groupName.c_str(), groupName.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
while (sqlite3_step(pstmt) == SQLITE_ROW)
|
|
{
|
|
DB_GROUP_OBJ obj;
|
|
obj.group_id = sqlite3_column_int(pstmt, 0);
|
|
obj.group_name = std::string((const char*)sqlite3_column_text(pstmt, 1), sqlite3_column_bytes(pstmt, 1));
|
|
obj.remarks = std::string((const char*)sqlite3_column_text(pstmt, 2), sqlite3_column_bytes(pstmt, 2));
|
|
obj.remarks = std::string((const char*)sqlite3_column_text(pstmt, 3), sqlite3_column_bytes(pstmt, 3));
|
|
objs.push_back(obj);
|
|
}
|
|
return objs.size();
|
|
}
|
|
|
|
int FaceDbMgr::QueryGroupByID(int group_id, std::vector<DB_GROUP_OBJ>& objs)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_GROUP_BY_NAME, strlen(FS_DB_QUERY_GROUP_BY_NAME), &pstmt, 0);
|
|
AutoDeleteStmt ads(pstmt);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
ret = sqlite3_bind_int(pstmt, 1, group_id);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
while (sqlite3_step(pstmt) == SQLITE_ROW)
|
|
{
|
|
DB_GROUP_OBJ obj;
|
|
obj.group_id = sqlite3_column_int(pstmt, 0);
|
|
obj.group_name = std::string((const char*)sqlite3_column_text(pstmt, 1), sqlite3_column_bytes(pstmt, 1));
|
|
obj.remarks = std::string((const char*)sqlite3_column_text(pstmt, 2), sqlite3_column_bytes(pstmt, 2));
|
|
obj.remarks = std::string((const char*)sqlite3_column_text(pstmt, 3), sqlite3_column_bytes(pstmt, 3));
|
|
objs.push_back(obj);
|
|
}
|
|
return objs.size();
|
|
}
|
|
|
|
|
|
/* 查询所有的组数据 */
|
|
DB_ERR_CODE FaceDbMgr::QueryGroupDatas(std::vector<DB_GROUP_OBJ>& objs)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
sqlite3_stmt * stat = NULL;
|
|
int res = sqlite3_prepare(m_db, FS_DB_QUERY_GROUP_DATA, -1, &stat, 0);
|
|
if (res != SQLITE_OK) return DB_ERR_SQL;
|
|
AutoDeleteStmt ads(stat);
|
|
|
|
while (sqlite3_step(stat) == SQLITE_ROW)
|
|
{
|
|
DB_GROUP_OBJ obj;
|
|
obj.group_id = sqlite3_column_int(stat, 0);
|
|
obj.group_name = std::string((const char*)sqlite3_column_text(stat, 1), sqlite3_column_bytes(stat,1));
|
|
obj.remarks = std::string((const char*)sqlite3_column_text(stat, 2), sqlite3_column_bytes(stat, 2));
|
|
obj.create_time = std::string((const char*)sqlite3_column_text(stat, 3), sqlite3_column_bytes(stat, 3));
|
|
objs.push_back(obj);
|
|
}
|
|
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
/*根据组ID查询人脸数据*/
|
|
int FaceDbMgr::QueryFeatrueByGroup(DB_GROUP_OBJ& group, std::vector<DB_FACE_OBJ>& face_db)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
|
|
sqlite3_stmt * stat = NULL;
|
|
int res = sqlite3_prepare(m_db, FS_DB_QUERY_FEATURES_INFO_BY_GROPU, -1, &stat, 0);
|
|
AutoDeleteStmt ads(stat);
|
|
if (res != SQLITE_OK) return DB_ERR_SQL;
|
|
res = sqlite3_bind_int(stat, 1, group.group_id);
|
|
if (res != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
while (sqlite3_step(stat) == SQLITE_ROW)
|
|
{
|
|
DB_FACE_OBJ obj;
|
|
const void* pFeatureBytes = sqlite3_column_blob(stat, 1);
|
|
int featureLen = sqlite3_column_bytes(stat, 1);
|
|
if (featureLen != MOBILE_FACE_FEATURE_BYTE_LEN)
|
|
{
|
|
std::cout << "feature length error..." << std::endl;
|
|
continue;
|
|
}
|
|
memcpy_s(obj.byteFeature, featureLen, pFeatureBytes, featureLen);
|
|
obj.name = std::string((const char*)sqlite3_column_text(stat, 2), sqlite3_column_bytes(stat, 2));
|
|
obj.vip_id = std::string((const char*)sqlite3_column_text(stat, 3), sqlite3_column_bytes(stat, 3));
|
|
obj.group = group;
|
|
obj.enter_time = std::string((const char*)sqlite3_column_text(stat, 6), sqlite3_column_bytes(stat, 6));
|
|
face_db.push_back(obj);
|
|
}
|
|
return face_db.size();
|
|
}
|
|
|
|
/*通过姓名查询人脸特征库*/
|
|
int FaceDbMgr::QueryFeatureByName(std::string face_name, std::string group_name, std::vector<DB_FACE_OBJ>& face_db)
|
|
{
|
|
face_db.clear();
|
|
std::vector<DB_GROUP_OBJ> group_objs;
|
|
QueryGroupByName(group_name, group_objs);
|
|
if (group_objs.size() < 1) return DB_ERR_NON_GROUP;
|
|
|
|
|
|
sqlite3_stmt * stat = NULL;
|
|
int res = sqlite3_prepare(m_db, FS_DB_QUERY_FEATURES_INFO_BY_NAME, -1, &stat, 0);
|
|
AutoDeleteStmt ads(stat);
|
|
|
|
if (res != SQLITE_OK) return DB_ERR_SQL;
|
|
res = sqlite3_bind_text(stat, 1, face_name.c_str(), face_name.length(), NULL);
|
|
if (res != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
res = sqlite3_bind_int(stat, 2, group_objs[0].group_id);
|
|
if (res != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
while (sqlite3_step(stat) == SQLITE_ROW)
|
|
{
|
|
DB_FACE_OBJ obj;
|
|
const void* pFeatureBytes = sqlite3_column_blob(stat, 1);
|
|
int featureLen = sqlite3_column_bytes(stat, 1);
|
|
if (featureLen != MOBILE_FACE_FEATURE_BYTE_LEN)
|
|
{
|
|
std::cout << "feature length error..." << std::endl;
|
|
continue;
|
|
}
|
|
memcpy_s(obj.byteFeature, featureLen, pFeatureBytes, featureLen);
|
|
obj.name = std::string((const char*)sqlite3_column_text(stat, 2), sqlite3_column_bytes(stat, 2));
|
|
obj.vip_id = std::string((const char*)sqlite3_column_text(stat, 3), sqlite3_column_bytes(stat, 3));
|
|
obj.group = group_objs[0];
|
|
obj.enter_time = std::string((const char*)sqlite3_column_text(stat, 6), sqlite3_column_bytes(stat, 6));
|
|
face_db.push_back(obj);
|
|
}
|
|
return face_db.size();
|
|
}
|
|
|
|
/*通过姓名查询人脸图片*/
|
|
//FS_DB_QUERY_IMG_BY_NAME
|
|
int FaceDbMgr::QueryImageByName(std::string face_name, int group_id, std::vector<uint8_t>& img_data)
|
|
{
|
|
if (!IsDbInit()) return DB_ERR_NO_INIT;
|
|
|
|
int ret;
|
|
sqlite3_stmt * pstmt = NULL;
|
|
ret = sqlite3_prepare_v2(m_db, FS_DB_QUERY_IMG_BY_NAME, strlen(FS_DB_QUERY_IMG_BY_NAME), &pstmt, 0);
|
|
if (ret != SQLITE_OK)
|
|
{
|
|
return DB_ERR_SQL;
|
|
}
|
|
AutoDeleteStmt ads(pstmt);//这里不清理干净会导致数据库关闭时返回错误码SQLITE_BUSY
|
|
|
|
ret = sqlite3_bind_text(pstmt, 1, face_name.c_str(), face_name.length(), NULL);
|
|
if (ret != SQLITE_OK)return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_int(pstmt, 2, group_id);
|
|
if (ret != SQLITE_OK)return DB_ERR_BIND_SQL_DATA;
|
|
|
|
ret = sqlite3_step(pstmt);
|
|
if (ret != SQLITE_ROW) return DB_ERR_SQL_EXE;
|
|
|
|
const void* tmp_data = sqlite3_column_blob(pstmt, 0);
|
|
int data_len = sqlite3_column_bytes(pstmt, 0);
|
|
|
|
img_data.resize(data_len);
|
|
memcpy_s(img_data.data(), data_len, tmp_data, data_len);
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
/*********************** FaceDB API *****************************/
|
|
|
|
std::string FaceDbMgr::GetErrInfo(DB_ERR_CODE err_code)
|
|
{
|
|
std::string err_info = m_err_info[err_code];
|
|
if (err_info.empty())
|
|
{
|
|
return "unknow error";
|
|
//return UnicodeToUtf8(L"未知错误...");
|
|
}
|
|
return err_info;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::EnterFace(const std::vector<float>& feature, std::string face_name, std::string vid, std::string group_name, std::vector<unsigned char> & imgData)
|
|
{
|
|
/*
|
|
1.判断特征长度
|
|
2.判断分组是否存在
|
|
3.判断分组数据是否存满
|
|
4.判断人脸特征是否已注册
|
|
*/
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
if (!m_bDbInit) return DB_ERR_NO_INIT;
|
|
if (feature.size() != MOBILE_FACE_FEATURE_FLOAT_LEN) return DB_ERR_FEATURE_LEN;//特征长度不对
|
|
int group_id = QueryGroupIdByName(group_name);
|
|
if (group_id < 0) return DB_ERR_NON_GROUP; //分组不存在
|
|
if (QueryGroupAllFeatureSize(group_id) >= MAX_FEATURE_FOR_GROUP) return DB_ERR_GROUP_FEATURE_FULL;
|
|
std::vector<DB_FACE_OBJ> face_objs;
|
|
if (QueryFeatureByName(face_name, group_name, face_objs) > 0)
|
|
{
|
|
return DB_ERR_NAME_FEATURE_EXIST;
|
|
}
|
|
|
|
/* 插入人脸数据 */
|
|
sqlite3_stmt * stat;
|
|
int ret = sqlite3_prepare_v2(m_db, FS_DB_INSERT_FEATURE_DATA, -1, &stat, 0);
|
|
AutoDeleteStmt ads(stat);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
ret = sqlite3_bind_blob(stat, 1, (unsigned char *)feature.data(), feature.size()*sizeof(float), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_text(stat, 2, face_name.c_str(), face_name.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_text(stat, 3, vid.c_str(), vid.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_blob(stat, 4, imgData.data(), imgData.size(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_int64(stat, 5, group_id);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_step(stat);
|
|
if (ret != SQLITE_DONE) return DB_ERR_ADD_FACE_FEATURE;
|
|
|
|
//同步到内存
|
|
if (QueryFeatureByName(face_name, group_name, face_objs) < 1)
|
|
{
|
|
return DB_ERR_ADD_FACE_FEATURE;
|
|
}
|
|
m_GroupDb[group_id].push_back(face_objs[0]);
|
|
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::FaceSearch(const std::vector<float> & feature, const std::string group_name, DB_FACE_OBJ& face_obj, std::vector<uint8_t>& img_data, float & fSimilarity, float fThreshold)
|
|
{
|
|
/*
|
|
1.查询组ID
|
|
2.在对应分组人脸库比对特征
|
|
*/
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
fSimilarity = 0.f;
|
|
//if (feature.size() != MOBILE_FACE_FEATURE_FLOAT_LEN) return 0;
|
|
auto iter = find_if(m_groups.begin(), m_groups.end(), [&group_name](const DB_GROUP_OBJ& tmp_obj) {
|
|
if (tmp_obj.group_name.compare(group_name) == 0)
|
|
{
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
|
|
if (iter == m_groups.end())
|
|
{
|
|
//没找到分组
|
|
return DB_ERR_NON_GROUP;
|
|
}
|
|
|
|
auto& face_db = m_GroupDb[iter->group_id];
|
|
if (face_db.size() == 0)
|
|
{
|
|
return DB_ERR_NO_DATA; //分组内没有人脸数据
|
|
}
|
|
|
|
std::vector<SEARCH_FACE_RESULT> results;
|
|
results.resize(face_db.size());
|
|
|
|
{
|
|
omp_set_num_threads(omp_get_num_procs() - 1);
|
|
#pragma omp parallel for
|
|
for (int i = 0; i < face_db.size(); i++)
|
|
{
|
|
results[i].score = FeatureCompare(feature.data(), (float*)face_db[i].byteFeature);
|
|
results[i].face_obj = face_db[i];
|
|
}
|
|
}
|
|
|
|
|
|
sort(results.begin(), results.end(), [&results](const SEARCH_FACE_RESULT& v1, const SEARCH_FACE_RESULT& v2) {
|
|
return v1.score > v2.score;
|
|
});
|
|
|
|
for (int j = 0; j < results.size(); j++)
|
|
{
|
|
if (results[j].score > fThreshold)
|
|
{
|
|
face_obj = results[j].face_obj;
|
|
fSimilarity = results[j].score;
|
|
QueryImageByName(face_obj.name, face_obj.group.group_id, img_data);
|
|
//FILE* fp;
|
|
//errno_t err = fopen_s(&fp,"E:/out1.jpg", "wb+");
|
|
//fwrite(img_data.data(), 1, img_data.size(), fp);
|
|
//fclose(fp);
|
|
}
|
|
break;
|
|
}
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::DeleteFaceByName(std::string face_name, std::string group_name)
|
|
{
|
|
/*
|
|
1.通过分组名查询分组ID
|
|
2.通过名字和分组ID从数据库中删除数据
|
|
3.从内存中删除数据
|
|
*/
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
if (!m_bDbInit) return DB_ERR_NO_INIT;
|
|
int group_id = QueryGroupIdByName(group_name);
|
|
if (group_id < 0) return DB_ERR_NON_GROUP; //分组不存在
|
|
|
|
sqlite3_stmt * stat;
|
|
int ret = sqlite3_prepare_v2(m_db, FS_DB_DELETE_FEATURE_BY_NAME, -1, &stat, 0);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
AutoDeleteStmt ads(stat);
|
|
|
|
ret = sqlite3_bind_text(stat, 1, face_name.c_str(), face_name.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_bind_int(stat, 2, group_id);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
ret = sqlite3_step(stat);
|
|
if (ret != SQLITE_DONE)
|
|
{//删除人脸失败
|
|
return DB_ERR_SQL_EXE;
|
|
}
|
|
|
|
//从内存中删除
|
|
m_GroupDb[group_id].erase(remove_if(m_GroupDb[group_id].begin(), m_GroupDb[group_id].end(),
|
|
[&face_name](DB_FACE_OBJ& face_obj) {
|
|
return face_obj.name.compare(face_name) == 0 ? true : false;
|
|
}), m_GroupDb[group_id].end());
|
|
|
|
|
|
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::DeleteAllFace(std::string group_name)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
if (!m_bDbInit) return DB_ERR_NO_INIT;
|
|
int group_id = QueryGroupIdByName(group_name);
|
|
if (group_id < 0) return DB_ERR_NON_GROUP; //分组不存在
|
|
|
|
sqlite3_stmt * stat;
|
|
int ret = sqlite3_prepare_v2(m_db, FS_DB_DELETE_FEATURE_BY_NAME, -1, &stat, 0);
|
|
AutoDeleteStmt ads(stat);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
ret = sqlite3_bind_int(stat, 1, group_id);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_step(stat);
|
|
if (ret != SQLITE_DONE) return DB_ERR_SQL_EXE;
|
|
|
|
//从内存中删除
|
|
m_GroupDb[group_id].clear();
|
|
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::AddGroup(std::string group_name, std::string remarks)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
if (!m_bDbInit) return DB_ERR_NO_INIT;
|
|
int group_id = QueryGroupIdByName(group_name);
|
|
if (group_id >= 0) return DB_ERR_GROUP_REPEAT;
|
|
|
|
sqlite3_stmt * stat;
|
|
int ret = sqlite3_prepare_v2(m_db, FS_DB_INSTER_GROUP_DATA, -1, &stat, 0);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
|
|
AutoDeleteStmt ads(stat);
|
|
|
|
ret = sqlite3_bind_text(stat, 1, group_name.c_str(), group_name.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
ret = sqlite3_bind_text(stat, 2, remarks.c_str(), remarks.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
|
|
ret = sqlite3_step(stat);
|
|
if (ret != SQLITE_DONE) return DB_ERR_ADD_GROUP;
|
|
|
|
std::vector<DB_GROUP_OBJ> groups;
|
|
QueryGroupByName(group_name, groups);
|
|
if (groups.size() < 1) return DB_ERR_ADD_GROUP;
|
|
m_groups.push_back(groups[0]);
|
|
return DB_ERR_OK;
|
|
}
|
|
|
|
DB_ERR_CODE FaceDbMgr::DeleteGroup(std::string group_name)
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_db_lock);
|
|
if (!m_bDbInit) return DB_ERR_NO_INIT;
|
|
int group_id = QueryGroupIdByName(group_name);
|
|
if (group_id < 0) return DB_ERR_NON_GROUP;
|
|
|
|
auto err_code = DeleteAllFace(group_name);
|
|
if (err_code != DB_ERR_OK) return err_code;
|
|
|
|
sqlite3_stmt * stat;
|
|
int ret = sqlite3_prepare_v2(m_db, FS_DB_DELETE_GROUP_BY_NAME, -1, &stat, 0);
|
|
AutoDeleteStmt ads(stat);
|
|
if (ret != SQLITE_OK) return DB_ERR_SQL;
|
|
ret = sqlite3_bind_text(stat, 1, group_name.c_str(), group_name.length(), NULL);
|
|
if (ret != SQLITE_OK) return DB_ERR_BIND_SQL_DATA;
|
|
ret = sqlite3_step(stat);
|
|
if (ret != SQLITE_DONE) return DB_ERR_ADD_GROUP;
|
|
|
|
//从内存中删除
|
|
m_groups.erase(remove_if(m_groups.begin(), m_groups.end(), [&group_name](DB_GROUP_OBJ& group_obj) {
|
|
return (group_obj.group_name.compare(group_name) == 0) ? true : false;
|
|
}));
|
|
|
|
for (auto it = m_GroupDb.begin(); it != m_GroupDb.end();)
|
|
{
|
|
if (it->first == group_id)
|
|
m_GroupDb.erase(it);
|
|
}
|
|
return DB_ERR_OK;
|
|
} |