本篇介绍EASY EAI Nano的AI人脸检测功能,先看下测试效果:
本篇参考官方文档: https://www.easy-eai.com/document_details/3/109
1 代码下载
下载官方测试代码: https://github.com/EASY-EAI/EASY-EAI-Toolkit-C-Solution.git,本篇来修改face_detect中的代码并测试。
下载AI算法模型face_detect.model,百度网盘: https://pan.baidu.com/s/1mrhVHxHWJ8cY9Fl9k5KtYg#list/path=%2F 提取码:0k7j
总的资料百度网盘了也有算法模型: https://pan.baidu.com/s/1AjOIu77mzFM4cDA0MMVr2A#list/path=%2F,提取码:5ttf
我先使用总的资料里下载的模型测试。
2 人脸检测API接口介绍
组件 |
头文件以及库路径 |
描述 |
系统操作组件 |
easyeai-api/common_api/system_opt |
提供线程操作函数 |
摄像头组件 |
easyeai-api/peripheral_api/camera |
提供摄像头操作函数 |
显示屏组件 |
easyeai-api/peripheral_api/display |
提供显示屏操作函数 |
人脸检测组件 |
easyeai-api/algorithm_api/face_detect |
提供人脸检测操作函数 |
主要来看下人脸检测组件。
face_detect.h主要内容如下,包括一个det(detect)类的3个人脸检测API函数:
class det {
public:
det(){
landmarks.resize(5);
}
~det(){
}
bool operator<(const det &t) const {
return score < t.score;
}
bool operator>(const det &t) const {
return score > t.score;
}
cv::Rect_<float> box;
std::vector<cv::Point2f> landmarks;
float score;
void print() {
printf("finalbox(x1y1x2y2) %f %f %f %f, score %f\n", box.x, box.y, box.br().x, box.br().y, score);
printf("landmarks ");
int point_number = landmarks.size();
for (int i = 0; i < point_number; i++) {
printf("%f %f, ", landmarks[i].x, landmarks[i].y);
}
printf("\n");
}
};
int face_detect_init(rknn_context *ctx, const char *path);
int face_detect_run(rknn_context ctx, cv::Mat &input_image, std::vector<det> &result);
int face_detect_release(rknn_context ctx);
一些参数:
- ctx:输入参数,rknn_context句柄
- path:输入参数,算法模型路径
- input_image:输入参数, Opencv Mat格式图像
- result:输出参数, 人脸检测的结果输出
3 代码分析与修改
官方例程使用的是双目摄像头中的RGB摄像头,本篇测试修改为使用外接USB摄像头来采集图像,并将采集的图像横屏显示。另外,在识别到人脸后,通过OpenCV函数,在屏幕左上角显示出识别到的人脸个数。
3.1 图像采集与显示线程(主线程)
修改后的主程序逻辑如下:
主要代码结构如下:
Mat algorithm_image;
pthread_mutex_t img_lock;
int main(int argc, char **argv)
{
//省略...
pthread_t mTid;
Result_t Result;
Mat image;
// 1.打开USB摄像头
//省略...
// 2.创建识别线程,以及图像互斥锁
pthread_mutex_init(&img_lock, NULL);
Result.result.clear();
Result.face_number = 0;
CreateNormalThread(detect_thread_entry, &Result, &mTid);
// 3.显示初始化
//省略...
// 4.(取流 + 显示)循环
while(1){
// 4.1、取流
pthread_mutex_lock(&img_lock);
ret = usbcamera_getframe(USB2_0, USB_DIRECT, pbuf);
if (ret) {
printf("error: %s, %d\n", __func__, __LINE__);
pthread_mutex_unlock(&img_lock);
continue;
}
algorithm_image = Mat(CAMERA_HEIGHT, CAMERA_WIDTH, CV_8UC3, pbuf);
image = algorithm_image.clone();
pthread_mutex_unlock(&img_lock);
// 4.2、显示
cv::putText(image, std::string("detect faces: ") + std::to_string((int)Result.result.size()),
cv::Point2f(30, 50), cv::FONT_HERSHEY_SIMPLEX,1.45, CV_RGB(255,0,0),3.0);
for (int i = 0; i < (int)Result.result.size(); i++)
{
// 标出人脸框
int x = (int)(Result.result[i].box.x);
int y = (int)(Result.result[i].box.y);
int w = (int)(Result.result[i].box.width);
int h = (int)(Result.result[i].box.height);
rectangle(image, Rect(x, y, w, h), Scalar(0, 255, 0), 2, 8, 0);
// 标出人脸定位标记
for (int j = 0; j < (int)Result.result[i].landmarks.size(); ++j) {
cv::circle(image, cv::Point((int)Result.result[i].landmarks[j].x, (int)Result.result[i].landmarks[j].y), 2, cv::Scalar(0, 255, 0), 3, 8);
}
}
disp_commit(image.data, IMAGE_SIZE);
usleep(20*1000);
}
//省略...
}
3.2 人脸检测处理
人脸检测处理序逻辑如下:
代码如下:
// 识别线程
void *detect_thread_entry(void *para)
{
int ret;
Result_t *pResult = (Result_t *)para;
// 人脸检测初始化
rknn_context ctx;
face_detect_init(&ctx, "face_detect.model");
Mat image;
while(1)
{
if(algorithm_image.empty()) {
usleep(5);
continue;
}
pthread_mutex_lock(&img_lock);
image = algorithm_image.clone();
pthread_mutex_unlock(&img_lock);
// 算法分析
ret = face_detect_run(ctx, image, pResult->result);
pResult->face_number = pResult->result.size();
if(ret <= 0){
pResult->result.clear();
usleep(1000);
continue;
}
printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
printf("face number : %d\n", pResult->face_number);
usleep(16*1000);
}
/* 人脸检测释放 */
face_detect_release(ctx);
return NULL;
}
4 测试
测试效果如下,可以同时检测到多张人脸,在屏幕左上角标注有检测到的人脸个数:
5 总结
本篇介绍了EASY EAI Nano的AI人脸检测功能,修改官方代码,改用外接USB摄像头来采集图像,并在识别到人脸后,通过OpenCV函数,在屏幕左上角显示出识别到的人脸个数。