发帖
0 0 0

【电子DIY作品】BW21-CBV-Kit 基于人脸识别的门禁系统

无垠的广袤
论坛元老

36

主题

50

回帖

4028

积分

论坛元老

积分
4028
QQ
电子DIY 26 0 昨天 18:55
[i=s] 本帖最后由 无垠的广袤 于 2025-6-27 19:02 编辑 [/i]

【电子DIY作品】BW21-CBV-Kit 基于人脸识别的门禁系统

本文介绍了安信可 BW21-CBV-Kit 开发板结合扩展板,实现了基于人脸识别的门禁系统,通过 OLED 实时显示门禁状态。

项目介绍

基于人脸识别的门禁系统,通过 OLED 显示门禁的开启和关闭状态。

door_unlock_system.jpg

  • 启动时处于识别模式;

  • 通过串口指令切换模式,

    • 发送 R 进入注册模式;
    • 在注册模式的基础上,发送 REG=Alice 注册人脸信息,发送 DEL=Alice 删除已注册的人脸信息;
    • 发送 Y 保存注册的人脸信息并切换为识别模式;
  • 重启设备后,直接进入识别模式,并加载已注册保存的人脸信息;

流程图

flowchart_door-unlock-system.jpg

代码

打开 Arduino IDE ,新建工程并添加如下代码

/*
 基于人脸识别的门禁系统(系统启动进入识别模式)
To use this system:
1.Upload the code and open serial monitor
2.Starts directly in recognition mode
3.Serial input 'R' switches to registration mode
4.Register faces using "REG=Name" commands
5.When done, send "Y" to save and switch back to recognition mode
6.In recognition mode, the OLED will show OPEN/CLOSE status
*/

#include "WiFi.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "RTSP.h"
#include "NNFaceDetectionRecognition.h"
#include "VideoStreamOverlay.h"
#include "AmebaFatFS.h"
#include <U8g2lib.h>  // Include U8g2 library for OLED

#define CHANNELVID  0    // Channel for RTSP streaming
#define CHANNELJPEG 1    // Channel for taking snapshots
#define CHANNELNN   3    // RGB format video for NN only available on channel 3

// Customised resolution for NN
#define NNWIDTH  576
#define NNHEIGHT 320

// U8g2 OLED setup - adjust according to your OLED model
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

VideoSetting configVID(VIDEO_FHD, 30, VIDEO_H264, 0);
VideoSetting configJPEG(VIDEO_FHD, CAM_FPS, VIDEO_JPEG, 1);
VideoSetting configNN(NNWIDTH, NNHEIGHT, 10, VIDEO_RGB, 0);
NNFaceDetectionRecognition facerecog;
RTSP rtsp;
StreamIO videoStreamer(1, 1);
StreamIO videoStreamerFDFR(1, 1);
StreamIO videoStreamerRGBFD(1, 1);

char ssid[] = "xxx";    // your network SSID (name)
char pass[] = "xxx";        // your network password
int status = WL_IDLE_STATUS;

bool regMode = false;       // Start in recognition mode
bool accessGranted = false; // Track access status
uint32_t img_addr = 0;
uint32_t img_len = 0;
String fileName;
long counter = 0;

// File Initialization
AmebaFatFS fs;

void updateOLEDStatus() {
    u8g2.clearBuffer();
    if (regMode) {
        u8g2.drawStr(0, 20, "REGISTER MODE");
        u8g2.drawStr(0, 40, "REG=<NAME>");
        u8g2.drawStr(0, 60, "Enter 'Y' to save");
    } else {
        u8g2.drawStr(0, 20, "RECOGNITION MODE");
        u8g2.drawStr(0, 40, accessGranted ? "Status: OPEN" : "Status: CLOSE");
    }
    u8g2.sendBuffer();
}

