发帖
3 0 0

小安派BW21-CBV-Kit—工位监测神器

风云龙一
中级会员

3

主题

3

回帖

214

积分

中级会员

积分
214
小安派·BW21-CBV-KIt 43 3 昨天 15:32
[i=s] 本帖最后由 风云龙一 于 2025-4-22 15:32 编辑 [/i]

功能介绍

你知道当你不在工位的时候,谁过来坐过吗?那谁是什么时间坐你这的?她/他坐你工作都在看哪?带着这些好奇,我用小安派BW21-CBV-Kit设计了一个工位监控神器。它能帮你偷偷记录他/她的身影......

用料

  • BW21-CBV-Kit x1
  • SD 卡 x1
  • 轻触按键 x2
  • 绿色 LED(可选)x1
  • 红色 LED(可选)x1
  • 超声波测距传感器 x1

功能实现

1、硬件接线

image.png

2、软件开发

软件使用Arduino,基于示例RTSPFaceRecognition进行修改。

image.png

代码详解

#include "WiFi.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "RTSP.h"
#include "NNFaceDetectionRecognition.h"
#include "VideoStreamOverlay.h"
#include <NTPClient.h>
#include <WiFiUdp.h>
#include "AmebaFatFS.h"
#include <NewPing.h>

#define TRIGGER_PIN 17
#define ECHO_PIN 8
#define MAX_DISTANCE 400
NewPing sonar(TRIGGER_PIN,ECHO_PIN,MAX_DISTANCE);
#define IOD18_PIN 18
#define IOD19_PIN 19


#define CHANNEL   0
#define CHANNELNN 3

// Lower resolution for NN processing
#define NNWIDTH  576
#define NNHEIGHT 320

float dis = 0.0;
String name = "";

uint32_t img_addr = 0;
uint32_t img_len = 0;

unsigned long startTime = 0;  // 定义一个变量用于记录开始时间
bool GPIOisHigh = false;  // 用于标记引脚是否已经变为高电平
bool facedetisTRUE = false; // 用于标记是否检测到人脸
AmebaFatFS fs;

VideoSetting config(VIDEO_FHD, CAM_FPS, VIDEO_JPEG, 1);
// VideoSetting config(VIDEO_FHD, 30, VIDEO_H264, 0);
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[] = "你的wifi名";    // your network SSID (name) Hello World
char pass[] = "你的wifi密码";        // your network password jwz@123456
int status = WL_IDLE_STATUS;

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 28800, 60000);
IPAddress ip;
int rtsp_portnum;

// 辅助函数,用于在数字小于 10 时前面补 0
String padWithZero(int num) {
  return (num < 10) ? "0" + String(num) : String(num);
}

// 生成日期时间格式的文件名
String generateFileName() {
  // 更新时间
  timeClient.update();

  // 获取时间戳
  unsigned long epochTime = timeClient.getEpochTime();
  Serial.println(epochTime);
  // struct tm *ptm = gmtime ((time_t *)&epochTime);
  time_t localTime = epochTime;
  struct tm *ptm = localtime(&localTime);

  // 提取年、月、日、时、分、秒
  int year = ptm->tm_year + 1900;
  int month = ptm->tm_mon + 1;
  int day = ptm->tm_mday;
  int hour = ptm->tm_hour;
  int minute = ptm->tm_min;
  int second = ptm->tm_sec;

  // 格式化日期和时间
  String fileName = String(year) + "-" + padWithZero(month) + "-" + padWithZero(day) + "_" +
                             padWithZero(hour) + "-" + padWithZero(minute) + "-" + padWithZero(second)+".jpg";

  // 打印当前日期和时间
  Serial.print("Current Date and Time: ");
  Serial.println(fileName);

  return String(fileName);
}

bool saveimage(){
    fs.begin();
    String fileName = generateFileName();
    File file = fs.open(String(fs.getRootPath()) + String(fileName));

    delay(1000);
    Camera.getImage(CHANNEL, &img_addr, &img_len);
    file.write((uint8_t *)img_addr, img_len);
    file.close();
    fs.end();
  return true;
}

void setup()
{
    Serial.begin(115200);
    pinMode(IOD18_PIN, INPUT);
    pinMode(IOD19_PIN, INPUT);

    // 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);

        // wait 2 seconds for connection:
        delay(2000);
    }
    ip = WiFi.localIP();
      // 初始化 NTP 客户端
    timeClient.begin();

    // Configure camera video channels with video format information
    // Adjust the bitrate based on your WiFi network quality
    config.setBitrate(2 * 1024 * 1024);    // Recommend to use 2Mbps for RTSP streaming to prevent network congestion
    Camera.configVideoChannel(CHANNEL, config);
    Camera.configVideoChannel(CHANNELNN, configNN);
    Camera.videoInit();

    // Configure RTSP with corresponding video format information
    rtsp.configVideo(config);
    rtsp.begin();
    rtsp_portnum = rtsp.getPort();

    // Configure Face Recognition model
    // Select Neural Network(NN) task and models
    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(CHANNEL));
    videoStreamer.registerOutput(rtsp);
    if (videoStreamer.begin() != 0) {
        Serial.println("StreamIO link start failed");
    }
    // Start data stream from video channel
    Camera.channelBegin(CHANNEL);

    // 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(CHANNEL, config);
    OSD.begin();
}

