数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 9|回复: 0

《DNK210使用指南-SDK版》第三十六章 人脸识别实验

[复制链接]
发表于 5 小时前 | 显示全部楼层 |阅读模式
第三十六章 人脸识别实验

在上一章节中,介绍了利用KPU模块实现人脸68关键点检测的功能,本章将继续介绍利用KPU模块实现人脸识别的功能。通过本章的学习,读者将学习到使用SDK编程技术实现人脸识别应用。                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         
本章分为如下几个小节:
36.1 KPU模块介绍
36.2 硬件设计
36.3 程序设计
36.4 运行验证


36.1 KPU模块介绍
有关KPU模块的介绍,请见第30.1小节《KPU介绍》。
36.2 硬件设计
36.2.1 例程功能
1. 获取摄像头输出的图像,并送入KPU进行人脸检测,接着对检测到的人脸分别进行人脸特征提取,然后将提取到的人脸特征与先前录入的人脸特征进行对比,如果得分高于阈值,则能成功识别人脸,最后将识别结果同原始图像在LCD上进行显示。
2. 按下KEY0按键可以录入当前人脸的特征,例程中最多保存五组。
36.2.2 硬件资源
本章实验内容,主要讲解KPU模块的使用,无需关注硬件资源。
36.2.3 原理图
本章实验内容,主要讲解KPU模块的使用,无需关注原理图。
36.3 程序设计
36.3.1 main.c代码
main.c中的代码如下所示:
INCBIN(model_kpu, "face_detect_320x240.kmodel");
INCBIN(model_fea, "feature_extraction.kmodel");

image_t kpu_image,crop_image,ai_image;
obj_info_t cla_obj_coord;
float record_ftrs[192 * 5]; /*最多存放5组数据,大小为192 * 5 * 4B */

static float g_anchor[ANCHOR_NUM * 2] = {0.1075, 0.126875, 0.126875, 0.175, 0.1465625, 0.2246875, 0.1953125, 0.25375, 0.2440625, 0.351875, 0.341875, 0.4721875, 0.5078125, 0.6696875, 0.8984375, 1.099687, 2.129062, 2.425937};
/*特征检测*/
static volatile uint8_t ai_done_flag;

/* KPU运算完成回调 */
static void ai_done_callback(void *userdata)
{
    ai_done_flag = 1;
}

float calCosinDistance(float *faceFeature0P, float *faceFeature1P, int featureLen)
{
    float coorFeature = 0;
    // calculate the sum square
    for(int fIdx = 0; fIdx < featureLen; fIdx++)
    {
        float featureVal0 = *(faceFeature0P + fIdx);
        float featureVal1 = *(faceFeature1P + fIdx);
        coorFeature += featureVal0 * featureVal1;
        //coorFeature += powf(featureVal0 - featureVal1, 2);
    }
    // cosin distance
    //return sqrtf(coorFeature);
    return (0.5 + 0.5 * coorFeature) * 100;
}

