报警输出完成

This commit is contained in:
2025-11-19 15:52:19 +08:00
parent 8530821351
commit 18885439e6
6 changed files with 317 additions and 64 deletions

Binary file not shown.

View File

@@ -3,7 +3,8 @@
1.推流摄像头画面,使用UDP原生协议进行推流,交由YOLO模型进行处理
2.接收YOLO传来的坐标和度数据
3.根据获取到的数据绘制边框和相应数据
4.将绘制完毕的视频流继续推流至RTSP服务器用于输出
4.根据距离信息进行报警和图片视频保存
5.将绘制完毕的视频流继续推流至RTSP服务器用于输出
*/
#include <iostream>
@@ -55,6 +56,8 @@ mutex alertMutex; // 保护alertQueue的互斥锁
condition_variable alertcv; // 通知报警线程有新任务
queue<nlohmann::json> alertQueue; // 存放解析后的数据
std::atomic<bool> alertWorkerRunning{false}; // 工作线程运行标志
atomic<bool> outPutMode = false; // 保存报警输出false--电平
// atomic<bool> currentFrameHasDanger{false}; // 是否进行了报警
// mqtt初始化
void MqttInit();
@@ -72,8 +75,14 @@ void mainLoop(VideoCapture &cap, FILE *pipe);
void getMsgCallback(mqtt::const_message_ptr msg);
// 绘制矩形方框和深度信息
void drawRect(int x, int y, int w, int h, double distance);
// 获取报警距离
// 报警线程
void warnThread();
// 获取报警距离和输出模式
bool GetDistance();
// 调用报警输出程序
void setGPIOLevel(int level);
// // 状态机
// void warnStatus();
int main()
{
@@ -102,6 +111,135 @@ int main()
return 0;
}
// 调用报警输出程序
void setGPIOLevel(int level)
{
string cmd = "echo 'orangepi' | sudo -S /home/orangepi/RKApp/GPIOSignal/bin/sendGpioSignal " + to_string(level);
system(cmd.c_str());
}
// // 状态机
// void warnStatus()
// {
// thread([]()
// {
// bool isAlarm = false;
// auto lastDangerTime = chrono::steady_clock::now();
// while(alertWorkerRunning.load())
// {
// } });
// }
// 报警线程
void warnThread()
{
// 开启报警线程
thread([]()
{
//状态变量
bool isAlarming = false; //报警状态
auto lastDangerTime = chrono::steady_clock::now(); //上次报警时间
//读取配置设置初始状态
GetDistance();
int normalLevel = outPutMode?0:1; //false:正常高,输出低,true:正常低,输出高
int alarmLevel = outPutMode?1:0; //报警输出,true:报警高,false:报警低
cout << "normalLevel = " << normalLevel <<",alarmLevel = " << alarmLevel << endl;
//设置初始状态为正常状态
setGPIOLevel(normalLevel);
while (alertWorkerRunning.load())
{
unique_lock<mutex> lk(alertMutex);
// 等待条件,队列非空或者收到停止信号
if(isAlarming)
{ //如果触发报警,就每每100ms检查一次
alertcv.wait_for(lk,100ms,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
}
else{
//没有触发报警,就死等
alertcv.wait(lk,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
}
//如果线程应退出切队列为空,退出循环
if(alertQueue.empty() && !alertWorkerRunning.load())
break;
//当前帧是否触发报警
bool currentFrameHasDanger = false;
//处理队列中的所有信号
while(!alertQueue.empty())
{
auto job = move(alertQueue.front());
alertQueue.pop(); //释放空指针
//解锁,以便于增加队列任务
lk.unlock();
//报警处理函数
try
{
//获取报警距离
GetDistance();
// 更新电平定义(防止运行时修改了配置文件)
normalLevel = outPutMode ? 0 : 1;
alarmLevel = outPutMode ? 1 : 0;
for(auto&ii:job)
{
if(ii["distance"] <= dis.danger)
{ //触发警报
currentFrameHasDanger = true;
}
}
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
lk.lock(); //重新上锁,以继续处理下个任务
}
//逻辑处理,状态机
if(currentFrameHasDanger)
{
lastDangerTime = chrono::steady_clock::now();
if(!isAlarming)
{
//刚进入报警状态
isAlarming = true;
setGPIOLevel(alarmLevel);
}
}
else
{
//当前帧没有危险,检测是否需要恢复
if(isAlarming)
{
auto now = chrono::steady_clock::now();
auto dur = chrono::duration_cast<chrono::seconds>(now - lastDangerTime).count();
if(dur >= 2)
{//超过两秒恢复正常
isAlarming=false;
setGPIOLevel(normalLevel);
}
}
}
} })
.detach();
}
// 获取报警距离
bool GetDistance()
{
@@ -123,6 +261,12 @@ bool GetDistance()
dis.warn = stoi(line.substr(sizeof("MID_THRESHOLD=") - 1));
else if (line.find("MAX_DISTANCE=") != string::npos)
dis.safe = stoi(line.substr(sizeof("MAX_DISTANCE=") - 1));
else if (line.find("outPutMode:") != string::npos)
{
// 确认输电平模式
string val = line.substr(sizeof("outPutMode:"));
outPutMode = (val == "true");
}
}
rf.Close();
@@ -148,7 +292,7 @@ void drawRect(int x, int y, int w, int h, double distance)
sca = Scalar(0, 255, 0);
rectangle(handleFrame, r, sca, 2);
putText(handleFrame,to_string(distance),Point(x,y),FONT_HERSHEY_SIMPLEX,0.35,Scalar(0,0,0));
putText(handleFrame, to_string(distance), Point(x, y), FONT_HERSHEY_SIMPLEX, 0.35, Scalar(0, 0, 0));
}
// mqtt初始化
@@ -163,43 +307,10 @@ void MqttInit()
client.connect()->wait();
client.subscribe(Topic, Qos)->wait();
// 开启报警线程
thread([]()
{
while (alertWorkerRunning.load())
{
unique_lock<mutex> lk(alertMutex);
// 等待条件,队列非空或者收到停止信号
alertcv.wait(lk,[](){
return !alertQueue.empty() || !alertWorkerRunning.load();});
alertWorkerRunning = true;
//如果线程应退出切队列为空,退出循环
if(alertQueue.empty() && !alertWorkerRunning.load())
break;
//处理队列中的所有信号
while(!alertQueue.empty())
{
auto job = move(alertQueue.front());
alertQueue.pop(); //释放空指针
//解锁,以便于增加队列任务
lk.unlock();
//报警处理函数
try
{
}
catch(const std::exception& e)
{
std::cerr << e.what() << '\n';
}
lk.lock(); //重新上锁,以继续处理下个任务
}
} })
.detach();
// 开启线程
warnThread();
}
// mqtt接收订阅消息的回调
@@ -316,9 +427,8 @@ bool processFrame(VideoCapture &cap, FILE *pipe, Mat &frame, int64 &count, chron
// 拷贝视频帧
handleFrame = frame;
// 读取最新检测:短锁获取并将结果拷贝到本地变量
vector<Dection> destCopy;
// 读取最新检测:短锁获取并将结果拷贝到本地变量
{
lock_guard<mutex> lk(detMutex);
destCopy = latestDection; // 复制到本地后释放锁
@@ -330,7 +440,11 @@ bool processFrame(VideoCapture &cap, FILE *pipe, Mat &frame, int64 &count, chron
drawRect(ii.x, ii.y, ii.w, ii.h, ii.distance);
}
latestDection.clear();
// 短锁进行清除
{
lock_guard<mutex> lk(detMutex);
latestDection.clear();
}
// 可选:显示窗口
// imshow("测试画面", frame);