void setup()
{
    // Initialize OLED display
    u8g2.begin();
    u8g2.clearBuffer();
    u8g2.setFont(u8g2_font_ncenB10_tr);
    u8g2.drawStr(0, 20, "Initializing...");
    u8g2.sendBuffer();

    Serial.begin(115200);

    // Attempt to connect to Wifi network:
    while (status != WL_CONNECTED) {
        Serial.print("Attempting to connect to WPA SSID: ");
        Serial.println(ssid);
        status = WiFi.begin(ssid, pass);

        // Update OLED
        u8g2.clearBuffer();
        u8g2.drawStr(0, 20, "Connecting WiFi");
        u8g2.sendBuffer();
  
        delay(2000);
    }

    // Configure camera video channels with video format information
    Camera.configVideoChannel(CHANNELVID, configVID);
    Camera.configVideoChannel(CHANNELJPEG, configJPEG);
    Camera.configVideoChannel(CHANNELNN, configNN);
    Camera.videoInit();

    // Configure RTSP with corresponding video format information
    rtsp.configVideo(configVID);
    rtsp.begin();

    // Configure Face Recognition model
    facerecog.configVideo(configNN);
    facerecog.modelSelect(FACE_RECOGNITION, NA_MODEL, DEFAULT_SCRFD, DEFAULT_MOBILEFACENET);
    facerecog.begin();
    facerecog.setResultCallback(FRPostProcess);

    // Configure StreamIO object to stream data from video channel to RTSP
    videoStreamer.registerInput(Camera.getStream(CHANNELVID));
    videoStreamer.registerOutput(rtsp);
    if (videoStreamer.begin() != 0) {
        Serial.println("StreamIO link start failed");
    }

    // Start data stream from video channel
    Camera.channelBegin(CHANNELVID);
    Camera.channelBegin(CHANNELJPEG);

    // Configure StreamIO object to stream data from RGB video channel to face detection
    videoStreamerRGBFD.registerInput(Camera.getStream(CHANNELNN));
    videoStreamerRGBFD.setStackSize();
    videoStreamerRGBFD.setTaskPriority();
    videoStreamerRGBFD.registerOutput(facerecog);
    if (videoStreamerRGBFD.begin() != 0) {
        Serial.println("StreamIO link start failed");
    }

    // Start video channel for NN
    Camera.channelBegin(CHANNELNN);

    // Start OSD drawing on RTSP video channel
    OSD.configVideo(CHANNELVID, configVID);
    OSD.begin();

    // Restore any registered faces saved in flash
    facerecog.restoreRegisteredFace();

    // Update OLED
    updateOLEDStatus();

    Serial.println("System started in RECOGNITION mode");
    Serial.println("Available commands:");
    Serial.println("R - Switch to registration mode");
    Serial.println("In registration mode:");
    Serial.println("REG={Name} - Register a new face");
    Serial.println("DEL={Name} - Delete a registered face");
    Serial.println("RESET - Reset all registered faces");
    Serial.println("Y - Save faces and switch to recognition mode");
}

void loop()
{
    // Handle serial input
    if (Serial.available() > 0) {
        String input = Serial.readString();
        input.trim();

        if (input.equalsIgnoreCase("R") && !regMode) {
            // Switch to registration mode
            regMode = true;
            Serial.println("Switched to REGISTRATION mode");
            updateOLEDStatus();
        }
        else if (input.equalsIgnoreCase("Y") && regMode) {
            // Save configurations and switch to recognition mode
            facerecog.backupRegisteredFace();
            regMode = false;
            Serial.println("Faces saved. Switched to RECOGNITION mode");
            updateOLEDStatus();
        }
        else if (regMode) {
            // Registration mode commands
            if (input.startsWith(String("REG="))) {
                String name = input.substring(4);
                facerecog.registerFace(name);
                Serial.print("Registered face: ");
                Serial.println(name);
      
                // Update OLED temporarily
                u8g2.clearBuffer();
                u8g2.drawStr(0, 20, "REGISTERED:");
                u8g2.drawStr(0, 40, name.c_str());
                u8g2.sendBuffer();
                delay(2000);
                updateOLEDStatus();
            } 
            else if (input.startsWith(String("DEL="))) {
                String name = input.substring(4);
                facerecog.removeFace(name);
                Serial.print("Removed face: ");
                Serial.println(name);
            } 
            else if (input.startsWith(String("RESET"))) {
                facerecog.resetRegisteredFace();
                Serial.println("All registered faces have been reset");
            }
        }
    }

    delay(100);
    OSD.createBitmap(CHANNELVID);
    OSD.update(CHANNELVID);
}