int main(void)
{
    uint8_t *disp;
    uint8_t *ai;
    uint8_t key;
    kpu_model_context_t task_kpu, task_fea;
    float *face_box, *face_feature;
    size_t face_box_size, face_feature_size;
    uint16_t x1 = 0, y1 = 0, x2, y2, cut_width, cut_height;
    float score, max_score;
    uint8_t face_index = 0;
    char show_data[25];
    region_layer_t detect_kpu;
    uint16_t feature_sta = 0;
    uint16_t feature_offset = 0;

    sysctl_pll_set_freq(SYSCTL_PLL0, 800000000);
    sysctl_pll_set_freq(SYSCTL_PLL1, 400000000);
    sysctl_pll_set_freq(SYSCTL_PLL2, 45158400);
    sysctl_clock_enable(SYSCTL_CLOCK_AI);
    sysctl_set_power_mode(SYSCTL_POWER_BANK6, SYSCTL_POWER_V18);
    sysctl_set_power_mode(SYSCTL_POWER_BANK7, SYSCTL_POWER_V18);
    sysctl_set_spi0_dvp_data(1);

    key_init();
    lcd_init();
    lcd_set_direction(DIR_YX_LRUD);
    camera_init(24000000);
    camera_set_pixformat(PIXFORMAT_RGB565);
    camera_set_framesize(320, 240);

    kpu_image.pixel = 3;
    kpu_image.width = 320;
    kpu_image.height = 240;
    // image_init(&kpu_image);

    ai_image.pixel = 3;
    ai_image.width = 64;
    ai_image.height = 64;
    image_init(&ai_image);


    if (kpu_load_kmodel(&task_kpu, (const uint8_t *)model_kpu_data) != 0)
    {
        printf("Kmodel load failed!\n");
        while (1);
    }
    if (kpu_load_kmodel(&task_fea, (const uint8_t *)model_fea_data) != 0)
    {
        printf("Kmodel load failed!\n");
        while (1);
    }

    detect_kpu.anchor_number = ANCHOR_NUM;
    detect_kpu.anchor = g_anchor;
    detect_kpu.threshold = 0.5;
    detect_kpu.nms_value = 0.2;
    region_layer_init(&detect_kpu, 10, 8, 30, 320, 240);

    while (1)
    {
        if (camera_snapshot(&disp, &ai) == 0)
        {
            ai_done_flag = 0;
            if (kpu_run_kmodel(&task_kpu, (const uint8_t *)ai, DMAC_CHANNEL5,
ai_done_callback, NULL) != 0)
            {
                printf("Kmodel run failed!\n");
                while (1);
            }
            while (ai_done_flag == 0);
            if (kpu_get_output(&task_kpu, 0, (uint8_t **)&face_box,
&face_box_size) != 0)
            {
                printf("Output get failed!\n");
                while (1);
            }

            detect_kpu.input = face_box;
            region_layer_run(&detect_kpu, &cla_obj_coord);
            // region_layer_draw_boxes(&detect_kpu, draw_boxes_callback);

            for (size_t j = 0; j < cla_obj_coord.obj_number; j++)        
            {
                if (cla_obj_coord.obj[j].x1 >= 2)
                {
                    x1 = cla_obj_coord.obj[j].x1 - 2;   /* 对识别框稍微放大点 */
                }
                if (cla_obj_coord.obj[j].y1 >= 2)
                {
                    y1 = cla_obj_coord.obj[j].y1 - 2;
                }

                x2 = cla_obj_coord.obj[j].x2 + 2;
                y2 = cla_obj_coord.obj[j].y2 + 2;
                cut_width = x2 - x1 ;
                cut_height = y2 - y1 ;

                kpu_image.addr = ai;
                crop_image.pixel = 3;
                crop_image.width = cut_width;
                crop_image.height = cut_height;
                image_init(&crop_image);
                image_crop(&kpu_image, &crop_image, x1, y1);
                image_resize(&crop_image,&ai_image);
                image_deinit(&crop_image);

                ai_done_flag = 0;
                if (kpu_run_kmodel(&task_fea, (const uint8_t *)ai_image.addr,
DMAC_CHANNEL5, ai_done_callback, NULL) != 0)
                {
                    printf("Kmodel run failed!\n");
                    while (1);
                }
                while (ai_done_flag == 0);
                if (kpu_get_output(&task_fea, 0, (uint8_t **)&face_feature,
&face_feature_size) != 0)
                {
                    printf("Output get failed!\n");
                    while (1);
                }

                max_score = 0;
                for (uint8_t i = 0; i < feature_sta; i++)
                {
                    score = calCosinDistance(&record_ftrs[i * 192], face_feature, 192);
                    if(score > max_score)
                    {
                        max_score = score;
                        face_index = i;
                    }
                }              
                key = key_scan(0);                /* 得到键值 */
                if (key == KEY0_PRES && feature_sta < 5)
                {
                    feature_offset = feature_sta * 192;
                    for (size_t i = 0; i < 192; i++)
                    {
                        record_ftrs[feature_offset + i] = *face_feature++;
                    }
                    feature_sta++;                  
                }

                if (max_score >1800)
                {
                    draw_box_rgb565_image((uint16_t *)disp, 320, x1, y1, x2, y2, GREEN);
                    sprintf(show_data,"%d-score:%.2f", face_index, max_score);
                    draw_string_rgb565_image((uint16_t *)disp, 320, 240, x1, y1,
show_data, GREEN);
                }
                else
                {
                    draw_box_rgb565_image((uint16_t *)disp, 320, x1, y1, x2, y2, RED);
                }
            }
            lcd_draw_picture(0, 0, 320, 240, (uint16_t *)disp);
            camera_snapshot_release();
        }
    }
}
本实验和上个实验相似,需要用到两个AI模型, face_detect_320x240.kmodel是人脸检测模型,用于获取人脸关键信息的坐标,然后通过图像两个坐标把人脸的关键区域切割下来给另外个模型使用。feature_extraction.kmodel是人脸特征点采集的模型,网络运算的图片大小为64*64。
简而言之,人脸识别就是对人脸特征信息进行对比匹配的过程。首先,我们会预先录入一定数量的人脸特征数据作为参照样本储存起来;随后,当需要进行人脸识别时,我们会采目标人脸图像用同个特征采集模型进行运算,提取出相应的特征信息;接着,将提取出的目标人脸特征信息与已存储的参照样本特征信息通过特定的比对函数计算相似度得分;最后,依据所得分数来判断待识别人脸是否属于参照样本中的成员。
calCosinDistance函数就是上述的对比函数,可以对特征做简单的区分和获取相似度得分。下面我们讲解main函数。
可以看到一开始是先初始化了LCD和摄像头,初始化完成后创建一个64*64RGB888图片缓存区,然后加载上述两个需要用到的网络模型,并初始化YOLO2网络,配置region_layer_t结构体参数的数据。
然后便是在一个循环中不断地获取摄像头输出的图像,首先将图像进行人脸检测,检测图像中存在的人脸,接着对人脸图像进行人脸特征提取,然后将提取到的人脸特征与先前保存的人脸特征进行对比,若对比得到高于指定的阈值,则表示能够识别出人脸,通过在获取到人脸特征后可以根据需要进行人脸特征的录入,最后将以上所有的分析检测结果在图像上进行绘制,然后在LCD上显示图像。
36.4 运行验证
DNK210开发板连接到电脑主机,通过VSCode将固件烧录到开发板中,将摄像头对准人脸,让其采集到人脸图像,接着按下KEY0按键来录入人脸的特征,最多录入5张,可以看到LCD上显示了人脸识别的结果,每张人脸根据其特征比对得分,得到一个ID号,ID号与人脸录入的顺序有关,如下图所示:
图36.4.1 LCD显示人脸识别实验结果


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册 微信登录

x
您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2026-3-10 14:48 , Processed in 0.140401 second(s), 10 queries , Gzip On, Redis On.

Powered by Discuz!

© MyDigit.Net Since 2006

快速回复 返回顶部 返回列表