news 2026/4/26 7:37:39

RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RV1126 NO.57:ROCKX+RV1126人脸识别推流项目之读取人脸图片并把特征值保存到sqlite3数据库

一.本章节介绍

本章节将讲解如何使用rockx提取人脸图像特征值,并将其存储到sqlite3数据库中。在实际开发中,人脸特征值通常都会存入数据库,常见的选择包括sqlite3、MySQL等。(注:本项目不会深入讲解数据库知识,而是带大家完成基础的增删改查操作)。

二.rockx读取人脸特征值保存数据库大体框图

上图展示了将人脸特征和图片数据写入数据库的处理流程:

  1. 连接并读取人脸SQLite3数据库
  2. 初始化三个Rockx句柄:
    • 人脸检测句柄(face_det_handle)
    • 人脸识别句柄(face_recognize_handle)
    • 人脸关键点句柄(face_5landmarks_handle)
  3. 使用rockx_image_read读取人脸图片
  4. 通过FILE API获取图片长度和二进制数据
  5. 使用rockx_face_align进行人脸图片对齐
  6. 调用rockx_face_recognize提取人脸特征值
  7. 将人脸特征值和图片二进制数据存入SQLite3数据库

三.rockx读取人脸特征值保存数据库的代码

3.1.Connection_sqlite3DataBase连接数据库

printf("Start Connection sqlite3......................\n"); Connection_sqlite3DataBase(); printf("End Connection_sqlite3DataBase......................\n");

这里封装了一个了SQLITE3连接数据库的函数Connection_sqlite3Database,这个函数的实现如下

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.创建三个rockx句柄

// 1. 创建人脸检测句柄 ret = rockx_create(&face_det_handle, ROCKX_MODULE_FACE_DETECTION_V2, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_DETECTION error %d\n", ret); return -1; } // 2. 创建人脸5关键点句柄 ret = rockx_create(&face_5landmarks_handle, ROCKX_MODULE_FACE_LANDMARK_5, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_LANDMARK_68 error %d\n", ret); return -1; } // 3. 创建人脸特征提取句柄 ret = rockx_create(&face_recognize_handle, ROCKX_MODULE_FACE_RECOGNIZE, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_LANDMARK_68 error %d\n", ret); return -1; }

我们需要创建三个人脸处理句柄来实现完整功能:

  1. 人脸检测句柄(ROCKX_MODULE_FACE_DETECTION_V2)
  2. 人脸识别句柄(ROCKX_MODULE_FACE_RECOGNIZE)
  3. 人脸关键点检测句柄(ROCKX_MODULE_FACE_LANDMARK_5)

这些句柄都通过rockx_create函数进行初始化。

3.3.读取人脸图片

rockx_image_t input_image1; rockx_image_read(image_path, &input_image1, 1); //读取图片文件到rockx_image_t(第二个参数1表示按RGB格式读取)

上图是读取人脸的图片,这里使用的是rockx_image_read来读取人脸图片,其中input_image是需要从命令行输入的。

3.4.使用FILE读取图片的二进制数据和长度

FILE *imageFile = fopen(image_path, "rb"); // 打开名为image.jpg的图片文件(二进制模式) if (!imageFile) { printf("无法打开图片文件.\n"); return -1; } fseek(imageFile, 0L, SEEK_END); // 定位到文件尾部 long fileSize = ftell(imageFile); // 获取文件大小 rewind(imageFile); // 重新定位到文件起始位置 printf("fileSize = %ld\n", fileSize); unsigned char *buffer = new unsigned char[fileSize]; // 分配足够大小的缓冲区 size_t bytesRead = fread(buffer, sizeof(unsigned char), fileSize, imageFile); // 从文件中读取图像数据到缓冲区

3.5.使用run_face_recognize检测人脸数据并找到最精确的人脸

