ROCKX——读取单张图片并检测图片内人脸的矩形

整体逻辑非常简洁,核心分为「初始化 → 读图封装 → 推理检测 → 解析结果 → 释放资源」五步,不用对接 RKMedia 视频链路,适合验证 RockX 环境、快速调试算法效果,也是视频流检测的基础单元。

一、整体流程总览

1. 拿图片路径 先存下你运行程序时输的图片文件名,比如你输./rockx_face_detection test.jpg,它就把test.jpg记下来。 但这里没做任何判断,要是你忘输图片名,程序直接就崩了,写得比较糙。

2. 初始化 AI 模型 先造一个 "配置容器",往里面填模型路径 ------ 告诉 AI:模型文件都在/userdata/rockx_data/这个文件夹里,你去这找人脸检测的模型。 然后调用rockx_create,把人脸检测模型加载到板子的 NPU(专门跑 AI 的硬件)里,准备干活。 要是加载失败(比如路径错了、模型文件丢了),就打印一句失败,直接退出。

3. 读取图片 用 RockX 自带的rockx_image_read把图片读进内存,最后那个参数1是把图片转成 RGB 格式。 这个自带的读图函数特别 "娇气",带透明通道的 png、编码特殊的 jpg,它经常读不出来,甚至直接让程序崩掉 ------ 这也是你之前换张图就段错误的核心原因。

4. AI 执行人脸检测 先准备一个 "结果筐",然后调用rockx_face_detect,把图片喂给 AI,让 NPU 跑算法算一遍。算出来的所有人脸坐标、置信度,都存到这个结果筐里。 计算失败就报错退出。

5. 在图上画人脸框 先把图片数据包装成 OpenCV 能认的格式,方便画图。这里是直接复用同一块内存,不额外拷贝数据,省时间,嵌入式里常用这种写法。 然后循环遍历每一张检测到的人脸,算出框的位置和大小,用 OpenCV 在图上画一个青色的矩形框。

6. 保存图片 + 收尾 把画好框的图片存成output_face_det.jpg,然后卸载 AI 模型、释放 NPU 资源,程序结束。

二、完整可运行代码

下面是可以直接编译运行的完整单图人脸检测代码,适配 RV1126 平台:

复制代码
#include <stdio.h>
#include <memory.h>
#include <sys/time.h>
#include "rknn_rockx_include/rockx_type.h"
#include "rknn_rockx_include/utils/rockx_config_util.h"
#include "rknn_rockx_include/utils/rockx_image_util.h"
#include "rockx.h"
#include <opencv2/opencv.hpp>
#include <opencv2/imgcodecs.hpp>

using namespace cv;

int main(int argc, char **argv)
{
    const char * img_path = argv[1];
    rockx_config_t * face_detect_config = rockx_create_config();
    rockx_add_config(face_detect_config,ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data/");

    rockx_handle_t face_detect_handle;
    rockx_ret_t rockx_ret;

    rockx_module_t face_rockx_module = ROCKX_MODULE_FACE_DETECTION_V2;
    rockx_ret = rockx_create (&face_detect_handle, face_rockx_module,face_detect_config, 0);
    if(rockx_ret != ROCKX_RET_SUCCESS)
    {
        printf("rockx_creat failed...\n");
        return -1;
    }

    rockx_image_t face_rockx_image;
    rockx_image_read(img_path, &face_rockx_image, 1);

    rockx_object_array_t face_array;
    rockx_ret = rockx_face_detect(face_detect_handle, &face_rockx_image, &face_array,nullptr);
    if(rockx_ret != ROCKX_RET_SUCCESS)
    {
        printf("face_detect failed...\n");
        return -1;
    }

    Mat rockx_face_mat = Mat(face_rockx_image.height, face_rockx_image.width, CV_8UC3, face_rockx_image.data);
    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 w = face_array.object[i].box.right - face_array.object[i].box.left;
        int h = face_array.object[i].box.bottom - face_array.object[i].box.top;
        Rect boundingRect(left, top, w, h);
        rectangle(rockx_face_mat, boundingRect, Scalar(255,255,0), 1);
    }

    imwrite("output_face_det.jpg",rockx_face_mat);
    rockx_destroy(face_detect_handle);


    return 0;
}

