发帖
4 0 0

安信可小安派BW21-CVB-Kit:人脸检测的本地RTSP推流

signal
中级会员

3

主题

12

回帖

432

积分

中级会员

积分
432
小安派·BW21-CBV-KIt 71 4 昨天 11:02

0 想法

在野外进行视频流或者图片传输时,可以选择利用备用电源驱动一个路由器来构建一个局域网用于传输需求。但小安派在是可以创建AP进行通信的(WIFI->CreateWiFiAP),且官方示例中的AmebaNN->RTSPFaceDetection还是建议使用自己的wifi。那突发奇想,是不是可以将其两个结合起来呢?这样在没有wifi的地方也可以用手机连接小安派的AP进行视频传输。

先说结论:芯片发热属于正常范围(较烫),体感温度约55℃±5℃(没专业设备,不好意思)。利用开发板做RTSP服务端还是太高估了(也可能是我还没有掌握精髓),延迟很大,存在失真可能性,速度卡成ppt了(传输1920 x 1080,检测576 x 320)。

// Channel 0 : 1920 x 1080 30FPS H264
// Channel 1 : 1280 x 720  30FPS H264
#define NNWIDTH  576
#define NNHEIGHT 320
VideoSetting config(VIDEO_FHD, 30, VIDEO_H264, 0); //Channel 0 1920 x 1080
VideoSetting configNN(NNWIDTH, NNHEIGHT, 10, VIDEO_RGB, 0);

1 做法

材料

小安派BW21-CVB-Kit官方套装(GC2053摄像头,天线,开发板)

Android / IOS手机(软件V7RC)

代码

/*
 Example guide:
 https://www.amebaiot.com/en/amebapro2-arduino-neuralnework-face-detection/

 NN Model Selection
 Select Neural Network(NN) task and models using modelSelect(nntask, objdetmodel, facedetmodel, facerecogmodel).
 Replace with NA_MODEL if they are not necessary for your selected NN Task.

 NN task
 =======
 OBJECT_DETECTION/ FACE_DETECTION/ FACE_RECOGNITION

 Models
 =======
 YOLOv3 model         DEFAULT_YOLOV3TINY   / CUSTOMIZED_YOLOV3TINY
 YOLOv4 model         DEFAULT_YOLOV4TINY   / CUSTOMIZED_YOLOV4TINY
 YOLOv7 model         DEFAULT_YOLOV7TINY   / CUSTOMIZED_YOLOV7TINY
 SCRFD model          DEFAULT_SCRFD        / CUSTOMIZED_SCRFD
 MobileFaceNet model  DEFAULT_MOBILEFACENET/ CUSTOMIZED_MOBILEFACENET
 No model             NA_MODEL
 */

#include "WiFi.h"
#include "StreamIO.h"
#include "VideoStream.h"
#include "RTSP.h"
#include "NNFaceDetection.h"
#include "VideoStreamOverlay.h"

#define CHANNEL   0
#define CHANNELNN 3

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

VideoSetting config(VIDEO_FHD, 30, VIDEO_H264, 0);
VideoSetting configNN(NNWIDTH, NNHEIGHT, 10, VIDEO_RGB, 0);
NNFaceDetection facedet;
RTSP rtsp;
StreamIO videoStreamer(1, 1);
StreamIO videoStreamerNN(1, 1);


IPAddress ip;
int rtsp_portnum;

// #define MANUAL_INPUT
#ifdef MANUAL_INPUT    // Initialise ssid string, pwd string, and serial_in object
// Initialise strings
String str_ssid, str_pass, str_channel;
#endif

// UTF-8 encoding can also be used for SSID with emoji characters
// Emoji characters can be converted into UTF-8 at https://mothereff.in/utf-8
// char ssid[] = "\xe2\x9c\x8c\xef\xb8\x8f Ameba \xe2\x9c\x8c\xef\xb8\x8f";

char ssid[] = "AP_Network_SSID";    // Set the AP SSID
char pass[] = "AP_Password";        // Set the AP password
char channel[] = "1";               // Set the AP channel
int status = WL_IDLE_STATUS;        // Indicator of Wifi status
int ssid_status = 0;                // Set SSID status, 1 hidden, 0 not hidden