int run_face_recognize(const char *name, rockx_image_t *in_image, rockx_face_feature_t *out_feature, unsigned char * buffer, int buffer_size) { rockx_ret_t ret; /*************** FACE Detect ***************/ // create rockx_face_array_t for store result rockx_object_array_t face_array; memset(&face_array, 0, sizeof(rockx_object_array_t)); // detect face ret = rockx_face_detect(face_det_handle, in_image, &face_array, NULL); if (ret != ROCKX_RET_SUCCESS) { printf("rockx_face_detect error %d\n", ret); return -1; } // process result for (int i = 0; i < face_array.count; i++) { int left = face_array.object[i].box.left; int top = face_array.object[i].box.top; int right = face_array.object[i].box.right; int bottom = face_array.object[i].box.bottom; float score = face_array.object[i].score; printf("%d box=(%d %d %d %d) score=%f\n", i, left, top, right, bottom,score); } rockx_object_t *max_face = get_max_face(&face_array); if (max_face == NULL) { printf("error no face detected\n"); return -1; } // Face Align rockx_image_t out_img; memset(&out_img, 0, sizeof(rockx_image_t)); /*************** 2. 人脸对齐 ***************/ ret = rockx_face_align(face_5landmarks_handle, in_image, &(max_face->box),NULL, &out_img); if (ret != ROCKX_RET_SUCCESS) { return -1; } /*************** 3. 人脸特征提取 ***************/ rockx_face_recognize(face_recognize_handle, &out_img, out_feature); /*************** 4. 特征+图片数据入库 ***************/ insert_face_data_toDataBase(name, out_feature->feature, FEATURE_SIZE, buffer, buffer_size); // Release Aligned Image rockx_image_release(&out_img); return 0; } run_face_recognize(name, &input_image1, &out_feature1, buffer, bytesRead);
rockx_object_t *get_max_face(rockx_object_array_t *face_array) { if (face_array->count == 0) { return NULL; } rockx_object_t *max_face = NULL;//存储人脸的最大指针 int i; for (i = 0; i < face_array->count; i++) { rockx_object_t *cur_face = &(face_array->object[i]); if (max_face == NULL) { max_face = cur_face; continue; } int cur_face_box_area = (cur_face->box.right - cur_face->box.left) * (cur_face->box.bottom - cur_face->box.top); int max_face_box_area = (max_face->box.right - max_face->box.left) * (max_face->box.bottom - max_face->box.top); if (cur_face_box_area > max_face_box_area) { max_face = cur_face; } } printf("get_max_face %d\n", i - 1); return max_face; }

get_max_face方法通过遍历所有人脸数据实现功能:计算每个人脸区域面积(cur_face_box_area)并与当前最大面积(max_face_box_area)比较。当检测到更大的人脸区域时,会更新最大面积值,最终确定max_face为最精确的人脸数据。

3.6. 把人脸特征值和图片数据保存到sqlite3数据库

void insert_face_data_toDataBase(const char *name, float feature[512], int featureSize, uint8_t *image_data, int image_length) { printf("face_size = %d\n", image_length); // 1. 预编译SQL并检查返回值 int ret = sqlite3_prepare(db, "insert into face_data_table(name,face_feature,feature_size,image_data,image_size) values (?,?,?,?,?);", -1, &stmt, NULL); if (ret != SQLITE_OK) { printf("sqlite3_prepare error: %s\n", sqlite3_errmsg(db)); return; } // 2. 绑定参数(修正特征字节数) ret = sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_STATIC); // SQLITE_STATIC 等价于NULL,表示不释放 if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_blob(stmt, 2, feature, featureSize * sizeof(float), SQLITE_STATIC); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_int(stmt, 3, featureSize); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_blob(stmt, 4, image_data, image_length, SQLITE_STATIC); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_int(stmt, 5, image_length); if (ret != SQLITE_OK) goto err; // 3. 打印调试 printf("insert face feature: "); for (int i = 0; i < 50; i++) { printf("%f ", feature[i]); } printf("\n"); // 4. 执行插入并检查返回值 ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { printf("sqlite3_step error: %s\n", sqlite3_errmsg(db)); } err: // 5. 释放语句对象 sqlite3_finalize(stmt); }

3.7.测试结果

(图二)

最后一步是将人脸特征值和图片数据存入SQLite3数据库。我们使用以下SQL插入语句:

INSERT INTO face_data_table(name, face_feature, feature_size, image_data, image_size) VALUES (?, ?, ?, ?, ?);

其中face_data_table是存储人脸数据的数据表,包含以下字段:

  • name:人脸名称
  • face_feature:人脸特征值
  • feature_size:特征值长度
  • image_data:图片数据
  • image_size:图片长度

通过sqlite3_prepare函数将SQL语句编译为可执行字节码,支持查询、插入、更新和删除等操作。具体参数绑定如下:

  1. sqlite3_bind_text(stmt, 1, name, strlen(name), NULL):绑定名称
  2. sqlite3_bind_blob(stmt, 2, feature, featureSize, NULL):绑定人脸特征值
  3. sqlite3_bind_int(stmt, 3, featureSize):绑定特征值长度
  4. sqlite3_bind_blob(stmt, 4, image_data, image_length, NULL):绑定图片数据
  5. sqlite3_bind_int(stmt, 5, image_length):绑定图片长度

3.8.完整代码

/* * ./sqlite3_operation_test name image_path */ #include "rockx.h" #include "sqlite3_operation.h" #define FEATURE_SIZE 512 rockx_handle_t face_det_handle; rockx_handle_t face_5landmarks_handle; rockx_handle_t face_recognize_handle; void insert_face_data_toDataBase(const char *name, float feature[512], int featureSize, uint8_t *image_data, int image_length) { printf("face_size = %d\n", image_length); // 1. 预编译SQL并检查返回值 int ret = sqlite3_prepare(db, "insert into face_data_table(name,face_feature,feature_size,image_data,image_size) values (?,?,?,?,?);", -1, &stmt, NULL); if (ret != SQLITE_OK) { printf("sqlite3_prepare error: %s\n", sqlite3_errmsg(db)); return; } // 2. 绑定参数(修正特征字节数) ret = sqlite3_bind_text(stmt, 1, name, strlen(name), SQLITE_STATIC); // SQLITE_STATIC 等价于NULL,表示不释放 if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_blob(stmt, 2, feature, featureSize * sizeof(float), SQLITE_STATIC); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_int(stmt, 3, featureSize); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_blob(stmt, 4, image_data, image_length, SQLITE_STATIC); if (ret != SQLITE_OK) goto err; ret = sqlite3_bind_int(stmt, 5, image_length); if (ret != SQLITE_OK) goto err; // 3. 打印调试 printf("insert face feature: "); for (int i = 0; i < 50; i++) { printf("%f ", feature[i]); } printf("\n"); // 4. 执行插入并检查返回值 ret = sqlite3_step(stmt); if (ret != SQLITE_DONE) { printf("sqlite3_step error: %s\n", sqlite3_errmsg(db)); } err: // 5. 释放语句对象 sqlite3_finalize(stmt); } 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; } rockx_object_t *get_max_face(rockx_object_array_t *face_array) { if (face_array->count == 0) { return NULL; } rockx_object_t *max_face = NULL;//存储人脸的最大指针 int i; for (i = 0; i < face_array->count; i++) { rockx_object_t *cur_face = &(face_array->object[i]); if (max_face == NULL) { max_face = cur_face; continue; } int cur_face_box_area = (cur_face->box.right - cur_face->box.left) * (cur_face->box.bottom - cur_face->box.top); int max_face_box_area = (max_face->box.right - max_face->box.left) * (max_face->box.bottom - max_face->box.top); if (cur_face_box_area > max_face_box_area) { max_face = cur_face; } } printf("get_max_face %d\n", i - 1); return max_face; } int run_face_recognize(const char *name, rockx_image_t *in_image, rockx_face_feature_t *out_feature, unsigned char * buffer, int buffer_size) { rockx_ret_t ret; /*************** FACE Detect ***************/ // create rockx_face_array_t for store result rockx_object_array_t face_array; memset(&face_array, 0, sizeof(rockx_object_array_t)); // detect face ret = rockx_face_detect(face_det_handle, in_image, &face_array, NULL); if (ret != ROCKX_RET_SUCCESS) { printf("rockx_face_detect error %d\n", ret); return -1; } // process result for (int i = 0; i < face_array.count; i++) { int left = face_array.object[i].box.left; int top = face_array.object[i].box.top; int right = face_array.object[i].box.right; int bottom = face_array.object[i].box.bottom; float score = face_array.object[i].score; printf("%d box=(%d %d %d %d) score=%f\n", i, left, top, right, bottom,score); } rockx_object_t *max_face = get_max_face(&face_array); if (max_face == NULL) { printf("error no face detected\n"); return -1; } // Face Align rockx_image_t out_img; memset(&out_img, 0, sizeof(rockx_image_t)); /*************** 2. 人脸对齐 ***************/ ret = rockx_face_align(face_5landmarks_handle, in_image, &(max_face->box),NULL, &out_img); if (ret != ROCKX_RET_SUCCESS) { return -1; } /*************** 3. 人脸特征提取 ***************/ rockx_face_recognize(face_recognize_handle, &out_img, out_feature); /*************** 4. 特征+图片数据入库 ***************/ insert_face_data_toDataBase(name, out_feature->feature, FEATURE_SIZE, buffer, buffer_size); // Release Aligned Image rockx_image_release(&out_img); return 0; } int main(int argc, char *argv[]) { rockx_ret_t ret; printf("----------------- main init ---------------------\n"); #if 1 if (argc != 3) { printf("Usage: Insert DataBase ./sqlite3_operation_test name image_path\n"); return -1; } printf("Start Connection sqlite3......................\n"); Connection_sqlite3DataBase(); printf("End Connection_sqlite3DataBase......................\n"); // 创建rockx配置对象 rockx_config_t *config = rockx_create_config(); // 设置rockx模型数据路径(需提前放置模型文件) rockx_add_config(config, ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data/"); /*************** Creat Handle ***************/ // create a face detection handle // 1. 创建人脸检测句柄 ret = rockx_create(&face_det_handle, ROCKX_MODULE_FACE_DETECTION_V2, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_DETECTION error %d\n", ret); return -1; } // 2. 创建人脸5关键点句柄 ret = rockx_create(&face_5landmarks_handle, ROCKX_MODULE_FACE_LANDMARK_5, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_LANDMARK_68 error %d\n", ret); return -1; } // 3. 创建人脸特征提取句柄 ret = rockx_create(&face_recognize_handle, ROCKX_MODULE_FACE_RECOGNIZE, config, 0); if (ret != ROCKX_RET_SUCCESS) { printf("init rockx module ROCKX_MODULE_FACE_LANDMARK_68 error %d\n", ret); return -1; } const char *name = argv[1]; const char *image_path = argv[2]; rockx_face_feature_t out_feature1; rockx_image_t input_image1; rockx_image_read(image_path, &input_image1, 1); //读取图片文件到rockx_image_t(第二个参数1表示按RGB格式读取) FILE *imageFile = fopen(image_path, "rb"); // 打开名为image.jpg的图片文件(二进制模式) if (!imageFile) { printf("无法打开图片文件.\n"); return -1; } fseek(imageFile, 0L, SEEK_END); // 定位到文件尾部 long fileSize = ftell(imageFile); // 获取文件大小 rewind(imageFile); // 重新定位到文件起始位置 printf("fileSize = %ld\n", fileSize); unsigned char *buffer = new unsigned char[fileSize]; // 分配足够大小的缓冲区 size_t bytesRead = fread(buffer, sizeof(unsigned char), fileSize, imageFile); // 从文件中读取图像数据到缓冲区 /*************** 执行人脸处理+入库 ***************/ run_face_recognize(name, &input_image1, &out_feature1, buffer, bytesRead); #endif return 0; }

四.在板子上查询数据库的人脸数据

4.1. 打开sqlite3数据库

使用sqlite3 face.db打开人脸数据库

4.2. 查询人脸的数据

通过SQL查询语句检索人脸识别数据,执行命令为:

SELECT * FROM face_data_table

查询结果如上方截图所示。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 21:06:40

多智能体测试自动化:AI驱动的企业级测试平台构建全攻略

本文详细介绍了如何构建基于多智能体协作(MAS)的AI驱动测试平台&#xff0c;通过模块化、并行化的智能体架构&#xff0c;解决了传统测试工具割裂、流程断层的问题。文章从MAS基础架构、工作流设计、服务封装、企业部署到DevOps集成&#xff0c;全方位阐述了实现从"工具驱…

作者头像 李华
网站建设 2026/4/20 13:42:20

3 年换 4 套管理系统,企业什么时候才能醒悟?

如果你是连锁企业的运营总监、集团公司的IT负责人&#xff0c;或是SaaS服务厂商的产品经理&#xff0c;这些“系统管理噩梦”大概率正在消耗团队的精力与企业的利润。 在数字化转型的赛道上&#xff0c;很多企业陷入“换系统—补漏洞—再换系统”的恶性循环&#xff0c;却忽略…

作者头像 李华
网站建设 2026/4/18 23:59:23

场效应管通电短路

场效应管通电短路是指MOS管在上电瞬间或工作过程中&#xff0c;漏极&#xff08;D&#xff09;与源极&#xff08;S&#xff09;之间失去阻断能力&#xff0c;呈现极低电阻&#xff08;通常<1Ω&#xff09;的失效状态。这是电力电子系统中最严重的故障之一&#xff0c;可能…

作者头像 李华
网站建设 2026/4/26 4:04:40

19、Samba使用指南:名称解析与额外功能配置

Samba使用指南:名称解析与额外功能配置 1. Samba名称解析概述 在NetBIOS名称服务器(NBNS)出现之前,名称解析完全依靠广播。若要获取某台机器的地址,只需在网络中广播其名称,理论上该机器会作出回应。例如,若要查找名为“fred”的机器,仍可通过广播查询来确定其是否存在…

作者头像 李华
网站建设 2026/4/18 4:51:51

无代码解决方案:解锁数字化转型的普惠路径

在数字化转型进入深水区的当下&#xff0c;企业对数字化工具的核心诉求已从“功能完备”转向“快速适配、低成本落地、业务主导”。传统代码开发模式因周期长、成本高、技术门槛高的弊端&#xff0c;难以满足中小企业和业务部门的灵活需求。无代码解决方案以可视化配置、拖拽式…

作者头像 李华
网站建设 2026/4/18 1:20:53

YMatrix 高可用详解:3 种镜像策略在节点宕机时表现有何不同?

前言 不同镜像策略如何对集群高可用表现产生影响&#xff1f; 在数据库中&#xff0c; 高可用性是保障业务连续性的核心——一旦 Primary 节点故障&#xff0c;能否快速切换到备份节点&#xff0c;直接决定了业务的“抗风险能力”。YMatrix 的 Mirror 机制正是实现这一目标的…

作者头像 李华