2.1 初始化 rockx 人脸检测框架

复制代码
int main(int argc, char **argv)
{
    const char * img_path = argv[1];
    rockx_config_t * face_detect_config = rockx_create_config();
    rockx_add_config(face_detect_config,ROCKX_CONFIG_DATA_PATH, "/userdata/rockx_data/");

    rockx_handle_t face_detect_handle;
    rockx_ret_t rockx_ret;

    rockx_module_t face_rockx_module = ROCKX_MODULE_FACE_DETECTION_V2;
    rockx_ret = rockx_create (&face_detect_handle, face_rockx_module,face_detect_config, 0);
    if(rockx_ret != ROCKX_RET_SUCCESS)
    {
        printf("rockx_creat failed...\n");
        return -1;
    }

初始化首先要使用rockx_create_config 分配rockx_config_t结构体,并使用rockx_add_config 把对应的rockx路径配置进去,在我们的板子里面在**/userdata/rockx_data** 里面,并使用rockx_create创建rockx_handle_t句柄。

2.2 读取人脸图片

复制代码
    rockx_image_t face_rockx_image;
    rockx_image_read(img_path, &face_rockx_image, 1);

读取对应的人脸图片,在rockx里面用rockx_image_read来读取对应的人脸图片。并把人脸的特征数据传入到rockx_image_t结构体里面。

2.3 ​​​​​​​调用 rockx 的人脸检测 API 对其进行人脸检测

复制代码
    rockx_object_array_t face_array;
    rockx_ret = rockx_face_detect(face_detect_handle, &face_rockx_image, &face_array,nullptr);
    if(rockx_ret != ROCKX_RET_SUCCESS)
    {
        printf("face_detect failed...\n");
        return -1;
    }

调用rockx_face_detect 对图片进行人脸检测,这里的输入的是input_image ,这个是由rockx_image_read 读取的图片数据,输出的数据是rockx_object_array_t 后面的数据则都是通过rockx_object_array_t来处理。

2.4 ​​​​​​​循环人脸数量并使用 Opencv 进行画框

复制代码
    Mat rockx_face_mat = Mat(face_rockx_image.height, face_rockx_image.width, CV_8UC3, face_rockx_image.data);
    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 w = face_array.object[i].box.right - face_array.object[i].box.left;
        int h = face_array.object[i].box.bottom - face_array.object[i].box.top;
        Rect boundingRect(left, top, w, h);
        rectangle(rockx_face_mat, boundingRect, Scalar(255,255,0), 1);
    }

循环人脸数量,人脸数量是face_array.count。然后获取人脸的坐标属性,这里的坐标属性就是left、top、w、h,并用OPENCV把input_image转换成Mat矩阵( Mat tmp_img = Mat(input_image.height, input_image.width, CV_8UC3, input_image.data)),转换完成之后再使用rectangle把坐标转换成矩形。

2.5 ​​​​​​​保存人脸检测的图片

复制代码
    imwrite("output_face_det.jpg",rockx_face_mat);
    rockx_destroy(face_detect_handle);

最后用imwrite保存人脸检测后的图片,并使用rockx_destroy销毁rockx_handle_t

三、高频踩坑点总结

1. 初始化失败,返回非 0 错误码

90% 是模型路径不对:

  • 必须写绝对路径,不能写相对路径;
  • 路径要指到 rockx_data 根目录,不要指到 face_det 子目录里;
  • 确认目录下有对应算法的模型文件,权限正常可读。

2. 模块 ID 不匹配

不同版本的 RockX SDK,人脸检测模块名可能不同:

  • 老版本:ROCKX_MODULE_FACE_DETECT
  • 新版本 V2:ROCKX_MODULE_FACE_DETECTION_V2
  • 用错模块 ID 会初始化失败,和你的 SDK 版本对应上就行。

四、和视频流检测的关系

单图检测是视频流检测的「单帧单元」,视频流场景只是把「读单图」换成了「RKMedia 取帧」,后面的封装、推理、解析结果、画框的逻辑100% 完全通用。 建议先跑通单张图片的 demo,确认环境、算法都正常,再把检测逻辑移植到你之前的视频线程里,调试成本会低很多。