[i=s] 本帖最后由 无垠的广袤 于 2025-6-27 19:02 编辑 [/i]
【电子DIY作品】BW21-CBV-Kit 基于人脸识别的门禁系统
本文介绍了安信可 BW21-CBV-Kit 开发板结合扩展板,实现了基于人脸识别的门禁系统,通过 OLED 实时显示门禁状态。
项目介绍
基于人脸识别的门禁系统,通过 OLED 显示门禁的开启和关闭状态。

流程图

代码
打开 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);

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

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

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

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

实现手持门禁系统的前提是通过串口配置注册人脸信息并存储至Flash 。
总结
本文介绍了安信可 BW21-CBV-Kit 开发板结合扩展板,实现了基于人脸识别的门禁系统,通过 OLED 实时显示门禁状态,为相关项目的快速开发设计和产品应用提供了参考。