RV1126 NO.58:ROCKX+RV1126人脸识别推流项目之读取人脸数据库并保存到map

一.本章节介绍

本章节将介绍如何通过查询人脸数据库表格,将数据存储到map容器中。map容器基于内存操作,能够实现高效快速的数据查询。在本项目中,map主要发挥快速查询功能:其中key存储人脸结构体(People),value则存储具体的人脸数据(rockx_face_feature_t)。

二.读取数据库保存到map流程框图

该流程图展示了从数据库读取数据并加载到Map容器的完整流程,包含三个关键步骤:

  1. 建立连接:初始化并连接SQLite3数据库
  2. 执行查询:通过SELECT语句获取人脸表格数据
  3. 数据映射:将查询结果循环存入Map容器

三.读取数据库保存到map的代码截图

cpp 复制代码
void init_face_data()
{
    /*刚开始交叉编译sqlite3_operation_test.cpp文件到板子中运行,把人脸信息及特征值保存到sqlite数据库中,再调用QueryPeopleData()
    函数从中一一取出人脸信息(比如姓名,图片信息以及大小),最后返回组装好的容器*/
    Connection_sqlite3DataBase();
    int task_id = generate_unique_task_id();
    S_THREAD_MAP thread_map;
    //map<string, rockx_face_feature_t> maps = QueryFaceFeature();
    map<People, rockx_face_feature_t> maps = QueryPeopleData();
    //thread_map.thread_map = maps;
    thread_map.thread_people_map = maps;
    set_thread_map(task_id, &thread_map);
    printf("本次人脸数据绑定的 task_id:%d\n", task_id);
}

init_face_data 是一个用于读取数据库数据并存入 map 容器的自定义函数,主要包含三个关键步骤:首先通过 Connection_sqlite3DataBase 加载数据库,接着使用 QueryPeopleData 查询数据库信息并存入 Map 容器,最后通过 set_thread_map 将 Map 数据存储到全局变量中。

3.1. 加载并连接sqlite3数据库

cpp 复制代码
int Connection_sqlite3DataBase()
{
  rc = sqlite3_open("/userdata/face.db", &db);
  if (rc != SQLITE_OK)
  {
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }
  else
  {
    printf("You have opened a sqlite3 database named bind.db successfully!\nCongratulation! Have fun!\n");
  }
  return 0;
}

这个函数直接调用了sqlite3的api sqlite3_open来初始化人脸数据库,若返回值不等于SQLITE_OK则初始化数据库失败,否则就初始化成功。

3.2. 通过select查询人脸表格的数据

cpp 复制代码
rockx_face_feature_t rockx_face_feature = {0, 0};
  // 定义返回值:map容器,键=People(人名+图片),值=人脸特征
  map<People, rockx_face_feature_t> people_map;
  sqlite3_stmt *stmt = nullptr;
  static int i=0;
  char buf_sql[256];
  //char *sql = "select name, feature_size, face_feature, image_size, image_data from face_data_table";
  sprintf(buf_sql,"select name, feature_size, face_feature, image_size, image_data from face_data_table_%d",i++);


  int id = 0, len = 0;
  char *name;
  int feature_size;
  int feature_bytes;
  int image_size;
  vector<char> images;
  People first_people;

该SQL查询语句用于从人脸数据表face_data_table中检索数据,查询字段包括:

  • name(姓名)
  • feature_size(特征值长度)
  • face_feature(人脸特征数据)
  • image_size(图片尺寸)
  • image_data(图片数据)

查询执行时使用了sqlite3_prepare方法进行SQL语句预处理。

3.3. 读取查询的结果并循环插入map容器

cpp 复制代码
int ret = sqlite3_prepare(db, buf_sql, strlen(sql), &stmt, 0);
  if (ret == SQLITE_OK)
  {
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
      name = (char *)sqlite3_column_text(stmt, 0);
      printf("name = %s\n", name);
      feature_size = sqlite3_column_int(stmt, 1);
      printf("feature_size = %d\n", feature_size);

      feature_bytes = feature * sizeof(float);
      const void *feature = sqlite3_column_blob(stmt, 2);
      memset(rockx_face_feature.feature, 0, feature_bytes);
      memcpy(rockx_face_feature.feature, feature, feature_bytes);
      rockx_face_feature.len = feature_bytes;

      image_size = sqlite3_column_int(stmt, 3);
      printf("image_size = %d\n", image_size);

      const char * image_data = (const char *)sqlite3_column_blob(stmt, 4);
      for (int i = 0; i < image_size; i++)
      {
         images.push_back(image_data[i]);
         images.clear(); // 新增:清空上一行的图片数据
      }

      first_people.people_name = string(name);
      first_people.images = images;

      string str(name);
      //people_map.insert(pair<const People, rockx_face_feature_t>(first_people, rockx_face_feature));
      people_map.insert(make_pair(first_people, rockx_face_feature));
      //people_map.insert(first_people, rockx_face_feature);
    }
  }
  //返回组装好的map容器
  return people_map;

这段代码实现了从SQLite3数据库读取数据并循环插入到map容器的功能。核心是通过sqlite3_step函数获取SELECT查询结果:当返回值为SQLITE_ROW时,表示当前行包含有效数据。

