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 分钟前
HarmonyOS鸿蒙实战应用6:随手账本——Preferences本地持久化
数据库·华为·app·鸿蒙
stuartevil24 分钟前
AI图生视频常见坑:参考图风格不一致怎么解决
人工智能·深度学习·音视频
2601_9621741725 分钟前
小试牛刀-SpringBoot集成SOL链
数据库·spring boot·后端
如何取名26 分钟前
结合实际业务进行LRU淘汰算法优化设计(数据库开发日志)
数据库·算法
HanhahnaH30 分钟前
Outbox 投递器:事务性发件箱模式详解
数据库
陈年老古董35 分钟前
OpenCV实战:文档扫描与图像风格迁移
人工智能·python·opencv·计算机视觉
新时代牛马38 分钟前
epoll 源码路径:从epoll_ctl 到ep_poll 的就绪唤醒
网络·数据库·网络协议
小蒜学长44 分钟前
基于SpringBoot + Vue的智能健身房管理系统的设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
芦柑4641 小时前
画布和3D导演台工具:短剧分镜从素材整理到空间预演的完整链路
服务器·前端·数据库
闲云野鹤在人间1 小时前
KVM虚拟化实战|CentOS‑Stream8 两种安装方式+模板制作+基础使用
linux·运维·服务器·centos