边缘计算+WEB端应用融合:AI行为识别智能监控系统搭建指南 -- 边缘设备图像识别及部署(二)_ai 边缘 识别 系统(1)

YunYan_V1.0采用C++编写,核心采用的是yolov5的图像识别能力,支持多线程的图像识别,充分调用RK3588的三个NPU进行图像识别。并且利用zlmediakit将对视频图像的读推流进行了高度集成。以下是代码的大致思路:

Created with Raphaël 2.3.0

开始

读取配置文件

初始化模型、视频解码器、视频编码器、线程池

解码帧画面推送至识别线程池

从识别线程池中获取识别结果

绘制检测框、识别预警并保留视频、帧画面推流

运行不正常?

结束

yes

no

原始视频信号

其中有一个问题就是怎么获取原始的视频流信息?我个人在开发中主要是获取三种流方式:
方式1:模拟视频流
模拟是通过mediamtx和ffmpeg实现的,通过一台局域网内的设备进行模拟信号的输送就可以实现获取rtsp流的目的,我自己用的就是闲置的树莓派
mediamtx下载地址:https://github.com/bluenviron/mediamtx/releases
ffmpeg官网:https://ffmpeg.org/ffmpeg.html,ffmpeg网上有很多安装教程可以根据自身系统版本搜索。

nohup ./mediamtx mediamtx.yml > mediamtx.log 2>&1 &
nohup ffmpeg -re -stream_loop -1 -i /home/medias/test.mp4 -vcodec copy -acodec copy -b:v 5M -f rtsp -rtsp_transport tcp rtsp://localhost:8554/live.sdp > testffmpeg.log 2>&1 &

rtsp://192.168.124.31:8554/live.sdp

方式2:网络摄像头原始视频流【海康设备】

rtsp://admin:XXXXXX@192.168.124.38:554/h265/ch1/main/av_stream

方式3:网络录像机原始视频流【海康设备】

rtsp://admin:XXXXXXX@192.168.124.29:554/Streaming/Channels/101

部分核心代码

以下是部分 核心代码片

  1. 创建线程池
// 创建线程池
yolo_thread_pool = new Yolov5ThreadPool(); 
// 初始化线程池
// 参数1:模型文件地址
// 参数2:线程数量
// 参数3:非极大值抑制
// 参数4:置信度
// 参数5:模型标签文件路径
// 参数6:标签数量 
yolo_thread_pool->setUp(model_path, num_threads, NMS_threshold, box_threshold, model_label_file_path, obj_class_num); 

  1. 定义解码器
MppDecoder \*decoder = new MppDecoder();  // 创建解码器
decoder->Init(video_type, app_ctx.source_frame_rate, &app_ctx); // 初始化解码器
// mpp在每次解析后都会回调mpp\_decoder\_frame\_callback方法
decoder->SetCallback(mpp_decoder_frame_callback); // 设置回调函数,用来处理解码后的数据
app_ctx.decoder = decoder;

  1. 解码后处理
// 这里利用了rk3588自带的rga进行颜色通道的转换:YUV420SP -> RGB888
// 也可以使用opencv
origin = wrapbuffer\_fd(fd, width, height, RK_FORMAT_YCbCr_420_SP, width_stride, height_stride);
src = wrapbuffer\_fd(mpp_frame_fd, width, height, RK_FORMAT_YCbCr_420_SP, width_stride, height_stride);
cv::Mat origin_mat = cv::Mat::zeros(height, width, CV_8UC3);
rga\_buffer\_t rgb_img = wrapbuffer\_virtualaddr((void \*)origin_mat.data, width, height, RK_FORMAT_RGB_888);
imcopy(origin, rgb_img);
// 提交推理任务给线程池
yolo_thread_pool->submitTask(origin_mat, job_cnt++);

  1. 获取处理结果并绘制预警