void setup()
{
    // Initialize serial and wait for port to open:
    Serial.begin(115200);
    while (!Serial) {
        ;    // wait for serial port to connect. Needed for native USB port only
    }

    // attempt to start AP:
    while (status != WL_CONNECTED) {
#ifdef MANUAL_INPUT
        Serial.println("Enter your ssid");
        while (Serial.available() == 0) {
        }
        str_ssid = Serial.readString();
        str_ssid.trim();
        Serial.print("SSID entered: ");
        Serial.println(str_ssid);

        Serial.println("Enter your password");
        while (Serial.available() == 0) {
        }
        str_pass = Serial.readString();
        str_pass.trim();
        if (str_pass.length() != 0) {          // user has entered data
            while (str_pass.length() < 8) {    // to catch pwd<8 exception
                Serial.println("Password cannot be less than 8 characters! Try again");
                while (Serial.available() == 0) {
                }
                str_pass = Serial.readString();
                str_pass.trim();
            }
            Serial.print("Password entered: ");
            Serial.println(str_pass);
        }

        Serial.println("Enter your channel number");
        int checker = 0;

        while (1) {
            while (Serial.available() == 0) {
            }
            str_channel = Serial.readString();
            str_channel.trim();
            checker = str_channel.toInt();
            if (str_channel == (String(checker))) {
                break;
            }
            Serial.println("channel should be a number!");
        }
        Serial.print("channel entered: ");
        Serial.println(str_channel);
#endif
        Serial.print("Attempting to start AP with SSID: ");
#ifndef MANUAL_INPUT
        Serial.println(ssid);
        status = WiFi.apbegin(ssid, pass, channel, ssid_status);
#else
        char ssid_cust[str_ssid.length() + 1];
        char pass_cust[str_pass.length() + 1];
        char channel_cust[str_channel.length() + 1];
        strcpy(ssid_cust, str_ssid.c_str());
        strcpy(pass_cust, str_pass.c_str());
        strcpy(channel_cust, str_channel.c_str());
        Serial.println(str_ssid.c_str());
        status = WiFi.apbegin(ssid_cust, pass_cust, channel_cust, ssid_status);
        str_ssid = str_pass = str_channel = "";
#endif
        delay(1000);
    }

    // AP MODE already started:
    Serial.println("AP mode already started");
    Serial.println();
    printWifiData();
    printCurrentNet();

    ip = WiFi.localIP();

    // 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 detection with corresponding video format information
    // Select Neural Network(NN) task and models
    facedet.configVideo(configNN);
    facedet.setResultCallback(FDPostProcess);
    facedet.modelSelect(FACE_DETECTION, NA_MODEL, DEFAULT_SCRFD, NA_MODEL);
    facedet.begin();

    // 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
    videoStreamerNN.registerInput(Camera.getStream(CHANNELNN));
    videoStreamerNN.setStackSize();
    videoStreamerNN.setTaskPriority();
    videoStreamerNN.registerOutput(facedet);
    if (videoStreamerNN.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()
{
    // Do nothing
}

// User callback function for post processing of face detection results
void FDPostProcess(std::vector<FaceDetectionResult> results)
{
    int count = 0;

    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", facedet.getResultCount());
    OSD.createBitmap(CHANNEL);

    if (facedet.getResultCount() > 0) {
        for (int i = 0; i < facedet.getResultCount(); i++) {
            FaceDetectionResult 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);

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

            // Print identification text above boundary box
            char text_str[40];
            snprintf(text_str, sizeof(text_str), "%s %d", item.name(), item.score());
            OSD.drawText(CHANNEL, xmin, ymin - OSD.getTextHeight(CHANNEL), text_str, OSD_COLOR_CYAN);

            // Draw facial feature points
            for (int j = 0; j < 5; j++) {
                int x = (int)(item.xFeature(j) * im_w);
                int y = (int)(item.yFeature(j) * im_h);
                OSD.drawPoint(CHANNEL, x, y, 8, OSD_COLOR_RED);
                count++;
                if (count == MAX_FACE_DET) {
                    goto OSDUpdate;
                }
            }
        }
    }

OSDUpdate:
    OSD.update(CHANNEL);
}
void printWifiData()
{
    // print your WiFi IP address:
    IPAddress ip = WiFi.localIP();
    Serial.print("IP Address: ");
    Serial.println(ip);

    // print your subnet mask:
    IPAddress subnet = WiFi.subnetMask();
    Serial.print("NetMask: ");
    Serial.println(subnet);

    // print your gateway address:
    IPAddress gateway = WiFi.gatewayIP();
    Serial.print("Gateway: ");
    Serial.println(gateway);
    Serial.println();
}

void printCurrentNet()
{
    // print the SSID of the AP:
    Serial.print("SSID: ");
    Serial.println(WiFi.SSID());

    // print the MAC address of AP:
    byte bssid[6];
    WiFi.BSSID(bssid);
    Serial.print("BSSID: ");
    Serial.print(bssid[0], HEX);
    Serial.print(":");
    Serial.print(bssid[1], HEX);
    Serial.print(":");
    Serial.print(bssid[2], HEX);
    Serial.print(":");
    Serial.print(bssid[3], HEX);
    Serial.print(":");
    Serial.print(bssid[4], HEX);
    Serial.print(":");
    Serial.println(bssid[5], HEX);

    // print the encryption type:
    byte encryption = WiFi.encryptionType();
    Serial.print("Encryption Type:");
    Serial.println(encryption, HEX);
    Serial.println();
}

烧录

按住boot键,按下reset键并松掉,这时候就可以松掉boot键了,点击编译并上传。静静等待上传成功。

运行

手机连接wifi,你也可以使用#define MANUAL_INPUT 改成手动输入wifi名称和密码。

wifi名字:AP_Network_SSID
wifi密码:AP_Password

V7RC设置RTSP地址和端口,默认rtsp://192.168.1.1:554。
cgi-bin_mmwebwx-bin_webwxgetmsgimg_&MsgID=46029422855082144&skey=@crypt_3db883.jpg

视频展示效果

converted1.gif

2 畅想

要是可以接多个摄像头或者安信可的雷达模块,那是不是就可以测距了。但目前最主要的还是要提高帧率。

3 结论

可以但没必要。小安派BW21-CVB-Kit整体的可玩性还是比较高的。后续有新想法会继续更新。

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

使用道具 举报

视频是不是飞了?没看到呀
昨天 11:34
HaydenHu 发表于 2025-3-25 11:16
视频是不是飞了?没看到呀

误点了保存编辑,结果直接发布了。现在已经添加了。上传本地视频会失败,转成动图了
这个软件看起来有点高大上的感觉
昨天 11:40
WT_0213 发表于 2025-3-25 11:34
这个软件看起来有点高大上的感觉

我也是在看到官方提供的示例上看到的V7RC
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 28168 个
  • 话题数: 39948 篇