各列数据的读取方式如下:

  • sqlite3_column_text(stmt, 0):获取SELECT语句第一个字段(索引0),对应name字段(字符串类型)
  • sqlite3_column_int(stmt, 1):获取第二个字段(索引1),对应feature_size字段(整型)
  • sqlite3_column_blob(stmt, 2):获取第三个字段(索引2),对应face_feature字段(二进制类型)
  • sqlite3_column_int(stmt, 3):获取第四个字段(索引3),对应image_size字段(整型)
  • sqlite3_column_blob(stmt, 4):获取第五个字段(索引4),对应image_data字段(二进制类型)

完成数据读取后,将获取的所有字段值插入到map容器中。

四.完整代码

cpp 复制代码
map<People, rockx_face_feature_t> QueryPeopleData()
{
  rockx_face_feature_t rockx_face_feature = {0, 0};
  // 定义返回值:map容器,键=People(人名+图片),值=人脸特征
  map<People, rockx_face_feature_t> people_map;
  sqlite3_stmt *stmt = nullptr;
  static int i=0;
  char buf_sql[256];
  //char *sql = "select name, feature_size, face_feature, image_size, image_data from face_data_table";
  sprintf(buf_sql,"select name, feature_size, face_feature, image_size, image_data from face_data_table_%d",i++);


  int id = 0, len = 0;
  char *name;
  int feature_size;
  int feature_bytes;
  int image_size;
  vector<char> images;
  People first_people;

  int ret = sqlite3_prepare(db, buf_sql, strlen(sql), &stmt, 0);
  if (ret == SQLITE_OK)
  {
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
      name = (char *)sqlite3_column_text(stmt, 0);
      printf("name = %s\n", name);
      feature_size = sqlite3_column_int(stmt, 1);
      printf("feature_size = %d\n", feature_size);

      feature_bytes = feature * sizeof(float);
      const void *feature = sqlite3_column_blob(stmt, 2);
      memset(rockx_face_feature.feature, 0, feature_bytes);
      memcpy(rockx_face_feature.feature, feature, feature_bytes);
      rockx_face_feature.len = feature_bytes;

      image_size = sqlite3_column_int(stmt, 3);
      printf("image_size = %d\n", image_size);

      const char * image_data = (const char *)sqlite3_column_blob(stmt, 4);
      for (int i = 0; i < image_size; i++)
      {
         images.push_back(image_data[i]);
         images.clear(); // 新增:清空上一行的图片数据
      }

      first_people.people_name = string(name);
      first_people.images = images;

      string str(name);
      //people_map.insert(pair<const People, rockx_face_feature_t>(first_people, rockx_face_feature));
      people_map.insert(make_pair(first_people, rockx_face_feature));
      //people_map.insert(first_people, rockx_face_feature);
    }
  }
  //返回组装好的map容器
  return people_map;
}


int Connection_sqlite3DataBase()
{
  rc = sqlite3_open("/userdata/face.db", &db);
  if (rc != SQLITE_OK)
  {
    fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
    sqlite3_close(db);
    exit(1);
  }
  else
  {
    printf("You have opened a sqlite3 database named bind.db successfully!\nCongratulation! Have fun!\n");
  }
  return 0;
}


int generate_unique_task_id() {
    return g_next_task_id++;  // 每次调用自增,返回唯一ID
}

void init_face_data()
{
    /*刚开始交叉编译sqlite3_operation_test.cpp文件到板子中运行,把人脸信息及特征值保存到sqlite数据库中,再调用QueryPeopleData()
    函数从中一一取出人脸信息(比如姓名,图片信息以及大小),最后返回组装好的容器*/
    Connection_sqlite3DataBase();
    int task_id = generate_unique_task_id();
    S_THREAD_MAP thread_map;
    //map<string, rockx_face_feature_t> maps = QueryFaceFeature();
    map<People, rockx_face_feature_t> maps = QueryPeopleData();
    //thread_map.thread_map = maps;
    thread_map.thread_people_map = maps;
    set_thread_map(task_id, &thread_map);
    printf("本次人脸数据绑定的 task_id:%d\n", task_id);
}
相关推荐
羑悻的小杀马特3 小时前
【Linux篇章】再续传输层协议TCP:用技术隐喻重构网络世界的底层逻辑,用算法演绎‘网络因果律’的终极推演(通俗理解TCP协议,这一篇就够了)!
linux·网络·后端·tcp/ip·tcp协议
枫叶丹43 小时前
【Qt开发】Qt事件(一)
c语言·开发语言·数据库·c++·qt·microsoft
博语小屋3 小时前
Socket 编程TCP:多线程远程命令执行
linux·网络·c++·网络协议·tcp/ip
AIOps打工人3 小时前
Grafana Query MCP:基于FastAPI的Grafana查询转换与分页服务
运维·数据库·python·ai·grafana·fastapi·devops
小鸡吃米…3 小时前
Python - 数据库访问
数据库·python
列逍3 小时前
Linux 动静态库深度解析:原理、制作与实战
linux·运维·服务器·动态库·静态库
云和数据.ChenGuang3 小时前
欧拉(openEuler)和CentOS
linux·运维·centos
qq_589568103 小时前
centos打开文件之后怎么退出 ,使用linux命令
linux·运维·centos
linuxxx1103 小时前
Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64
linux·运维·centos