std::vector<Detection> objects;
// 获取推理结果
auto ret_code = yolov5_thread_pool->getTargetResultNonBlock(objects, result_cnt);
// 遍历检测结果并且进行判断
for (const auto &object : objects)
{
    auto iter = ctx->labels_map.find(object.className);
    // 设置参数判断是否全图警戒,1为全图
    bool temp_ret = true;
    if (ctx->enable_region == 1 && ctx->g_ploygon.size() > 0)
    {
        Point p = {
            object.box.x + object.box.width / 2,
            object.box.y + object.box.height / 2};
        // 判断是否在预警区域中
        temp_ret = isInside(ctx->g_ploygon, p);
    }
    double value = iter->second;
    // 判断识别对象是否在识别要素中,同时判断要素是否在警戒区域中,执行度大于设定值
    if (iter != ctx->labels_map.end() && temp_ret && object.confidence >= value)
    {
        cv::rectangle(img, object.box, cv::Scalar(255, 0, 0), 2);
        // class name with confidence
        std::string draw_string = object.className + " " + std::to\_string(object.confidence);
        cv::putText(img, draw_string, cv::Point(object.box.x, object.box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 1,
                    cv::Scalar(255, 0, 0), 2);
        // 在迭代中发现了存在异常的标记,进行临时变量标记,此变量可能会在过程中重复赋值。
        if_warning_hold = true;
    }
    else
    {
        cv::rectangle(img, object.box, object.color, 2);
        // class name with confidence
        std::string draw_string = object.className + " " + std::to\_string(object.confidence);
        cv::putText(img, draw_string, cv::Point(object.box.x, object.box.y - 5), cv::FONT_HERSHEY_SIMPLEX, 1,
                    cv::Scalar(255, 0, 255), 2);
    }
}

  1. 检测结果推流
 // mk的参数初始化
char \*ini_path = mk\_util\_get\_exe\_dir(ctx->mk_file_path.c\_str());
mk_config config = {
        .thread_num = 10,
        .log_level = 0,
        .log_mask = LOG_CONSOLE,
        .log_file_path = NULL,
        .log_file_days = 0,
        .ini_is_path = 1,
        .ini = ini_path,
        .ssl_is_path = 1,
        .ssl = NULL,
        .ssl_pwd = NULL
};

// memset(&config, 0, sizeof(mk\_config));
// config.log\_mask = LOG\_CONSOLE;
// 初始化环境,调用该库前需要先调用此函数
mk\_env\_init(&config);
mk\_free(ini_path);
// 在端口80上启动HTTP服务器
if (ctx->enable_http == 1)
    mk\_http\_server\_start(ctx->push_http_port, 0);
// 在端口554上启动RTSP服务器
if (ctx->enable_rtsp == 1)
    mk\_rtsp\_server\_start(ctx->push_rtsp_port, 0);
// 在端口1935上启动RTMP服务器
if (ctx->enable_rtmp == 1)
    mk\_rtmp\_server\_start(ctx->push_rtmp_port, 0);
if (ctx->enable_rtc == 1)
    mk\_rtc\_server\_start(ctx->push_rtc_port);
// 创建一个新的Codeium播放器
ctx->player = mk\_player\_create();
ctx->stream_url = url;
// 设置处理播放事件的回调函数
mk\_player\_set\_on\_result(ctx->player, on_mk_play_event_func, ctx);
// 设置播放被异常中断的回调
mk\_player\_set\_on\_shutdown(ctx->player, on_mk_shutdown_func, ctx);
// 播放来自提供的RTSP URL的视频流
mk\_player\_play(ctx->player, ctx->stream_url);
// 推流
ret = mk\_media\_input\_h264(ctx->media, enc_data, enc_data_size, millis, millis);

根据以上代码无法完整完成编码工作,由于本专栏主要方向是关于边缘计算设备和WEB端应用的融合,实现AI行为识别的智能监控系统。所以不会对终端设备的实际使用技术及代码原理进行特别详细的描述。如果读者有需要可以留言,我可以出一个关于RK3588的独立专栏。
其实本质上边缘计算设备无论是选择RK3588,还是带有GPU的主机都可以,本项目是为了减少项目的搭建预算所以找的更便宜的解决方案,同时也能符合国产化、信创需要。

配置文件清单

以下是YunYan_V1.0提供的参数清单:

[YUNYAN]
# 进程的唯一编号,这是一个uid
CEProcessId = b6cf4e7e-b952-4bf5-be29-0225f71d7f57
# 模型路径,必须是完整路径yolo5s\_cx\_200
ModelPath = /home/YunYan-V1/weights/yolov5s.rknn
# IOU
NMSThreshold = 0.65
# 置信度
BoxThreshold = 0.4
# 模型的labels文件路径
ModelLabelsFilePath = /home/YunYan-V1/coco_80_labels_list.txt
# 推理类型数量 yolov5 80
ObjClassNum = 80
# 流地址
StreamUrl = rtsp://192.168.124.31:8554/live3.sdp
# 视频流类型264/265,default 264,265格式目前不支持
VideoType = 264
# 原始视频帧率
SourceFrameRate = 25
# 启动监测的线程数,default 12
NumThreads = 20
# 是否开启hls播放功能,default 0,需要和EnableHttp同时开启
EnableHls = 0
# 是否开启hls播放功能,default 0
EnableHttp = 0
# http推流端口,default 80
PushHttpPort = 80
# 是否开启rtsp推流
EnableRtsp = 1
# rstp推流端口,default 554
PushRtspPort = 554
# 是否开启rtsp推流
EnableRtmp = 0
# rtmp推流端口,default 1935
PushRtmpPort = 1935
# 是否开启rtc
EnableRtc = 0
# rtc推流端口,default 8000
PushRtcPort = 8001
# 推流地址设定1
PushPathFirst = yunyan-live
# 推流地址设定2
PushPathSecond = test


**自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

**深知大多数大数据工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!**

**因此收集整理了一份《2024年大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。**
![img](https://img-blog.csdnimg.cn/img_convert/fea99dcb6e70227756b2cb9ae1ea784b.png)
![img](https://img-blog.csdnimg.cn/img_convert/33059de28615be4a68e6233402674e85.png)
![img](https://img-blog.csdnimg.cn/img_convert/f23be0db12e663031e85f4226d320ce2.png)
![img](https://img-blog.csdnimg.cn/img_convert/6925bcf8aa985f3dc4c117d3c130c7d4.png)
![img](https://img-blog.csdnimg.cn/img_convert/728630e39540d2239919bfe938b835c6.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上大数据开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注大数据获取)**
![img](https://img-blog.csdnimg.cn/img_convert/abaf7fd5d80819e7883658c0c8d016fd.png)

04)]
[外链图片转存中...(img-7MpmKXIY-1712913290604)]
[外链图片转存中...(img-shE1QKfs-1712913290604)]
[外链图片转存中...(img-FnFQP71V-1712913290604)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上大数据开发知识点,真正体系化!**

**由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新**

**如果你觉得这些内容对你有帮助,可以添加VX:vip204888 (备注大数据获取)**
[外链图片转存中...(img-4Xzhuhtu-1712913290605)]

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值