void loop()
{

    unsigned int uS = sonar.ping();
    dis = uS/US_ROUNDTRIP_CM;
    Serial.print("Ping:");
    Serial.print(uS/US_ROUNDTRIP_CM);
    Serial.println("cm");

    if(digitalRead(IOD18_PIN) == HIGH){
      name = "myself";
      facerecog.registerFace(name);
    }else if (digitalRead(IOD19_PIN) == HIGH) {
      facerecog.resetRegisteredFace();
    }
    delay(2000);
    OSD.createBitmap(CHANNEL);
    OSD.update(CHANNEL);  
}

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

    Serial.print("Network URL for RTSP Streaming: ");
    Serial.print("rtsp://");
    Serial.print(ip);
    Serial.print(":");
    Serial.println(rtsp_portnum);
    Serial.println(" ");

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

    if (facerecog.getResultCount() > 0) {
        facedetisTRUE = true;
        for (int i = 0; i < facerecog.getResultCount(); i++) {
            FaceRecognitionResult item = results[i];
            // Result coordinates are floats ranging from 0.00 to 1.00
            // Multiply with RTSP resolution to get coordinates in pixels
            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;
            if (String(item.name()) == String("unknown")) {
                osd_color = OSD_COLOR_RED;
            } else {
                osd_color = OSD_COLOR_GREEN;
            }

            // Draw boundary box
            printf("Face %d name %s:\t%d %d %d %d\n\r", i, item.name(), xmin, xmax, ymin, ymax);
            OSD.drawRect(CHANNEL, xmin, ymin, xmax, ymax, 3, osd_color);

            // Print identification text above boundary box
            char text_str[40];
            snprintf(text_str, sizeof(text_str), "Face:%s", item.name());
            OSD.drawText(CHANNEL, xmin, ymin - OSD.getTextHeight(CHANNEL), text_str, osd_color);
   
        if (dis <= 50.0) {
          if (!GPIOisHigh) {
            // 检测距离小于50cm,记录开始时间
            startTime = millis();
            GPIOisHigh = true;
  
          } else {
            // 检查是否已经持续了 3 秒
            if (millis() - startTime >= 3000 and item.name() == "myself")  {  
              saveimage();
              Serial.print("----------photo save complete!------------ ");
              while (dis <= 50.0); //一直小于50cm不重复记录
              GPIOisHigh = false;
            }
          }
        } else {
          // 离开后,重置标记
          GPIOisHigh = false;
        }
        }  
    }else{
      facedetisTRUE = false;
    }
    OSD.update(CHANNEL);
}

1、人脸监测识别

送电后开始实时检测人脸,首先要将摄像头对准自己,并且自己与测距传感器的距离小于50cm,然后按下绿色按钮,此时系统会录入自己人脸并命名为"myself",这样当自己坐在工位时就不会录入自己信息了(如果连自己的离开和坐下的时间都要记录,可以将 if (millis() - startTime >= 3000 and String(item.name()) != "myself") 条件里的后半部分去掉)。

微信截图_20250422151442.png

陌生人坐下会检测为“unknow”,距离够近后延时3秒钟开始拍照存储。

微信截图_20250422151035.png

通过按红色按钮可删除掉记录的人脸,通过绿色按钮重新录入。

2、距离监测

接入超声波测距传感器,根据自己工位及所需检测的距离自行调整。

3、以时间命名保存图片

通过wifi联网后,获取NTP时间

保存图片以当前时间命名,格式为YYYY-MM-DD_hh-mm-ss.jpg。

image.png

注意内容

其中使用人脸检测录入是获取摄像头的视频流

VideoSetting config(VIDEO_FHD, 30, VIDEO_H264, 0);

此模式下无法直接获取图片,因此将摄像头定义为图片帧格式

VideoSetting config(VIDEO_FHD, CAM_FPS, VIDEO_JPEG, 1);

功能拓展

此方式只将图片保存到存储卡中,若想实时或每天远程查看检测图片,可通过MQTT连接云端服务器,将图片上传即可,这样就可以实时看到谁光顾你的工位了。

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

使用道具 举报

园长已经监测到你了哈哈
工作时间可以调试板子真不错
一看就是个帅小伙
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28534 个
  • 话题数: 40652 篇