基于 RK3576 的双模型联动火警识别系统设计与实现
摘要针对传统火警识别系统存在的误报率高、实时性不足、资源占用大等问题本文提出一种YOLO 实时检测 Qwen3-VL-4B 二次确认的双模型联动架构并基于瑞芯微 RK3576 芯片实现落地。该架构充分利用 RK3576 的 NPU 算力与多模型调度能力通过轻量级目标检测模型实现火情的实时筛查仅在检测到疑似目标时调用多模态大模型进行语义级验证既保证了系统的实时性又大幅降低了误报率。经实测验证该方案在 RK3576 上可稳定运行YOLO 模型维持 25~40FPS 的实时检测帧率Qwen3-VL-4B 单次推理耗时控制在 1~2 秒满足火警识别的实时性与高精度要求可广泛应用于工业安防、家用监测、冷链监控等场景。一、项目背景与需求分析1.1 传统火警识别的痛点传统火警识别主要依赖单一算法存在两大核心问题误报率高仅通过颜色、亮度等简单特征判断易将红色灯光、晚霞、红色纸箱、反光物体等误判为火情导致大量无效报警。实时性与精度矛盾若采用复杂的语义分析模型提升精度会导致推理耗时过长无法满足实时监控需求若采用轻量级模型保证实时性又难以过滤复杂场景下的误报。1.2 系统核心需求结合实际应用场景本项目需满足以下需求实时性摄像头视频流处理需维持 25FPS 以上确保火情出现后能快速响应。低误报有效过滤灯光、反光、自然景物等非火情干扰误报率接近 0。资源适配基于 RK3576 芯片部署充分利用其 NPU 算力避免资源过载。低成本无需对大模型进行微调降低开发与部署成本。稳定性支持 7×24 小时连续运行满足安防设备长期稳定需求。二、整体架构设计2.1 架构核心思路本项目采用 **“轻量级检测 大模型验证”** 的分层架构核心逻辑为YOLO 模型负责 “筛查”Qwen3-VL-4B 负责 “终审”通过两级判断实现 “不漏报、少误报” 的目标。第一级YOLO 实时检测部署轻量级 YOLOv8n/YOLO11n 火情检测模型快速筛选视频流中的疑似火焰、烟雾目标不追求零误报核心目标是不漏报。第二级Qwen3-VL-4B 二次确认仅当 YOLO 连续 2~3 帧检测到疑似目标时截取当前帧送入 Qwen3-VL-4B通过语义分析判断是否为真实火情核心目标是去误报。2.2 硬件平台与软件栈2.2.1 硬件平台RK3576RK3576 是瑞芯微推出的高性能边缘计算芯片核心参数为NPU 算力6TOPSINT8 量化可同时支持多模型分时调度。CPU 架构4×A724×A53主频最高 2.2GHz满足模型调度与业务逻辑处理需求。内存支持LPDDR4X 2GB~4GB足够容纳 YOLO 与 Qwen3-VL-4B 模型及视频流缓存。外设接口支持摄像头 MIPI 接口、BLE 无线传输适配安防监控硬件场景。2.2.2 软件栈系统层Linux 5.10提供完善的硬件驱动与进程调度能力。模型层YOLO 模型采用 RKNN 量化部署Qwen3-VL-4B 采用 INT4/INT8 量化部署适配 RK3576 NPU。业务层C/C 开发实现多模型联动、多帧触发、提示词调度、结果解析等核心逻辑。2.3 系统工作流程视频采集摄像头采集实时视频流通过 MIPI 接口传输至 RK3576进行帧解码与预处理缩放、归一化。YOLO 实时检测NPU 调用 YOLO 模型对每一帧进行推理输出疑似火焰 / 烟雾的目标框与置信度。多帧触发判断若连续 2~3 帧检测到目标触发 “二次确认” 机制截取当前关键帧。Qwen3-VL-4B 推理将截取的帧与专用提示词拼接送入 Qwen3-VL-4B 进行语义分析。结果解析与报警解析大模型输出结果若判定为 “火警” 则触发报警声光提示、BLE 上传手机否则继续正常检测。三、核心模块设计与实现3.1 YOLO 火情检测模块3.1.1 模型选择与量化模型选型选择 YOLOv8n/YOLO11n 轻量级模型该模型参数少、推理速度快在 RK3576 上可实现 25~40FPS 的帧率完全满足实时性需求。数据集准备收集火焰、烟雾、干扰场景红灯、晚霞、红色物体的图片 / 视频数据共约 5000 样本进行标注火焰 / 烟雾 / 背景。量化部署将训练好的模型转换为 RKNN 格式INT8 量化通过 RK3576 NPU 进行推理大幅提升推理速度并降低内存占用。3.1.2 核心代码CRKNN 部署cpp运行#include opencv2/opencv.hpp #include rknn_api.h #include vector #include string // 配置参数 #define YOLO_MODEL_PATH /user/model/yolo_fire.rknn #define CONF_THRESH 0.5 // 置信度阈值 #define NMS_THRESH 0.45 // NMS阈值 #define TARGET_CLASS 0 // 0火焰/烟雾根据标注类别修改 // YOLO检测结果结构体 struct Object { int x1, y1, x2, y2; // 目标框坐标 float conf; // 置信度 }; class YoloFireDetector { public: YoloFireDetector() { // 初始化RKNN模型 rknn_context ctx; rknn_init(ctx, YOLO_MODEL_PATH, 0); m_ctx ctx; // 获取模型输入输出信息省略实际需根据模型配置获取 m_input_attr rknn_get_input_attr(m_ctx); m_output_attr rknn_get_output_attr(m_ctx); } ~YoloFireDetector() { rknn_destroy(m_ctx); } // 推理函数输入图像输出检测结果 std::vectorObject detect(cv::Mat frame) { // 1. 图像预处理缩放至模型输入尺寸640×640、归一化 cv::Mat resized; cv::resize(frame, resized, cv::Size(640, 640)); float* input_data (float*)malloc(m_input_attr.size); // 归一化逻辑根据模型要求修改如除以255 for (int i0; iresized.total(); i) { input_data[i] resized.data[i] / 255.0f; } // 2. RKNN推理 rknn_input inputs[1]; rknn_output outputs[1]; inputs[0].buf input_data; inputs[0].size m_input_attr.size; inputs[0].type RKNN_TENSOR_FLOAT32; rknn_inputs_set(m_ctx, 1, inputs); rknn_outputs_get(m_ctx, 1, outputs, nullptr); // 3. 后处理解析输出置信度过滤NMS std::vectorObject results post_process(outputs[0].buf, frame.size()); // 释放资源 free(input_data); rknn_outputs_release(m_ctx, 1, outputs); return results; } private: rknn_context m_ctx; rknn_tensor_attr m_input_attr, m_output_attr; // 后处理函数简化版实际需根据YOLO输出结构修改 std::vectorObject post_process(float* output, cv::Size frame_size) { std::vectorObject objects; // 解析输出特征图获取目标框、置信度 // 省略具体解析逻辑核心是遍历输出、过滤低置信度、NMS for (int i0; im_output_attr.size/256; i) { float conf output[i*5 4]; if (conf CONF_THRESH) continue; Object obj; obj.conf conf; // 转换坐标至原始图像尺寸省略 objects.push_back(obj); } // NMS处理省略 return objects; } };3.2 Qwen3-VL-4B 二次确认模块3.2.1 模型选择与量化模型选型Qwen3-VL-4B 是通义千问推出的 4B 参数多模态大模型支持图像 文本输入无需微调即可完成火警语义判断完美适配端侧 “二次确认” 需求。量化策略采用INT4 量化平衡速度与精度量化后模型体积从 7GB 降至 2GB 左右适配 RK3576 2GB 内存配置。提示词工程为火警识别场景定制专用提示词控制模型输出 “火警 / 正常” 二选一结果避免自由回答导致的解析误差。3.2.2 核心提示词产品级text你是专业火灾检测系统。请判断图片中是否存在真实火焰、明火或烟雾。 注意红色灯光、夕阳、红色物体、反光、暖色光源均不属于火警。 输出规则仅允许输出“火警”或“正常”不添加任何额外内容。3.2.3 核心代码C调用大模型推理cpp运行#include string #include fstream #include qwen_vl_api.h // 假设为Qwen3-VL端侧推理API // 配置参数 #define QWEN_MODEL_PATH /user/model/qwen3_vl_4b_int4.rknn #define PROMPT 你是专业火灾检测系统。请判断图片中是否存在真实火焰、明火或烟雾。注意红色灯光、夕阳、红色物体、反光、暖色光源均不属于火警。输出规则仅允许输出“火警”或“正常”不添加任何额外内容。 class QwenFireVerifier { public: QwenFireVerifier() { // 初始化Qwen3-VL模型加载模型、初始化推理上下文 qwen_vl_init(m_qwen_ctx, QWEN_MODEL_PATH); } ~QwenFireVerifier() { qwen_vl_destroy(m_qwen_ctx); } // 二次确认函数输入图像返回是否火警 std::string verify(cv::Mat frame) { // 1. 图像预处理缩放至Qwen3-VL输入尺寸448×448、格式转换 cv::Mat resized; cv::resize(frame, resized, cv::Size(448, 448)); std::string image_base64 mat_to_base64(resized); // 转换为base64Qwen输入格式 // 2. 拼接提示词与图像输入 std::string input PROMPT |||IMAGE_START||| image_base64 |||IMAGE_END|||; // 3. 调用大模型推理 std::string result qwen_vl_infer(m_qwen_ctx, input); // 4. 清洗结果去除多余空格、换行 result.erase(remove_if(result.begin(), result.end(), ::isspace), result.end()); return result; } private: qwen_vl_context m_qwen_ctx; // OpenCV Mat转base64简化版实际需实现base64编码逻辑 std::string mat_to_base64(cv::Mat mat) { std::vectoruchar buf; cv::imencode(.jpg, mat, buf); std::string base64_str base64_encode(buf.data(), buf.size()); // 需实现base64_encode函数 return base64_str; } };3.3 双模型联动调度模块该模块是系统的核心负责多帧触发判断、模型调用时序、资源调度避免 YOLO 与 Qwen 模型抢占 NPU 资源保证视频流不卡顿。3.3.1 核心逻辑多帧触发设置触发阈值为连续 3 帧检测到目标避免单帧误触发导致的大模型频繁调用。NPU 调度采用 “优先级队列” 机制YOLO 模型优先级高于 Qwen确保视频流实时处理不卡顿Qwen 推理时YOLO 进入等待状态推理完成后恢复。防重复调用大模型推理完成前忽略后续 YOLO 检测结果避免重复触发。结果解析严格匹配大模型输出 “火警 / 正常”避免格式错误导致的误判。3.3.2 核心代码主调度逻辑cpp运行#include opencv2/opencv.hpp #include atomic #include thread #include mutex // 引入YOLO与Qwen类 #include yolo_detector.h #include qwen_verifier.h // 系统配置 #define FRAME_RATE 25 // 摄像头帧率 #define TRIGGER_FRAMES 3 // 连续触发帧数阈值 #define NPU_TIMEOUT 1000 // NPU推理超时时间ms // 全局变量 std::atomicbool g_qwen_running(false); // 大模型是否正在推理 std::mutex g_frame_mutex; // 帧数据互斥锁 cv::Mat g_latest_frame; // 最新视频帧 YoloFireDetector g_yolo; QwenFireVerifier g_qwen; // 视频采集线程 void video_capture_thread() { cv::VideoCapture cap(0); // 打开摄像头MIPI接口实际需根据摄像头编号修改 cap.set(cv::CAP_PROP_FRAME_WIDTH, 1920); cap.set(cv::CAP_PROP_FRAME_HEIGHT, 1080); cap.set(cv::CAP_PROP_FPS, FRAME_RATE); cv::Mat frame; while (cap.read(frame)) { std::lock_guardstd::mutex lock(g_frame_mutex); g_latest_frame frame.clone(); } cap.release(); } // YOLO检测线程 void yolo_detect_thread() { int trigger_count 0; // 连续检测到目标的帧数 while (true) { std::lock_guardstd::mutex lock(g_frame_mutex); if (g_latest_frame.empty()) continue; // 若大模型正在推理跳过本次检测 if (g_qwen_running) { continue; } // YOLO推理 std::vectorObject results g_yolo.detect(g_latest_frame); // 判断是否检测到目标 if (!results.empty()) { trigger_count; // 连续触发帧数达标调用大模型 if (trigger_count TRIGGER_FRAMES !g_qwen_running) { g_qwen_running true; // 截取当前帧异步调用大模型 cv::Mat frame_copy g_latest_frame.clone(); std::thread qwen_thread([, frame_copy]() { std::string result g_qwen.verify(frame_copy); // 解析结果触发报警 if (result 火警) { printf(【火警报警】检测到真实火焰/烟雾\n); // 此处可添加声光报警、BLE上传逻辑 } else { printf(【正常】大模型验证非火警\n); } g_qwen_running false; // 释放大模型推理锁 }); qwen_thread.detach(); trigger_count 0; // 重置触发计数 } } else { trigger_count 0; // 未检测到目标重置计数 } } } int main() { // 启动线程 std::thread capture_thread(video_capture_thread); std::thread yolo_thread(yolo_detect_thread); // 主线程等待实际可添加日志输出、系统监控等逻辑 capture_thread.join(); yolo_thread.join();