建立文件夹
face/samplecode/ASFTestDemo/build$ mkdir ../jpg_pre_extra
face/samplecode/ASFTestDemo/build$ mkdir ../jpg_extred
face/samplecode/ASFTestDemo/build$ mkdir ../jpg_err_extred
在int database_init(void)中添加建表程序
表包含几项:
id 整形,主键,自增
feature blob形,用来保存人脸特征数据
name 字符,256长,非空,保存姓名
idcn 字符,18长,非空,唯一,用于保存身份证号
//建表,保存人脸特征数据
//id int 主键 自增| feature blob| name varchar(255)| idcn varchar(18) 唯一
snprintf(cmd, sizeof(cmd),
"CREATE TABLE IF NOT EXISTS %s (id INTEGER PRIMARY KEY AUTOINCREMENT, feature blob, name varchar(256) NOT NULL, idcn varchar(18) NOT NULL UNIQUE)",
DATABASE_TABLE);
if (sqlite3_exec(g_db, cmd, 0, 0, &err) != SQLITE_OK) {
sqlite3_close(g_db);
g_db = NULL;
printf("%s create table %s failed!\n", __func__, DATABASE_TABLE);
return -1;
}
抽取人脸特征的程序
//抽取底库的人脸特征
//int width 输入数据的宽度
//int height 输入数据的高度
//MUInt8* rgb888_data 输入数据
//ASF_FaceFeature *pout_feature 输出特征的地址
int arcsorft_face_process(int width, int height, MUInt8* rgb888_data, ASF_FaceFeature *pout_feature) {
pthread_mutex_lock(&g_mutex);
MRESULT res = MOK;
//图像空间变换
ASVLOFFSCREEN offscreen = { 0 };
ColorSpaceConversion(width, height, ASVL_PAF_RGB24_B8G8R8, rgb888_data, offscreen);
ASF_MultiFaceInfo detectedFaces = { 0 };
ASF_SingleFaceInfo SingleDetectedFaces = { 0 };
//人脸检测
res = ASFDetectFacesEx(handle, &offscreen, &detectedFaces);
//人脸检测错误
if (res != MOK) {
printf("ASFDetectFaces fail: %ld\n", res);
//getchar();
pthread_mutex_unlock(&g_mutex);
return res;
}
//照片中存在多个人脸
else if(detectedFaces.faceNum != 1) {
printf("faceNum: %d, not 1\n", detectedFaces.faceNum);
//getchar();
pthread_mutex_unlock(&g_mutex);
return -1;
}
//单个人脸抽取人脸特征
else
{
SingleDetectedFaces.faceRect.left = detectedFaces.faceRect[0].left;
SingleDetectedFaces.faceRect.top = detectedFaces.faceRect[0].top;
SingleDetectedFaces.faceRect.right = detectedFaces.faceRect[0].right;
SingleDetectedFaces.faceRect.bottom = detectedFaces.faceRect[0].bottom;
SingleDetectedFaces.faceOrient = detectedFaces.faceOrient[0];
printf("face num: %d, left: %d, top: %d, right: %d, bottom: %d, faceOrient: %d \n", detectedFaces.faceNum,
detectedFaces.faceRect[0].left,
detectedFaces.faceRect[0].top,
detectedFaces.faceRect[0].right,
detectedFaces.faceRect[0].bottom,
detectedFaces.faceOrient[0]);
// 单人脸特征提取
res = ASFFaceFeatureExtractEx(handle, &offscreen, &SingleDetectedFaces, pout_feature);
if (res != MOK)
{
printf("ASFFaceFeatureExtractEx fail: %ld\n", res);
}
else
{
//printf("featureSize: %d\n", pout_feature->featureSize);
}
pthread_mutex_unlock(&g_mutex);
return res;
}
}
插入人脸数据的程序
//人脸特征的增,改
//data feature数据
//size feature数据 长度
int database_insert(void *data, size_t size, const char *name, size_t n_size, const char *idcn, bool sync_flag)
{
char cmd[256];
int ret = -1;
sqlite3_stmt *stat = NULL;
if (n_size > NAME_LEN) {
printf("%s n_size error\n", __func__);
return -1;
}
pthread_mutex_lock(&g_mutex);
//id, feature, name, icdn
snprintf(cmd, sizeof(cmd), "REPLACE INTO %s (feature, name, idcn) VALUES(?, '%s', '%s');", DATABASE_TABLE_FEATURE, name, idcn);
printf("%s\n", cmd);
ret = sqlite3_prepare(g_db, cmd, -1, &stat, 0);
if (ret != SQLITE_OK) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_prepare fail \n");
return ret;
}
ret = sqlite3_exec(g_db, "begin transaction", NULL, NULL, NULL);
if (ret != SQLITE_OK) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_exec fail \n");
return ret;
}
ret = sqlite3_bind_blob(stat, 1, data, size, NULL);
if (ret != SQLITE_OK) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_bind_blob fail \n");
return ret;
}
ret = sqlite3_step(stat);
if (ret != SQLITE_DONE) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_step fail \n");
return ret;
}
ret = sqlite3_finalize(stat);
if (ret != SQLITE_OK) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_finalize fail \n");
return ret;
}
ret = sqlite3_exec(g_db, "commit transaction", NULL, NULL, NULL);
if (ret != SQLITE_OK) {
pthread_mutex_unlock(&g_mutex);
printf("sqlite3_exec fail \n");
return ret;
}
if (sync_flag) {
sync();
//database_bak();
}
pthread_mutex_unlock(&g_mutex);
printf("insert data ok \n");
return ret;
}
主程序调用
int main()
{
int ret = -1;
unsigned char* pjpg_data = NULL;
unsigned char* pbgr_data = (unsigned char*)malloc(1);
int width, height;
//初始化数据库
ret = database_init();
if(ret != 0)
{
printf("database_init false! \n");
return -1;
}
//读取APPID, SDKKEY
char* appid = (char*)malloc(1);
char* sdkkey = (char*)malloc(1);
int id_size, key_size;
get_data_by_name((char*)"text_APPID", NULL, &appid, NULL, NULL, &id_size);
get_data_by_name((char*)"text_SDKKEY", NULL, &sdkkey, NULL, NULL, &key_size);
arcsorft_init(appid, sdkkey);
//读照片
//等待抽取特征的头像
const char* jpg_pre_extra_path = "../jpg_pre_extra";
//已经抽取特征的头像
const char* jpg_extred_path = "../jpg_extred";
//有错误的头像
const char* jpg_err_extred_path = "../jpg_err_extred";
//打开文件夹
DIR* dirp = opendir(jpg_pre_extra_path);
struct dirent* dp;
//历遍里面每一个文件
int i = 1;
while ((dp = readdir(dirp)) != nullptr) {
if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
char jpg_name[300];
char new_name[300] = {0};
sprintf(jpg_name, "%s/%s", jpg_pre_extra_path, dp->d_name);
//打开文件
FILE* fpjpg = fopen(jpg_name, "rb");
//查文件的长度
fseek(fpjpg, 0, SEEK_END);
long file_length = ftell(fpjpg);
fseek(fpjpg, 0, SEEK_SET);
//分配内存
pjpg_data = (unsigned char*)malloc(file_length);
//读取数据
fread(pjpg_data, 1, file_length, fpjpg); //jpeg文件数据
//关闭文件
fclose(fpjpg);
//把jpg图片解码成bgr数据
jpg2bgr(pjpg_data, file_length, &pbgr_data, &width, &height);
printf("pic %s width: %d, height: %d \n", jpg_name, width, height);
//抽取人脸特征
ASF_FaceFeature feature;
ret = arcsorft_face_process(width, height, pbgr_data, &feature);
//有错误的话把图片放到 ../jpg_err_extred 文件夹
if(ret != 0) {
//移动文件
sprintf(new_name, "%s/%s", jpg_err_extred_path, dp->d_name);
rename(jpg_name, new_name);
continue;
}
char workerName[255] = {0};
char idNumber[19] = {0};
memcpy(workerName, dp->d_name, 18);
memcpy(idNumber, dp->d_name, 18);
printf("workerName:%s, idNumber: %s\n", workerName, idNumber);
//把人员插入数据库
ret = database_insert(feature.feature, feature.featureSize, workerName, 0, idNumber, 1);
if(ret == 0) {
//移动文件
//成功的话把文件移到../jpg_extred
sprintf(new_name, "%s/%s", jpg_extred_path, dp->d_name);
rename(jpg_name, new_name);
}
else {
//移动文件
//有错误的话把图片放到 ../jpg_err_extred 文件夹
sprintf(new_name, "%s/%s", jpg_err_extred_path, dp->d_name);
rename(jpg_name, new_name);
}
}
}
//释放内存
free(pbgr_data);
//关闭文件夹
closedir(dirp);
getchar();
arcsorft_deinit ();
return 0;
}
编译运行
在…/jpg_pre_extra 放一张头像
命名为 200000000000000002.jpg
make 编译后运行
face/samplecode/ASFTestDemo/build$ make
Scanning dependencies of target arcsoft_face_engine_test
[ 20%] Building CXX object CMakeFiles/arcsoft_face_engine_test.dir/samplecode.cpp.o
[ 40%] Linking CXX executable arcsoft_face_engine_test
[100%] Built target arcsoft_face_engine_test
face/samplecode/ASFTestDemo/build$ ./arcsoft_face_engine_test
************* ArcFace SDK Info *****************
startTime: 2024-09-09 00:00:00
endTime: 2025-09-09 00:00:00
Version:3.0.12402010101.3
BuildDate:07/29/2020
CopyRight:Copyright 2020 ArcSoft Corporation Limited. All rights reserved.
************* Face Recognition *****************
ASFInitEngine sucess: 0
pic ../jpg_pre_extra/200000000000000002.jpg width: 392, height: 567
face num: 1, left: 67, top: 107, width: 248, height: 248, faceOrient: 1
workerName:200000000000000002, idNumber: 200000000000000002
REPLACE INTO face_feature (feature, name, idcn) VALUES(?, '200000000000000002', '200000000000000002');
insert data ok
ASFUninitEngine sucess: 0
数据库中可以见到成功插入的项