#include "PreProcessFn.h" #include "PreProcessModel.h" #pragma comment(lib,"libmysql") #include #include #include #include #include #include #include "iostream" #include #include #include #include #include "cls/CRabbitmqClient.h" #include #include #include "base/base64.h" #include "cls/warningfile.h" #include // C++17 中的文件系统库 #include #include #include namespace fs = boost::filesystem; std::mutex mtx;// 全局互斥锁,用于保护队列 PreProcessModel ppm = PreProcessModel(); PreProcessFn::PreProcessFn() { } PreProcessFn::~PreProcessFn(void) { } // 创建录像异步任务的 future 对象 std::future video_writer_future; int* stringToIntArray(std::string input) { for (int i = 0; i < input.size(); i++) { if (input[i] == ';') { input[i] = ','; } } std::vector result; std::stringstream ss(input); std::string token; // 从输入字符串中解析整数,并存储到结果向量中 while (getline(ss, token, ',')) { result.push_back(std::stoi(token)); } // 动态分配内存以存储整数数组 int* beltregion = new int[result.size()]; // 将结果向量中的整数复制到动态分配的数组中 for (int i = 0; i < result.size(); i++) { beltregion[i] = result[i]; } return beltregion; } std::vector stringToPoints(const std::string& input) { std::vector points; std::stringstream ss(input); int x, y; char discard; while (ss >> x >> discard >> y >> discard) { points.push_back(cv::Point(x, y)); // Check for the ';' delimiter if (ss.peek() == ';') { ss.ignore(); } } return points; } // 获取当前时间并格式化为指定格式的字符串 std::string getCurrentDateTime(const std::string& format) { // 获取当前时间 time_t now = time(0); // 转换为本地时间 tm* local_time = localtime(&now); // 定义存储时间字符串的缓冲区 char buffer[80]; // 格式化时间为字符串 strftime(buffer, sizeof(buffer), format.c_str(), local_time); // 返回格式化后的时间字符串 return std::string(buffer); } // 获取当前时间,包括毫秒 std::string getCurrentDateTimeWithMilliseconds(const std::string& format) { // 获取当前时间点 auto now = std::chrono::system_clock::now(); // 将时间点转换为时间戳 auto now_ms = std::chrono::time_point_cast(now); auto ms_part = now_ms.time_since_epoch().count() % 1000; // 转换为本地时间 std::time_t now_time = std::chrono::system_clock::to_time_t(now); std::tm* local_time = std::localtime(&now_time); // 定义存储时间字符串的缓冲区 char buffer[80]; // 格式化时间为字符串,包括毫秒 std::strftime(buffer, sizeof(buffer), format.c_str(), local_time); // 将毫秒部分添加到字符串中 std::string result(buffer); result += std::to_string(ms_part); return result; } //imgType 包括png bmp jpg jpeg等opencv能够进行编码解码的文件 std::string Mat2Base64(const cv::Mat& image, std::string imgType) { //Mat转base64 std::vector buf; cv::imencode(imgType, image, buf); std::string img_data = base64_encode(buf.data(), buf.size(), false); return img_data; } //imgType 包括png bmp jpg jpeg等opencv能够进行编码解码的文件 std::string Mat2Bin(const cv::Mat& image, std::string imgType) { //Mat转base64 std::vector buf; cv::imencode(imgType, image, buf); std::string img_data = base64_encode(buf.data(), buf.size(), false); return img_data; } string fnWarningFileToJson(warningfile wf) { // 创建 Json::Value 对象 Json::Value root; root["coalCode"] = wf.getCoalCode(); root["cameraCode"] = wf.getCameraCode(); root["cameraName"] = wf.getCameraName(); root["analyse"] = wf.getAnalyse(); root["analyseResult"] = wf.getAnalyseResult(); root["warningTime"] = wf.getWarningTime(); root["recordFileName"] = wf.getRecordFileName(); root["recordImgFileName"] = wf.getrecordImgFileName(); root["rtspUrl"] = wf.getRtspUrl(); root["duration"] = wf.getDuration(); // 使用 Json::FastWriter 将 Json::Value 对象转换为 JSON 字符串 Json::FastWriter writer; return writer.write(root); } //创建文件夹 年 月 日 string fnCreateFileFolder(string hdPath) { // 获取当前系统时钟的当前时间点 auto now = std::chrono::system_clock::now(); // 将当前时间点转换为 time_t 类型 std::time_t time_now = std::chrono::system_clock::to_time_t(now); // 将 time_t 类型的时间转换为本地时间 std::tm local_time = *std::localtime(&time_now); std::string year_folder = std::to_string(local_time.tm_year + 1900); std::string month_folder = std::to_string(local_time.tm_mon + 1); std::string day_folder = std::to_string(local_time.tm_mday); std::string folder_path = hdPath + "/" + year_folder + "/" + month_folder + "/" + day_folder + "/"; // // 检查文件夹是否已存在 if (!fs::exists(folder_path.c_str())) { // 不存在则创建文件夹 fs::create_directories(folder_path.c_str()); //std::cout << "已创建文件夹:" << folder_path << std::endl; } return folder_path;//返回文件夹路径 } /// /// 判断结果比例 /// /// int fnJudeRatio(vector vec, int ftype,double ratio) { // 计算队列中 0 和 1 的数量 double count0 = 0;//0的个数 double count1 = 0;//1的个数 double vecSize = vec.size(); for (int i = 0; i < vec.size(); ++i) { if (vec[i] == 0) { count0++; } else { count1++; } } //cout << getCurrentDateTime1("%Y%m%d%H%M%S") << endl; /*cout << "------------" << endl; cout << count0 << endl; cout << count1 << endl;*/ // 计算比例 double ratio0 = count0 / vecSize; double ratio1 = count1 / vecSize; switch (ftype) { case 0: if (ratio0 >= ratio) { return 0; } else { return 1; } break; case 1: if (ratio1 >= ratio) { return 1; } else { return 0; } break; default: return -1; break; } } /// /// 录像并保存报警信息至MySql模块 /// void fnVideoRecordToMysql(Mat frame, int Alarm, VideoWriter& video_writer, std::chrono::system_clock::time_point start_time, warningfile wf, MYSQL* mysql, int _recordtime) { // 当前时间 double seconds = std::chrono::duration(std::chrono::system_clock::now() - start_time).count(); //cout << start_time << endl; //cout << current_time << endl; // 如果录制时间超过 10 秒,则停止录制 if (seconds >= _recordtime) { cout << "已录制 10 秒视频,停止录制" << endl; video_writer.release(); } else { video_writer.write(frame);//录像处理 } if (Alarm == 1)//报警信息保存至mysql { // 记录报警的时候,同时写入redis数据库 wf.setWarningTime(getCurrentDateTime("%Y-%m-%d %H:%M:%S")); // 构建插入 SQL 语句 std::stringstream ss; ss << "INSERT INTO alarmevent (AlarmType, AlarmName, CameraCode, AlarmState, AlarmPic, AlarmVideo, AlarmTime) VALUES ('" << wf.getAnalyse() << "', '" << wf.getAnalyseResult() << "', " << wf.getCameraCode() << ", '" << "0" << "', '" << wf.getrecordImgFileName() << "', '" << wf.getRecordFileName() << "', '" << wf.getWarningTime() << "')"; std::string query = ss.str(); // 执行插入语句 if (mysql_query(mysql, query.c_str())) { string err_string = mysql_error(mysql); cout << err_string << endl; } } } /// /// 录像并保存报警信息至MySql模块,录像为以前时间段 /// void fnVideoRecordToMysql2(vector vecVideo, int Alarm, VideoWriter& video_writer, warningfile wf, MYSQL* mysql) { for (int i = 0; i < vecVideo.size(); i++) { video_writer.write(vecVideo[i]);//录像处理 } video_writer.release(); if (Alarm == 1)//报警信息保存至mysql { // 记录报警的时候,同时写入redis数据库 wf.setWarningTime(getCurrentDateTime("%Y-%m-%d %H:%M:%S")); // 构建插入 SQL 语句 std::stringstream ss; ss << "INSERT INTO alarmevent (AlarmType, AlarmName, CameraCode, AlarmState, AlarmPic, AlarmVideo, AlarmTime) VALUES ('" << wf.getAnalyse() << "', '" << wf.getAnalyseResult() << "', '" << wf.getCameraCode() << "', '" << "0" << "', '" << wf.getrecordImgFileName() << "', '" << wf.getRecordFileName() << "', '" << wf.getWarningTime() << "')"; std::string query = ss.str(); // 执行插入语句 if (mysql_query(mysql, query.c_str())) { string err_string = mysql_error(mysql); cout << err_string << endl; } } } // 回调函数,用于将返回的数据存储在 std::string 中 size_t WriteCallback(void* contents, size_t size, size_t nmemb, void* userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } string join(const vector& sequence, const string& separator) { std::string result; for (size_t i = 0; i < sequence.size(); ++i) result += sequence[i] + ((i != sequence.size() - 1) ? separator : ""); return result; } /// /// 写入数据至redis模块 /// void fnWriteToRedis(redisContext*& context, string ipccode) { redisReply* reply; //检测redis是否连接,报警写入redis if (!context == NULL && !context->err) { // 记录报警的时候,同时写入redis数据库 std::string key = "camera::run::" + ipccode; std::string value = "1"; //写入redis reply = (redisReply*)redisCommand(context, "SET %s %s", key.c_str(), value.c_str()); if (reply == NULL) { printf("信息写入redis失败\n"); redisFree(context); } freeReplyObject(reply); } } /// @brief 视频流拉取处理 /// @param _rtspUrl 视频流源地址 /// @param queJC 未处理的视频流帧队列 void PreProcessFn::fnGetVideoMatToQueue(string rtspUrl,queue& queJC) { VideoCapture rtspStream(rtspUrl.c_str());// 连接RTSP流,软解码 //Ptr d_reader = cv::cudacodec::createVideoReader(rtspUrl); int count = 0; long currentFrame = 1; long skip_frame_num = skipN;//跳帧间隔设置(每1帧) while (!asyncStop) { //std::cout << "当前线程待处理队列数据数量0000:" << queJC.size() << std::endl; //cout << getCurrentDateTime("%Y%m%d%H%M%S") << endl; //cout << skip_frame_num << endl; try { if (queJC.size() > 500) { cout << "获取视频时,存在内存溢出风险!" << endl; } if (currentFrame % skip_frame_num == 0) //跳帧处理 { Mat frame; //cv::cuda::GpuMat d_frame; //////软解码 if (!rtspStream.isOpened()) { rtspStream.open(rtspUrl.c_str()); if (!rtspStream.isOpened()) { std::this_thread::sleep_for(std::chrono::seconds(5));// 等待一段时间后重试连接 //log.Log(rtspUrl + ":重启连接失败,请等待" + "\n"); continue; } cout << rtspUrl + ":重启连接完成," + to_string(count) + "\n" << endl; //log.Log(rtspUrl + ":重启连接完成," + to_string(count) + "\n"); count = 0;//重连计数复位 } //读取视频帧 if (!rtspStream.read(frame)) { if (count > 3) { cout << rtspUrl + ":连接释放,重新连接!" + "\n"; //log.Log(rtspUrl + ":连接释放,重新连接!" + "\n"); rtspStream.release(); //rtspStream.open(rtspUrl.c_str()); count = 0;//重连计数复位 } else { std::this_thread::sleep_for(std::chrono::seconds(1));// 延迟1秒再去取帧 cout << rtspUrl + ":" + to_string(count) << endl; count++; } continue; } //// //硬解码 //读取视频帧 // if (!d_reader->nextFrame(d_frame)) // { // d_reader = cv::cudacodec::createVideoReader(rtspUrl); // continue; // } // d_frame.download(frame); // //cout << "gpu" << endl; // d_frame.release(); /// if (frame.empty()) { std::cout << "空帧,废弃" << std::endl; continue; } //加锁,防止别的系统操作这段内存 std::unique_lock lck(mtx); queJC.push(frame); // 推入待处理队列 lck.unlock(); //cv::imwrite("./img/" + std::to_string(currentFrame)+".jpg", frame); //cv::imshow(rtspUrl, queJC.front());//展示帧图片 //cv::imshow(rtspUrl, frame);//展示帧图片 //waitKey(5); //std::this_thread::sleep_for(std::chrono::milliseconds(100));// 延迟等待一段时间 frame.release(); } if (currentFrame > 10000) { currentFrame = 0; } currentFrame++; } catch (const std::exception& ex) { std::string errorMessage = "拉流失败-"; errorMessage += ex.what(); continue; } } //d_reader.release(); rtspStream.release(); } /// /// 连接并校验 Redis 服务器密码 /// /// /// /// /// /// bool connectToRedis(const char* server, int port, const char* password, redisContext*& context) { // 连接 Redis 服务器 context = redisConnect(server, port); if (context == nullptr || context->err) { std::cerr << "连接redis服务端失败!" << std::endl; return false; } //// 校验密码 //redisReply* reply = (redisReply*)redisCommand(context, "AUTH %s", password); //if (reply == NULL) { // std::cerr << "连接校验失败!" << std::endl; // redisFree(context); // return false; //} //else { // // 检查回复以确定是否鉴权成功 // if (reply->type == REDIS_REPLY_ERROR && strcmp(reply->str, "OK") != 0) { // std::cerr << "密码错误: " << reply->str << std::endl; // freeReplyObject(reply); // redisFree(context); // return false; // } // freeReplyObject(reply); //} return true; } std::string jsontostr(Json::Value& json) { string return_str; if(!json.isNull()&&!json.empty()) { for (int i = 0; i < json.size(); i++) { return_str += json[i].asString()+","; } if (!return_str.empty() && return_str.back() == ',') { return_str.pop_back(); } } else { return_str = ""; } return return_str; } /// @brief 视频帧处理函数 /// @param ipcsNode 摄像机节点 /// @param modelArray 模型列表 /// @param queJC 未处理的视频流帧队列 /// @param queJC2 处理完的视频流帧队列 void PreProcessFn::fnImRecognitionPro(const Json::Value& ipcsNode, Json::Value modelArray, queue& queJC, queue& queJC2) { std::string ipccode = ipcsNode["code"].asString();//摄像机编码 std::string ipcname = ipcsNode["name"].asString();//摄像机名称 std::string ipcrtsppath = ipcsNode["video"].asString();//视频rtsp源 // std::string skipN = ipcsNode["skipN"].asString();//跳帧 // int skipN = ipcsNode["skipN"].asString();//跳帧 //mysql连接初始化 MYSQL* mysql = mysql_init(nullptr); if (!mysql_real_connect(mysql, mysqlpath.c_str(), mysqluser.c_str(), mysqlpass.c_str(), mysqldatabase.c_str(), stoi(mysqlport), NULL, 0)) { std::cout << "连接 MySQL 数据库失败: " << mysql_error(mysql) << std::endl; //mysql_close(mysql); // 关闭连接 //std::exit(0);//数据库连接错误,退出程序 } else { std::cout << "连接 MySQL 数据库成功。" << std::endl; mysql_set_character_set(mysql, "utf8mb4"); //mysql_query(mysql, "SET NAMES GB2312");//解决中文乱码问题 } //初始化redis链接 redisContext* context; if (!connectToRedis(redispath.c_str(), stoi(redisport), redispass.c_str(), context)) { cout << "redis连接初始化失败!" << endl; } else { cout << "redis连接初始化成功!" << endl; } std::string limitDM = "1";//堆煤限定阈值,超过阈值进行报警,配置文件赋值,每个摄像头都不一样 //新增模型处理 ------第1步 //检测区域设定 std::vector areaBelt;//皮带运行检测区域 std::vector areaTSJ;//提升机检测区域 std::vector areaPerson;//人员检测区域 std::vector workareaPerson;//工作区域人员检测区域 std::vector leftareaBeltJC;//左侧皮带检测区域 std::vector rightareaBeltJC;//右侧皮带检测区域 std::vector areaBeltJC;//皮带检测区域 std::vector areaHC;//猴车 std::vector areaSleep;//睡岗 std::vector areaDM;//堆煤检测区域 std::vector areaWear;//穿戴检测区域 std::vector areaFire;//烟火检测区域 std::vector detectarea;//检测区域 std::vector flowarea;//皮带外围区域 std::vector flowrelate;//皮带相对区域 std::vector leftarea;//左侧区域 std::vector rightarea;//右侧区域 std::vector beltarea;//中间区域 std::vector workarea;//工作区域 //模型处理 ------第2步 RUN rBelt;//皮带运行模型 rBelt.analysis1 = "0001";//运行 rBelt.analysis2 = "0002";//停止 RUN rTSJ;//提升机检测模型 rTSJ.analysis1 = "0001";//运行 rTSJ.analysis2 = "0002";//停止 HAT hatJC;//目标检测模型 Cover cover;//摄像头遮挡算法 Camera camera;//摄像头移动算法 DMJC dm;//堆煤检测模型 BELT beltJC;//皮带跑偏,大块异物 HAT hatHC;//乘猴车携带大件模型 HAT hatSleep;//睡岗 HAT hatWear ;//穿戴模型1 clasification cfWear;//穿戴模型2 HAT hatFire;//烟火模型 //各模型录像保存路径 ------第3步 string videoPathBelt = "";//皮带运行挡录像保存路径 string videoPathTSJ = "";// 提升机录像保存路径 string videoPathPerson = "";// 人员闯入录像保存路径 string videoPathBeltJC = "";// 皮带检测录像保存路径 string videoPathCameraCover = "";// 摄像头遮挡录像保存路径 string videoPathCameraMove = "";// 摄像头移动录像保存路径 string videoPathDM = "";// 堆煤录像保存路径 string videoPathHC = "";// 猴车录像保存路径 string videoPathSleep = "";// 睡岗录像保存路径 string videoPathWear = "";// 穿戴录像保存路径 string videoPathFire = "";// 烟火录像保存路径 //最后一次录像时间 ------第4步 auto videoTimeBelt = std::chrono::system_clock::now();// 上一次皮带运行状态录制时间 auto videoTimeTSJ = std::chrono::system_clock::now();// 上一次提升机录制时间 auto videoTimePerson = std::chrono::system_clock::now();// 上一次人员闯入录制时间 auto videoTimeBeltJC = std::chrono::system_clock::now();// 上一次皮带检测录制时间 //auto videoTimeCameraCover = std::chrono::system_clock::now();// 上一次摄像头遮挡录制时间 //auto videoTimeCameraMove = std::chrono::system_clock::now();// 上一次摄像头移动录制时间 auto videoTimeDM = std::chrono::system_clock::now();// 上一次堆煤录制时间 auto videoTimeHC = std::chrono::system_clock::now();// 上一次猴车录制时间 auto videoTimeSleep = std::chrono::system_clock::now();// 上一次睡岗录制时间 auto videoTimeWear = std::chrono::system_clock::now();// 上一次穿戴录制时间 auto videoTimeFire = std::chrono::system_clock::now();// 上一次烟火录制时间 //当前录像开始时间 ------第5步 auto start_timeBelt = std::chrono::system_clock::now();// 皮带运行状态开始录制时间 auto start_timeTSJ = std::chrono::system_clock::now();// 提升机开始录制时间 auto start_timePerson = std::chrono::system_clock::now();// 人员闯入开始录制时间 auto start_timeBeltJC= std::chrono::system_clock::now();// 皮带检测开始录制时间 auto start_timeCameraCover = std::chrono::system_clock::now();// 摄像头遮挡开始录制时间 auto start_timeCameraMove = std::chrono::system_clock::now();// 摄像头移动开始录制时间 auto start_timeDM = std::chrono::system_clock::now();// 堆煤开始录制时间 auto start_timeHC = std::chrono::system_clock::now();// 猴车开始录制时间 auto start_timeSleep = std::chrono::system_clock::now();// 睡岗开始录制时间 auto start_timeWear = std::chrono::system_clock::now();// 穿戴开始录制时间 auto start_timeFire = std::chrono::system_clock::now();// 烟火开始录制时间 //调用模型和算法的返回结果 ------第6步 int beltStatus = 0;// 皮带最新状态 int beltStatusold = 0;// 皮带旧状态 int tsjStatus = -1;// 提升机最新状态 0运动 1停止 -1未知 int tsjStatusold = -1;// 提升机旧状态 0运动 1停止 -1未知 vector personResult;//breakin:>0 人员闯入 <=0 无人员闯入;wearHat 0:全部佩戴安全帽 1:有人未佩戴安全帽 vector beltJCResult; double cameracover = 0;// 摄像头遮挡标志 double cameramove = 0;// 摄像头移动标志 float proportion = 0;// 煤炭占比 vector hcResult; //猴车返回结果 vector sleepResult; //睡岗返回结果 vector resultWearold;//穿戴返回结果,上一次的结果 vector resultWear;//穿戴返回结果 vector resultFire;//烟火返回结果 //异步任务结果 ------第7步 std::future futureBelt;// 皮带运行状态检测异步任务结果 std::future futureTSJ;// 提升机状态检测异步任务结果 std::future> futurePerson;// 目标检测异步任务结果 std::future> futureBeltJC;// 皮带检测异步任务结果 std::future futureCameraCover;// 摄像头遮挡检测异步任务结果 std::future futureCameraMove;// 摄像头移动检测异步任务结果 std::future futureDM;// 堆煤检测异步任务结果 std::future> futureHC;// 乘猴车携带大件异步任务结果 std::future> futureSleep;// 睡岗异步任务结果 std::future> futureWear;// 穿戴检测异步任务结果 std::future> futureFire;// 烟火检测异步任务结果 //VideoWriter对象 ------第8步 VideoWriter video_writerBelt;// 皮带运行状态录像用 VideoWriter video_writerTSJ;// 提升机录像用 VideoWriter video_writerPerson;// 人员闯入录像用 VideoWriter video_writerBeltJC;// 皮带检测录像用 VideoWriter video_writerCameraCover;// 摄像头遮挡录像用 VideoWriter video_writerCameraMove;// 摄像头移动录像用 VideoWriter video_writerDM;// 堆煤录像用 VideoWriter video_writerHC;// 猴车录像用 VideoWriter video_writerSleep;// 睡岗录像用 VideoWriter video_writerWear;// 穿戴录像用 VideoWriter video_writerFire;// 烟火录像用 //创建写入redis的实例 ------第9步 warningfile wfBelt = warningfile(); warningfile wfTSJ = warningfile(); warningfile wfPerson = warningfile(); warningfile wfBeltJC = warningfile(); warningfile wfCameraCover = warningfile(); warningfile wfCameraMove = warningfile(); warningfile wfDM = warningfile(); warningfile wfHC = warningfile(); warningfile wfSleep = warningfile(); warningfile wfWear = warningfile(); warningfile wfFire = warningfile(); //第一次报警时间 ------第10步 auto firstSleep = std::chrono::system_clock::now();// 睡岗第一次报警时间 auto firstFire = std::chrono::system_clock::now();// 烟火第一次报警时间 //记录判断结果 vector vecVideoSleep;//保存睡岗视频帧 vector vecFire;//烟火判断结果 vector vecVideoFire;//保存烟火视频帧 //提升机和皮带判断时,需要累计三张图片才能进行判断 std::vector imagesTsj; std::vector imagesBelt; std::string color_result; std::string lable_title; cout < quTSJ;//记录提升机运动的判断结果 std::queue quBelt;//记录皮带运动判断结果 int tsjCount;//提升机计数,间隔一段时间,调用一次模型 int beltCount;//提升机计数,间隔一段时间,调用一次模型 Mat iMatWear;//人员穿戴的第一帧 long currentFrame = 1;//记录当前帧数 long skip_frame_num = skipN;//跳帧间隔设置 Mat frame; while (!asyncStop) { //std::cout << ipccode + "当前线程待处理队列数量1111:" << queJC.size() << std::endl; if (queJC.size() < 1)//队列里有一定数量帧的时候,再开始处理 continue; try { // 在操作队列之前先锁定互斥锁 std::unique_lock lck(mtx); frame = queJC.front().clone(); queJC.pop(); lck.unlock(); if (frame.empty()) continue; if (currentFrame % skip_frame_num == 0) //跳帧处理 { ///////////////////////////////////执行异步任务/////////////////////////////////////////////// //皮带运行算法处理及判断 modelId = 1 if (rBelt.isLoad) { futureBelt = std::async(std::launch::async, &PreProcessModel::fnBeltMoveRec, &ppm, std::ref(frame), std::ref(imagesBelt), ref(beltCount), std::ref(rBelt), areaBelt); } //提升机模型处理及判断 modelId = 2 if (rTSJ.isLoad) { futureTSJ = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelTSJ, &ppm, std::ref(frame), std::ref(imagesTsj), ref(tsjCount), std::ref(rTSJ), std::ref(quTSJ), areaTSJ); } //人员闯入模型处理及判断 modelId = 3 if (hatJC.isLoad) { futurePerson = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelHAT1, &ppm, std::ref(frame), std::ref(hatJC), areaPerson,workareaPerson,c_list,lable_title,color_result); } //摄像头移动和遮挡专用 auto cameraRecordTime = std::chrono::system_clock::now() + std::chrono::hours(-1);//记录最后一次调用摄像头移动算法时间,间隔1小时调用一次摄像头移动和遮挡算法 std::chrono::duration timeDifference = std::chrono::system_clock::now() - cameraRecordTime; if (timeDifference.count() >= 3600)//间隔1个小时检测一次摄像头移动和遮挡 { //摄像头遮挡算法处理及判断 modelId = 4 if (cover.isLoad) { futureCameraCover = std::async(std::launch::async, &PreProcessModel::fnCameraCoverRec, &ppm, std::ref(frame), std::ref(cover)); } //摄像头移动算法处理及判断 modelId = 5 if (camera.isLoad) { futureCameraMove = std::async(std::launch::async, &PreProcessModel::fnCameraMoveRec, &ppm, std::ref(frame), std::ref(camera)); } cameraRecordTime = std::chrono::system_clock::now();//重新计时 } //堆煤模型处理及判断 modelId = 6 if (dm.isLoad) { futureDM = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelDM, &ppm, std::ref(frame), std::ref(dm), areaDM); } //皮带跑偏和异物检测模型处理及判断 modelId = 7 if (beltJC.isLoad) { futureBeltJC = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelBeltJC2, &ppm, std::ref(frame), std::ref(beltJC), leftareaBeltJC,rightareaBeltJC,areaBeltJC); } //乘猴车携带大件 modelId = 8 if (hatHC.isLoad) { futureHC = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelHATHC, &ppm, std::ref(frame), std::ref(hatHC), areaHC); } //睡岗 modelId = 9 if (hatSleep.isLoad) { futureSleep = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelHATSleep, &ppm, std::ref(frame), std::ref(hatSleep)); } //人员穿戴模型处理及判断 11 if (hatWear.isLoad) { futureWear = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelWear, &ppm, std::ref(frame), std::ref(hatWear), std::ref(cfWear), areaWear); } //烟火模型处理及判断 12 if (hatFire.isLoad) { futureFire = std::async(std::launch::async, &PreProcessModel::fnImRecProByModelFire, &ppm, std::ref(frame), std::ref(hatFire)); } ///////////////////////////////////检查异步任务,并得到返回结果/////////////////////////////////////////////// //检查异步任务是否开启 modelId = 1 if (futureBelt.valid()) { beltStatus = futureBelt.get();// 皮带最新运行状态 } //检查异步任务是否开启 modelId = 2 if (futureTSJ.valid()) { tsjStatus = futureTSJ.get();// 等待返回提升机运行状态 } //检查异步任务是否开启 modelId = 3 if (futurePerson.valid()) { personResult = futurePerson.get();// 等待返回是否人员闯入 } //检查异步任务是否开启 modelId = 4 if (futureCameraCover.valid()) { cameracover = futureCameraCover.get();// 获取摄像头遮挡状态 } //检查异步任务是否开启 modelId = 5 if (futureCameraMove.valid()) { cameramove = futureCameraMove.get();// 获取摄像头移动状态 } //检查异步任务是否开启 modelId = 6 if (futureDM.valid()) { proportion = futureDM.get();// 等待返回堆煤占比 //跳帧保存数据 if (currentFrame % (skip_frame_num*5) == 0) //跳帧处理,每间隔一定帧数保存一次记录 { // 实时写入煤流量 std::string query = "CALL insert_or_update_CoalFlow(" + ipccode + ", " + std::to_string(proportion) + ")"; // 检查连接是否仍然有效 if (mysql_ping(mysql) == 0) { //std::cout << "连接 MySQL 数据库成功" << std::endl; if (mysql_query(mysql, query.c_str())) { string err_string = mysql_error(mysql); cout << err_string << endl; } } else { //重新连接数据库 if (!mysql_real_connect(mysql, mysqlpath.c_str(), mysqluser.c_str(), mysqlpass.c_str(), mysqldatabase.c_str(), stoi(mysqlport), NULL, 0)) { std::cout << "连接 MySQL 数据库失败: " << mysql_error(mysql) << std::endl; mysql_close(mysql); // 关闭连接 } //mysql_set_character_set(mysql, "utf8mb4"); mysql_query(mysql, "SET NAMES GB2312");//解决中文乱码问题 } } } //皮带检测异步任务是否开启 modelId = 7 if (futureBeltJC.valid()) { beltJCResult = futureBeltJC.get();// 等待返回是否皮带检测结果 } //乘猴车携带大件 modelId = 8 if (futureHC.valid()) { hcResult = futureHC.get();// 等待返回结果 } //睡岗 modelId = 9 if (futureSleep.valid()) { sleepResult = futureSleep.get();// 等待返回睡岗人员数量 } //人员穿戴 11 if (futureWear.valid()) { resultWear = futureWear.get();// 等待返回人员穿戴结果 } //烟火检测 12 if (futureFire.valid()) { resultFire = futureFire.get();// 等待返回烟火结果 } queJC2.push(frame);// 推到视频推流队列 string filefolder = fnCreateFileFolder(warningFilePath);//生成文件夹路径 string videoPath;//录像保存路径 string firstImagPath;//录像的第一张图片 double seconds; #pragma region 进行判断报警录像处理 // 皮带运行状态变化报警 1 if (beltStatus != -1 && beltStatus != beltStatusold && !video_writerBelt.isOpened()) { beltStatus = beltStatusold;//皮带状态保持一致 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeBelt).count(); if (seconds > RecIntervalime) { cout << "皮带运行触发报警录像后,开始保存10秒视频" << endl; start_timeBelt = std::chrono::system_clock::now(); videoTimeBelt = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 if (beltStatus == 0)//运输 { videoPath = filefolder + videoPathBelt + rBelt.analysis1 + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称; firstImagPath = filefolder + videoPathBelt + rBelt.analysis1 + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; } else//停止 { videoPath = filefolder + videoPathBelt + rBelt.analysis2 + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称; firstImagPath = filefolder + videoPathBelt + rBelt.analysis2 + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; } //cv::resize(frame, frame, Size(640, 480)); // 创建VideoWriter对象 video_writerBelt = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfBelt.setRecordFileName(videoPath); wfBelt.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerBelt, start_timeBelt, wfBelt, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (beltStatus != -1) beltStatus = beltStatusold;//皮带状态保持一致 if (video_writerBelt.isOpened()) { //cv::resize(frame, frame, Size(640, 480)); fnVideoRecordToMysql(frame, 0, video_writerBelt, start_timeBelt, wfBelt, mysql, recordtime); } } // 提升机状态变化报警 2 if (tsjStatus != -1 && tsjStatus != tsjStatusold && !video_writerTSJ.isOpened()) { tsjStatusold = tsjStatus;//提升机保持状态一致 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeTSJ).count(); if (seconds > RecIntervalime) { cout << "提升机触发报警录像后,开始保存10秒视频" << endl; start_timeTSJ = std::chrono::system_clock::now(); videoTimeTSJ = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 if (tsjStatus == 0)//运输 { videoPath = filefolder + videoPathTSJ + rTSJ.analysis1 + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称; firstImagPath = filefolder + videoPathTSJ + rTSJ.analysis1 + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; } else//停止 { videoPath = filefolder + videoPathTSJ + rTSJ.analysis2 + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称; firstImagPath = filefolder + videoPathTSJ + rTSJ.analysis2 + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; } //cv::resize(frame, frame, Size(640, 480)); // 创建VideoWriter对象 video_writerTSJ = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfTSJ.setRecordFileName(videoPath); wfTSJ.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerTSJ, start_timeTSJ, wfTSJ, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (tsjStatus != -1) tsjStatusold = tsjStatus;//提升机保持状态一致 if (video_writerTSJ.isOpened()) { cv::resize(frame, frame, Size(640, 480)); fnVideoRecordToMysql(frame, 0, video_writerTSJ, start_timeTSJ, wfTSJ, mysql, recordtime); } } //人员闯入或者未戴安全帽报警 3 if (!video_writerPerson.isOpened() && personResult.size() > 0 && ((areaPerson.size()>0 && personResult[0] > 0) //人员闯入判断 || personResult[1] > 0 //未带安全帽判断 || (workareaPerson.size()>0 && personResult[2] <= 0))//离岗判断 ) { string videotitle = ""; if (personResult[0] > 0) { videotitle = "人员闯入"; } if (personResult[1] > 0) { videotitle = videotitle + " 未佩戴安全帽"; } if (personResult[2] <= 0) { videotitle = videotitle + " 人员脱岗离岗"; } wfPerson.setAnalyseResult(videotitle); personResult[0] = 0;//人员闯入标志复位 personResult[1] = 0;//未带安全帽标志复位 personResult[2] = 0;//工作区域离岗标志复位 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimePerson).count(); if (seconds > RecIntervalime) { cout << videotitle << "触发报警录像后,开始保存10秒视频" << endl; start_timePerson = std::chrono::system_clock::now(); videoTimePerson = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathPerson + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathPerson + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerPerson = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfPerson.setRecordFileName(videoPath); wfPerson.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerPerson, start_timePerson, wfPerson, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (video_writerPerson.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerPerson, start_timePerson, wfPerson, mysql , recordtime); } } //摄像头遮挡报警 4 if (cameracover == 1 && !video_writerCameraCover.isOpened()) { cameracover = 0;//标志复位 cout << "摄像头遮挡触发报警录像后,开始保存10秒视频" << endl; start_timeCameraCover = std::chrono::system_clock::now(); //videoTimeCameraCover = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathCameraCover + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathCameraCover + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerCameraCover = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfCameraCover.setRecordFileName(videoPath); wfCameraCover.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerCameraCover, start_timeCameraCover, wfCameraCover, mysql , recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } else { if (video_writerCameraCover.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerCameraCover, start_timeCameraCover, wfCameraCover, mysql , recordtime); } } //摄像头移动报警 5 if (cameramove == 1 && !video_writerCameraMove.isOpened()) { cameramove = 0;//标志复位 cout << "摄像头移动触发报警录像后,开始保存10秒视频" << endl; start_timeCameraMove = std::chrono::system_clock::now(); //videoTimeCameraMove = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathCameraMove + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathCameraMove + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerCameraMove = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfCameraMove.setRecordFileName(videoPath); wfCameraMove.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerCameraMove, start_timeCameraMove, wfCameraMove, mysql , recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } else { if (video_writerCameraMove.isOpened()) { fnVideoRecordToMysql(frame, 1, video_writerCameraMove, start_timeCameraMove, wfCameraMove, mysql , recordtime); } } // 堆煤报警 6 if (proportion > std::stof(limitDM) && !video_writerDM.isOpened()) { wfDM.setAnalyseResult("堆煤"); proportion = 0;//标志复位 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeDM).count(); if (seconds > RecIntervalime) { cout << "堆煤触发报警录像后,开始保存10秒视频" << endl; start_timeDM = std::chrono::system_clock::now(); videoTimeDM = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathDM + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathDM + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerDM = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfDM.setRecordFileName(videoPath); wfDM.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerDM, start_timeDM, wfDM, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (video_writerDM.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerDM, start_timeDM, wfDM, mysql, recordtime); } } //皮带跑偏,异物报警 7 if (!video_writerBeltJC.isOpened() && beltJCResult.size() > 0 && (beltJCResult[0] > 0 || beltJCResult[1] == 0 || beltJCResult[2] > 0)) { if (beltJCResult[0] > 0 ) { wfBeltJC.setAnalyseResult("大煤块"); } else if (beltJCResult[1] == 0) { wfBeltJC.setAnalyseResult("皮带跑偏"); } else if (beltJCResult[2] > 0) { wfBeltJC.setAnalyseResult("大块异物"); } else { wfBeltJC.setAnalyseResult(""); } beltJCResult[0] = 0;//大煤块标志复位 beltJCResult[1] = 1;//标志复位 0为跑偏 1为不跑偏 beltJCResult[2] = 0;//异物标志复位 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeBeltJC).count(); if (seconds > RecIntervalime) { cout << "皮带跑偏,大煤块,异物触发报警录像后,开始保存10秒视频" << endl; start_timeBeltJC = std::chrono::system_clock::now(); videoTimeBeltJC = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathBeltJC + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathBeltJC + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerBeltJC = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfBeltJC.setRecordFileName(videoPath); wfBeltJC.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerBeltJC, start_timeBeltJC, wfBeltJC, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (video_writerBeltJC.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerBeltJC, start_timeBeltJC, wfBeltJC, mysql, recordtime); } } // 猴车携带大件 8 if (hcResult.size() >0 && hcResult[0] > 0 && !video_writerHC.isOpened()) { wfHC.setAnalyseResult("猴车携带大件"); hcResult[0] = 0;//标志复位 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeHC).count(); if (seconds > RecIntervalime) { cout << "猴车携带大件触发报警录像后,开始保存10秒视频" << endl; start_timeHC = std::chrono::system_clock::now(); videoTimeHC = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathHC + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathHC + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerHC = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfHC.setRecordFileName(videoPath); wfHC.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerHC, start_timeHC, wfHC, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (video_writerHC.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerHC, start_timeHC, wfHC, mysql , recordtime); } } // 睡岗报警 9 if (sleepResult.size() > 0 && sleepResult[0] > 0 && !video_writerSleep.isOpened()) { wfSleep.setAnalyseResult("睡岗"); sleepResult[0] = 0;//标志复位 seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeSleep).count(); if (seconds > RecIntervalime) { cout << "睡岗触发报警录像后,开始保存10秒视频" << endl; start_timeSleep = std::chrono::system_clock::now(); videoTimeSleep = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathSleep + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathSleep + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerSleep = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfSleep.setRecordFileName(videoPath); wfSleep.setrecordImgFileName(firstImagPath); fnVideoRecordToMysql(frame, 1, video_writerSleep, start_timeSleep, wfSleep, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, frame); } } else { if (video_writerSleep.isOpened()) { fnVideoRecordToMysql(frame, 0, video_writerSleep, start_timeSleep, wfSleep, mysql, recordtime); } } // 人员穿戴报警 11 if (resultWear.size() > 0 && !video_writerWear.isOpened()) { string AnalyseResult = ""; //初始化上一次的结果记录 if (resultWearold.size() == 0) { resultWearold = resultWear; iMatWear = frame;//记录进入的第一个人图像 } if (resultWear[0] == 0)//检测框内没人 { if (resultWearold[0] == 1)//原来检测区域有人,则表示检测完毕,进行判断处理 { if (resultWearold[1] < 1) { AnalyseResult+="未佩戴安全帽"; } if (resultWearold[2] < 1) { AnalyseResult += " 未携带自救器"; } if (resultWearold[3] < 1) { AnalyseResult += " 未穿胶鞋"; } if (resultWearold[4] < 1) { AnalyseResult += " 未穿工作服"; } //wfWear.setAnalyse("AI-11-03"); wfWear.setAnalyseResult(AnalyseResult); resultWear.clear(); resultWearold.clear();//判断完成后清空保留的状态 } else { resultWearold = resultWear; } } else if (resultWear[0] == 1)//检测框内有1人 { resultWearold[0] = resultWear[0]; if (resultWear[1] == 1)//记录安全帽检测结果 { resultWearold[1] = 1; } if (resultWear[2] == 1)//记录自救器检测结果 { resultWearold[2] = 1; } if (resultWear[3] == 1)//记录鞋子检测结果 { resultWearold[3] = 1; } if (resultWear[4] == 1)//记录工作服检测结果 { resultWearold[4] = 1; } } else if (resultWear[0]>1)//检测框内有多人 { //wfWear.setAnalyseResult("检测框内有多人"); cout << "检测框内有多人,检测作废" << endl; resultWear.clear(); } if (!AnalyseResult.empty())//判断有违规行为 { seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeWear).count(); if (seconds > RecIntervalime) { cout << "人员穿戴触发报警录像后,开始保存10秒视频" << endl; start_timeWear = std::chrono::system_clock::now(); videoTimeWear = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathWear + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathWear + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerWear = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfWear.setRecordFileName(videoPath); wfWear.setrecordImgFileName(firstImagPath); //fnVideoRecord(frame, 1, video_writerWear, start_timeWear, wfWear, context, recordtime); fnVideoRecordToMysql(frame, 1, video_writerWear, start_timeWear, wfWear, mysql, recordtime); //保存第一张图片 cv::imwrite(firstImagPath, iMatWear); } } } else { if (video_writerWear.isOpened()) { //fnVideoRecord(frame, 0, video_writerWear, start_timeWear, wfWear, context, recordtime); fnVideoRecordToMysql(frame, 0, video_writerWear, start_timeWear, wfWear, mysql, recordtime); } } // 烟火报警 12 if (resultFire.size() > 0 && !video_writerFire.isOpened()) { int res = 0; //有烟火报警 if (resultFire[0] || resultFire[1]) { if (vecFire.size() == 0) { firstFire = std::chrono::system_clock::now();//记录第一次报警时间 vecFire.push_back(resultFire[0] || resultFire[1]); vecVideoFire.push_back(frame); resultFire[0] = 0;//火标志复位 resultFire[1] = 0;//烟标志复位 continue; } } if (vecFire.size() > 0)//开始计数了 { std::chrono::duration timeDifference = std::chrono::system_clock::now() - firstFire; if (timeDifference.count() > 5)//大于5秒,进行判断 { res = fnJudeRatio(vecFire, 1, 0.6); //判断有烟火 if (res != 0) { wfFire.setAnalyseResult("烟火报警"); seconds = std::chrono::duration(std::chrono::system_clock::now() - videoTimeHC).count(); if (seconds > RecIntervalime) { cout << "烟火触发报警录像后,开始保存10秒视频" << endl; start_timeFire = std::chrono::system_clock::now(); videoTimeFire = std::chrono::system_clock::now();//重新开始记录最后一次录像时间 videoPath = filefolder + videoPathFire + getCurrentDateTime("%Y%m%d%H%M%S") + ".mp4";//录像文件名称 firstImagPath = filefolder + videoPathFire + getCurrentDateTime("%Y%m%d%H%M%S") + ".png"; // 创建VideoWriter对象 video_writerFire = VideoWriter(videoPath, cv::VideoWriter::fourcc('a', 'v', 'c', '1'), 20, Size(frame.cols, frame.rows)); wfFire.setRecordFileName(videoPath); wfFire.setrecordImgFileName(firstImagPath); //fnVideoRecord(frame, 1, video_writerFire, start_timeFire, wfFire, context, recordtime); fnVideoRecordToMysql2(vecVideoFire, 1, video_writerFire, wfFire, mysql); //保存第一张图片 cv::imwrite(firstImagPath, vecVideoFire[0]); } } vecVideoFire.clear(); vecFire.clear(); } else { vecFire.push_back(resultFire[0] || resultFire[1]); vecVideoFire.push_back(frame); } } resultFire[0] = 0;//火标志复位 resultFire[1] = 0;//烟标志复位 } #pragma endregion } //cv::imwrite("./img/" + std::to_string(currentFrame)+".jpg", frame); //cv::resize(frame, frame, Size(1920, 1080)); //cv::imshow(ipccode, frame);//展示帧图片 //cv::imshow("ipccode", queJC2.front());//展示帧图片 //cv::waitKey(20); //std::this_thread::sleep_for(std::chrono::milliseconds(10));// 延迟等待一段时间 if (currentFrame > 10000) { currentFrame = 0; } currentFrame++; fnWriteToRedis(context,ipccode); } catch (const std::exception& ex) { std::string errorMessage = "处理视频帧失败-"; errorMessage += ex.what(); cout << errorMessage << endl; continue; } } frame.release(); } /// @brief 推流到rabbitmq /// @param queJC2 处理完的视频流帧队列 /// @param ipccode 摄像机编号 void PreProcessFn::fnPushVideoInRabbitMQ(queue& queJC2, string ipccode) { CRabbitmqClient objRabbitmq; int iRet = objRabbitmq.Connect(rabbitpath, stoi(rabbitport), rabbituser, rabbitpass); iRet = objRabbitmq.ExchangeDeclare(ipccode, "fanout"); objRabbitmq.Publish("", ipccode, ""); printf("Rabbitmq连接状态:%d\n", iRet); std::string imgStr; //定义接受帧 Mat frame; long currentFrame = 1; long skip_frame_num = skipN;//跳帧间隔设置(每1帧) //创建url连接,定时判断有没有页面进行拉流 CURL* curl; CURLcode res; std::string readBuffer; curl = curl_easy_init(); bool pushflg = true;//是否推流标志 if(curl) { string url = "http://" + rabbitpath + ":1" + rabbitport + "/api/exchanges/%2F/"+ ipccode + "/bindings/source"; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // 如果需要验证身份,请设置用户名和密码,例如 "admin:admin" curl_easy_setopt(curl, CURLOPT_USERNAME, rabbituser.c_str()); curl_easy_setopt(curl, CURLOPT_PASSWORD, rabbitpass.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); } while (!asyncStop) { //std::cout << ipccode + "当前线程Rabbitmq数据数量2222:" << queJC2.size() << std::endl; try { if (queJC2.size() > 500) { cout << "推送视频时,存在内存溢出风险!" << endl; } if (queJC2.empty() || queJC2.size() == 0) { continue; } //加锁,防止别的系统操作这段内存 std::unique_lock lck(mtx); frame = queJC2.front(); queJC2.pop(); lck.unlock(); if (frame.empty())//帧为空,则舍弃 continue; if (currentFrame % 20 == 0) //每20帧,判断一次是否有页面拉流 { //通过API获取指定exchange对应的queue res = curl_easy_perform(curl); if(res != CURLE_OK) { pushflg = false;//不可推流 std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(res) << std::endl; continue; } else { //std::cout << readBuffer << std::endl; //对应的exchange中,有queue,则进行推流 if(readBuffer.length()>5) { pushflg = true; //可推流 } else { pushflg = false;//不可推流 } } } //pushflg=true;//test //如果为true则推流 if(pushflg) { if (iRet != 0) { //重新连接并发送 objRabbitmq.Connect(rabbitpath, stoi(rabbitport), rabbituser, rabbitpass); objRabbitmq.ExchangeDeclare(ipccode, "fanout"); } //cv::imwrite("./img/" + ipccode +".jpg", frame); ////压缩图片 //cv::resize(frame, frame, Size(1280, 720)); imgStr = Mat2Base64(frame, ".jpg");//输出Base64编码的字符串 //std::cout << "Base64 size: " << imgStr.size() << std::endl; objRabbitmq.Publish(imgStr, ipccode, ""); //cv::resize(frame, frame, Size(1280, 720)); //cv::imshow(ipccode, frame);//展示帧图片 //waitKey(5); } readBuffer.clear(); //std::this_thread::sleep_for(std::chrono::milliseconds(10));// 延迟等待一段时间 if (currentFrame > 10000) { currentFrame = 0; } currentFrame++; } catch (const std::exception& ex) { std::string errorMessage = "保存到RabbitMQ失败:-"; errorMessage += ex.what(); cout << errorMessage << endl; continue; } } curl_easy_cleanup(curl); frame.release(); } /// @brief 推流到流媒体服务器 /// @param queJC2 处理完的视频流帧队列 /// @param ipccode 摄像机编号 void PreProcessFn::fnPushVideo(queue& queJC2, string ipccode) { //定义接受帧 Mat frame; vector arguments = { "ffmpeg " "-hwaccel","cuvid", "-hwaccel_output_format","cuda", "-y", "-an", "-f", "rawvideo", "-vcodec", "rawvideo", "-pix_fmt", "bgr24", "-s", "640x480", "-r", "15", "-i", "-", "-pix_fmt", "yuv420p", "-f", "flv", "-max_delay", "1000", "-flvflags", "no_duration_filesize", "-c:v","h264_nvenc", "-b:v", "3M", "-g:v", "15", "-bf", "0", "-bufsize", "50000000", "-rtbufsize", "50000000", "rtmp://192.168.1.8:1935/live/camera1" }; string ffmpeg_command = join(arguments, " "); // 打开FFmpeg进程 FILE* pipe = popen(ffmpeg_command.c_str(), "w"); if (!pipe) { std::cerr << "无法启动FFmpeg" << std::endl; } while (!asyncStop) { //std::cout << ipccode + "当前线程Rabbitmq数据数量2222:" << queJC2.size() << std::endl; try { if (queJC2.size() > 500) { cout << "推送视频时,存在内存溢出风险!" << endl; } if (queJC2.empty() || queJC2.size() == 0) { continue; } frame = queJC2.front(); queJC2.pop(); if (frame.empty())//帧为空,则舍弃 continue; // 将帧写入到FFmpeg管道中 fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe); //cv::resize(frame, frame, Size(1280, 720)); //cv::imshow(ipccode, frame);//展示帧图片 //waitKey(10); //std::this_thread::sleep_for(std::chrono::milliseconds(10));// 延迟等待一段时间 } catch (const std::exception& ex) { std::string errorMessage = "保存到RabbitMQ失败:-"; errorMessage += ex.what(); cout << errorMessage << endl; continue; } } frame.release(); } /// @brief 推流到流媒体服务器 /// @param queJC2 处理完的视频流帧队列 /// @param ipccode 摄像机编号 void PreProcessFn::fnPushVideoToUrl(queue& queJC2,string toRtsp, string fps, string ipccode) { //定义接受帧 Mat frame; vector arguments = { "ffmpeg " "-hwaccel","cuvid", "-hwaccel_output_format","cuda", "-y", "-an", "-f", "rawvideo", "-vcodec", "rawvideo", "-pix_fmt", "bgr24", "-s", "1280x720", "-r", fps, "-i", "-", "-pix_fmt", "yuv420p", "-f", "flv", "-max_delay", "1000", "-flvflags", "no_duration_filesize", "-c:v","h264_nvenc", "-b:v", "3M", "-g:v", "15", "-bf", "0", "-bufsize", "50000000", "-rtbufsize", "50000000", toRtsp }; string ffmpeg_command = join(arguments, " "); // 打开FFmpeg进程 FILE* pipe = popen(ffmpeg_command.c_str(), "w"); if (!pipe) { std::cerr << "无法启动FFmpeg" << std::endl; } while (!asyncStop) { //std::cout << ipccode + "当前线程Rabbitmq数据数量2222:" << queJC2.size() << std::endl; try { if (queJC2.size() > 500) { cout << "推送视频时,存在内存溢出风险!" << endl; } if (queJC2.empty() || queJC2.size() == 0) { continue; } frame = queJC2.front(); queJC2.pop(); if (frame.empty())//帧为空,则舍弃 continue; // 将帧写入到FFmpeg管道中 fwrite(frame.data, 1, frame.total() * frame.elemSize(), pipe); //cv::resize(frame, frame, Size(1280, 720)); //cv::imshow(ipccode, frame);//展示帧图片 //waitKey(10); //std::this_thread::sleep_for(std::chrono::milliseconds(10));// 延迟等待一段时间 } catch (const std::exception& ex) { std::string errorMessage = "保存到RabbitMQ失败:-"; errorMessage += ex.what(); cout << errorMessage << endl; continue; } } frame.release(); }