[i=s] 本帖最后由 huatenma 于 2025-3-29 13:06 编辑 [/i]
实现逻辑思路
- 硬件初始化流程:
复制
[OLED初始化] -> [WiFi连接] -> [摄像头初始化] -> [RTSP配置] -> [神经网络管道搭建]
- 数据流逻辑:
复制
摄像头视频流
├─> 主通道(CAM_CHANNEL) ─> RTSP流媒体输出
└─> NN处理通道(NN_CHANNEL) ─> 人脸检测模型 ─> 检测结果回调
- 显示逻辑:
复制
人脸检测结果 -> 坐标转换 -> OLED显示引擎 -> 屏幕刷新
- 关键功能模块:
模块 |
功能说明 |
关键技术点 |
OLED驱动模块 |
管理屏幕初始化、图形绘制和刷新 |
Adafruit GFX库、双缓冲机制 |
摄像头管理模块 |
配置多通道视频流、编码参数设置 |
Ambarella SDK视频管道管理 |
神经网络模块 |
人脸检测模型加载、推理结果处理 |
SCRFD轻量级人脸检测模型 |
坐标转换系统 |
将1920x1080坐标映射到128x64屏幕 |
线性映射算法 |
异步回调机制 |
人脸检测结果与主循环的非阻塞通信 |
volatile变量保证数据一致性 |
- 性能优化措施:
- 双通道视频处理:主通道用于高清视频流传输,独立通道用于低分辨率神经网络处理
- 坐标约束机制:使用constrain()函数确保绘制坐标在屏幕范围内
- 节流刷新机制:80ms刷新间隔平衡流畅度和资源消耗
- 轻量级绘图:使用基本几何图形降低渲染负载
- 异常处理机制:
- 硬件初始化失败检测(摄像头、OLED)
- WiFi连接重试机制(最多5次重试)
- 人脸坐标约束处理(防止绘制越界)
- 网络中断自动恢复(依赖Ambarella SDK底层自动重连)
系统架构示意图
复制
+---------------------+
| 摄像头输入 |
| (1920x1080@30fps) |
+----------+----------+
|
v
+----------+----------+
| 视频分配器 |
| [通道0] [通道3] |
+----------+----------+
| |
v v
+----------+----------+ +-------------------+
| RTSP编码器 | | 神经网络处理器 |
| (H.264视频流) | | (人脸检测模型) |
+----------+----------+ +---------+---------+
| |
v v
+----------+----------+ +---------+---------+
| 网络传输模块 | | 人脸数据回调 |
| (RTSP协议传输) | | (坐标转换处理) |
+---------------------+ +---------+---------+
|
v
+-------+-------+
| OLED显示引擎 |
| (128x64 OLED)|
+--------------+
/* AMB82-MINI人脸识别OLED显示完整代码 */
#include "WiFi.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "RTSP.h"
#include "NNFaceDetection.h"
#include "VideoStreamOverlay.h"
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
//---------------------------
// 硬件配置
//---------------------------
// OLED配置
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 摄像头通道配置
#define CAM_CHANNEL 0 // 主视频通道
#define NN_CHANNEL 3 // 神经网络处理通道
#define NN_WIDTH 576 // NN处理宽度
#define NN_HEIGHT 320 // NN处理高度
//---------------------------
// 全局对象
//---------------------------
VideoSetting camConfig(VIDEO_FHD, 30, VIDEO_H264, 0); // 主摄像头配置(1920x1080)
VideoSetting nnConfig(NN_WIDTH, NN_HEIGHT, 10, VIDEO_RGB, 0); // NN输入配置
NNFaceDetection faceDetector;
RTSP rtspStream;
StreamIO videoPipeline(1, 1); // 视频流管道
StreamIO nnPipeline(1, 1); // NN处理管道
//---------------------------
// 网络配置
//---------------------------
char ssid[] = "Maga";
char pass[] = "134567890";
volatile bool wifiConnected = false;
//---------------------------
// 人脸数据共享变量
//---------------------------
volatile struct {
int x;
int y;
int width;
int height;
bool detected;
} faceData = {0, 0, 0, 0, false};
//---------------------------
// 系统初始化
//---------------------------
void setup() {
// 初始化串口
Serial.begin(115200);
while (!Serial);
// 阶段1:OLED初始化
initOLED();
// 阶段2:WiFi连接
connectWiFi();
// 阶段3:摄像头系统初始化
initCameraSystem();
// 阶段4:神经网络管道搭建
setupNNPipeline();
// 阶段5:OSD叠加层初始化
OSD.configVideo(CAM_CHANNEL, camConfig);
OSD.begin();
}
//---------------------------
// 主循环
//---------------------------
void loop() {
updateOLEDDisplay();
delay(80); // 控制刷新率约12.5FPS
}
//---------------------------
// 初始化OLED
//---------------------------
void initOLED() {
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println("OLED初始化失败!");
while(1);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.println("System Init...");
display.display();
}
//---------------------------
// 连接WiFi
//---------------------------
void connectWiFi() {
display.clearDisplay();
display.setCursor(0,0);
display.print("Connecting to ");
display.println(ssid);
display.display();
int retryCount = 0;
while (WiFi.begin(ssid, pass) != WL_CONNECTED) {
display.print(".");
display.display();
delay(2000);
if(retryCount++ > 5) {
display.println("\nConnection Failed!");
display.display();
while(1);
}
}
display.println("\nConnected!");
display.print("IP:");
display.println(WiFi.localIP());
display.display();
delay(1000);
}
//---------------------------
// 初始化摄像头系统
//---------------------------
void initCameraSystem() {
// 配置摄像头通道
camConfig.setBitrate(2 * 1024 * 1024); // 2Mbps比特率
Camera.configVideoChannel(CAM_CHANNEL, camConfig);
Camera.configVideoChannel(NN_CHANNEL, nnConfig);
// 初始化视频系统
if(Camera.videoInit() != 0) {
display.println("Camera Init Fail!");
display.display();
while(1);
}
// 配置RTSP流
rtspStream.configVideo(camConfig);
rtspStream.begin();
// 构建视频流管道
videoPipeline.registerInput(Camera.getStream(CAM_CHANNEL));
videoPipeline.registerOutput(rtspStream);
videoPipeline.begin();
Camera.channelBegin(CAM_CHANNEL);
}
//---------------------------
// 配置神经网络管道
//---------------------------
void setupNNPipeline() {
// 初始化人脸检测器
faceDetector.configVideo(nnConfig);
faceDetector.setResultCallback(faceDetectionCallback);
faceDetector.modelSelect(FACE_DETECTION, NA_MODEL, DEFAULT_SCRFD, NA_MODEL);
faceDetector.begin();
// 构建NN处理管道
nnPipeline.registerInput(Camera.getStream(NN_CHANNEL));
nnPipeline.registerOutput(faceDetector);
nnPipeline.begin();
Camera.channelBegin(NN_CHANNEL);
}
//---------------------------
// 人脸检测回调函数
//---------------------------
void faceDetectionCallback(std::vector<FaceDetectionResult> results) {
if(!results.empty()) {
FaceDetectionResult firstFace = results[0];
// 原始坐标转换(基于1920x1080)
int origX = firstFace.xMin() * 1920;
int origY = firstFace.yMin() * 1080;
int origW = (firstFace.xMax() - firstFace.xMin()) * 1920;
int origH = (firstFace.yMax() - firstFace.yMin()) * 1080;
// 映射到OLED分辨率
faceData.x = map(origX, 0, 1920, 0, SCREEN_WIDTH);
faceData.y = map(origY, 0, 1080, 0, SCREEN_HEIGHT);
faceData.width = map(origW, 0, 1920, 0, SCREEN_WIDTH);
faceData.height = map(origH, 0, 1080, 0, SCREEN_HEIGHT);
faceData.detected = true;
} else {
faceData.detected = false;
}
}
//---------------------------
// OLED显示更新
//---------------------------
void updateOLEDDisplay() {
display.clearDisplay();
if(faceData.detected) {
// 绘制人脸框
display.drawRect(
constrain(faceData.x, 0, SCREEN_WIDTH),
constrain(faceData.y, 0, SCREEN_HEIGHT),
constrain(faceData.width, 1, SCREEN_WIDTH-faceData.x),
constrain(faceData.height, 1, SCREEN_HEIGHT-faceData.y),
SSD1306_WHITE
);
// 绘制简化面部特征
int eyeY = faceData.y + faceData.height/4;
int mouthY = faceData.y + faceData.height*3/4;
// 左眼
display.fillCircle(
faceData.x + faceData.width/4,
eyeY,
2, SSD1306_WHITE
);
// 右眼
display.fillCircle(
faceData.x + faceData.width*3/4,
eyeY,
2, SSD1306_WHITE
);
// 嘴巴
display.drawLine(
faceData.x + faceData.width/4,
mouthY,
faceData.x + faceData.width*3/4,
mouthY,
SSD1306_WHITE
);
} else {
display.setCursor(0,0);
display.println("No Face Detected");
}
display.display();
}