// User callback function for post processing of face recognition results
void FRPostProcess(std::vector<FaceRecognitionResult> results)
{
    uint16_t im_h = configVID.height();
    uint16_t im_w = configVID.width();

    printf("Total number of faces detected = %d\r\n", facerecog.getResultCount());
    OSD.createBitmap(CHANNELVID);

    if (facerecog.getResultCount() > 0 && !regMode) {
        FaceRecognitionResult face = results[0];
        if (String(face.name()) != String("unknown")) {
            if (!accessGranted) {  // Only trigger once per recognition
                Serial.print("Access GRANTED for: ");
                Serial.println(face.name());
                accessGranted = true;
      
                // Update OLED
                updateOLEDStatus();
      
                // Take snapshot
                fs.begin();
                File file = fs.open(String(fs.getRootPath()) + face.name() + String(++counter) + ".jpg");
                delay(1000);
                Camera.getImage(CHANNELJPEG, &img_addr, &img_len);
                file.write((uint8_t *)img_addr, img_len);
                file.close();
                fs.end();
      
                // After 10 seconds, return to CLOSE status
                delay(5000);
                accessGranted = false;
                updateOLEDStatus();
            }
        } else {
            if (accessGranted) {  // Only update if status changed
                Serial.println("Access DENIED - Unknown face");
                accessGranted = false;
                updateOLEDStatus();
            }
        }
    }

    for (int i = 0; i < facerecog.getResultCount(); i++) {
        FaceRecognitionResult item = results[i];
        int xmin = (int)(item.xMin() * im_w);
        int xmax = (int)(item.xMax() * im_w);
        int ymin = (int)(item.yMin() * im_h);
        int ymax = (int)(item.yMax() * im_h);

        uint32_t osd_color = (String(item.name()) == String("unknown")) ? OSD_COLOR_RED : OSD_COLOR_GREEN;
  
        printf("Face %d name %s:\t%d %d %d %d\n\r", i, item.name(), xmin, xmax, ymin, ymax);
        OSD.drawRect(CHANNELVID, xmin, ymin, xmax, ymax, 3, osd_color);

        char text_str[40];
        snprintf(text_str, sizeof(text_str), "Face:%s", item.name());
        OSD.drawText(CHANNELVID, xmin, ymin - OSD.getTextHeight(CHANNELVID), text_str, osd_color);
    }
    OSD.update(CHANNELVID);
}
  • 保存工程,设备选择 AMB82-MINI 开发板,选择串口对应的端口号,摄像头选择 GC2053
  • 按住 BOOT 键的同时,短按 EN 键,使设备进入下载模式;
  • 点击 上传 按钮,待上传完成,短按 EN 键复位并运行程序;

效果

  • 系统进入识别模式 (Recognition Mode);
  • 串口发送 R ,进入注册模式 (Register Mode);

register-mode.jpg

  • 同一局域网下打开 VLC 软件的网络串流接口,输入开发板 ip 地址,如 rtsp://192.168.1.104:554 ,获取实时人脸识别状态,并保持人脸位置;
  • 串口发送 REG=LJL ,注册识别到的目标人脸信息,此时 VLC 采集画面显示绿色框;

register_face.jpg

  • 串口发送 Y ,自动保存人脸信息并返回识别模式;

测试

当摄像头未检测到目标人脸时,OLED显示门禁状态为 CLOSE ;

CLOSE.jpg

当摄像头检测到目标人脸时,OLED显示门禁状态切换为 OPEN,并保持 5 秒;

OPEN.jpg

移动门禁系统

结合扩展板的板载电池接口,可使用锂电池为系统供电,实现便携式手持门禁系统。

DoorUnlockFaceSystem.gif

实现手持门禁系统的前提是通过串口配置注册人脸信息并存储至Flash 。

总结

本文介绍了安信可 BW21-CBV-Kit 开发板结合扩展板,实现了基于人脸识别的门禁系统,通过 OLED 实时显示门禁状态,为相关项目的快速开发设计和产品应用提供了参考。

──── 0人觉得很赞 ────

使用道具 举报

您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 29086 个
  • 话题数: 41888 篇