diff --git a/ai_matrix/Config/Config.cpp b/ai_matrix/Config/Config.cpp index e78d867..ae4e5b7 100644 --- a/ai_matrix/Config/Config.cpp +++ b/ai_matrix/Config/Config.cpp @@ -70,6 +70,8 @@ namespace ai_matrix this->identifyConfig_.iTargetMinWidth = config_["identify"]["target_min_width"].as(); this->identifyConfig_.iTargetMinY = config_["identify"]["target_min_y"].as(); this->identifyConfig_.iMaxIdentifyFrame = config_["identify"]["max_identify_frame"].as(); + this->identifyConfig_.iMaxContainerSpaceX = config_["identify"]["max_container_space_x"].as(); + this->identifyConfig_.iMaxContainerSpaceY = config_["identify"]["max_container_space_y"].as(); // websocket server 服务端参数 this->wSocketConfig_.bIsUse = config_["wsocket_server"]["is_use"].as(); diff --git a/ai_matrix/Config/Config.h b/ai_matrix/Config/Config.h index 0f6858c..c662e15 100644 --- a/ai_matrix/Config/Config.h +++ b/ai_matrix/Config/Config.h @@ -88,6 +88,10 @@ namespace ai_matrix int iTargetMinY; // 单次识别最大帧数 int iMaxIdentifyFrame; + // 两个箱子的箱角最大差值X + int iMaxContainerSpaceX; + // 两个箱子的箱角最大差值Y + int iMaxContainerSpaceY; }; // websocket_server 的服务端参数 diff --git a/app/config/config.yaml b/app/config/config.yaml index 5473391..b779733 100644 --- a/app/config/config.yaml +++ b/app/config/config.yaml @@ -1,7 +1,7 @@ # 基础控制参数 base: # 股道名称 - track_name: "1" + track_name: "1门" # 测试模式 test_model: false # Api 监听端口 @@ -24,43 +24,63 @@ log: # 数据源参数 data_source: - url: "./vedio/buertai2.mp4" - # 跳帧数 - skip_interval: 3 - # 行驶方向 0-自动识别 1-向左 2-向右 (与“首位信息”成对存在,形成例如向左就编号在前,向右就属性在前的对应) - direction: 0 - # 0-向左编号在前 1-向左属性在前 (向右行驶的情况:2-向右编号在前 3-向右属性在前) - left_first: 0 - # (向左行驶的情况:0-向左编号在前 1-向左属性在前) 2-向右编号在前 3-向右属性在前 - right_first: 3 - # 识别区域 - identify_areas: [120, 0, 1800, 1080] + - # 顶部摄像头(必须顶部摄像头) + url: "./videos/buertai2.mp4" + # 跳帧数 + skip_interval: 3 + # 识别区域 + identify_areas: [120, 0, 1800, 1080] + # 切箱方式 + divide_mode: "corner" #[corner, pixel] + # 汽车行进方向 + run_direction: "down" #[up, down, left, right] + - # 侧部摄像头 + url: "./videos/buertai2.mp4" + # 跳帧数 + skip_interval: 3 + # 识别区域 + identify_areas: [ 120, 0, 1800, 1080 ] + # 切箱方式 + divide_mode: "pixel" #[corner, pixel] + # 汽车行进方向 + run_direction: "right" #[up, down, left, right] + - # 侧边摄像头 + url: "./videos/buertai2.mp4" + # 跳帧数 + skip_interval: 3 + # 识别区域 + identify_areas: [ 120, 0, 1800, 1080 ] + # 切箱方式 + divide_mode: "pixel" #[corner, pixel] + # 汽车行进方向 + run_direction: "left" #[up, down, left, right] # 识别参数 identify: - # 运行方式 - run_mode: "always" #[always; command] - # 是否开启动态检测 - need_move_detect_flag: true - # 识别方向 [LEFT,RIGHT,ALL] - identify_direction: "LEFT" + # 切箱方式 + divide_mode: "corner" #[corner, pixel] # 大框帧跨度(比一个大框从出现到消失的跨度稍大一点, 跟跳帧有关系) - partition_frame_span: 20 - # 大框帧跨度的位置像素差异 - split_frame_span_px: 200 + partition_frame_span: 0 + # 顶部Y轴大框帧跨度的位置像素差异 + top_y_split_span_px: 200 + # 侧边X轴大框帧跨度的位置像素差异 + side_x_split_span_px: 600 # 每帧大框位置差异最小值 (持续小于此值,则可能停车) chkstop_px: 15 # 持续X次续位置差异小于gc_chkstop_px,则判断为停车。 chkstop_count: 10 # 过滤最小大框高度(不需要的话就写个很小的值) - num_frame_height: 150 - pro_frame_height: 120 - # 过滤最大框宽度(不需要的话就写个很大的值) - space_frame_width: 500 - # 是否识别车头 - train_heard_detect: false - # 是否识别集装箱 - container_detect: false + target_min_height: 95 + # 过滤最小大框宽度(不需要的话就写个很小的值) + target_min_width: 50 + # 过滤低于指定Y轴的大框 + target_min_y: 550 + # 单次识别最大帧数 + max_identify_frame: 600 + # 两个箱子的箱角最大差值X + max_container_space_x: 600 + # 两个箱子的箱角最大差值Y + max_container_space_y: 500 # websocket_server 的服务端参数 wsocket_server: diff --git a/app/config/matrix.yaml b/app/config/matrix.yaml index 3943746..65d8c2f 100644 --- a/app/config/matrix.yaml +++ b/app/config/matrix.yaml @@ -1,44 +1,56 @@ -#use_deviceid: -# #engineid: deviceid -# 0: 0 - #engine实例 engines: ApiEngine: 0 + DeleteExpiredFolderEngine: 0 + WSServerEngine: 0 VideoEngine: 0 + VideoEngine: 1 + VideoEngine: 2 VideoDecodeEngine: 0 - MoveEngine: 0 - SaveMoveImageEngine: 0 + VideoDecodeEngine: 1 + VideoDecodeEngine: 2 + ControlEngine: 0 +# SaveMoveImageEngine: 0 SaveMoveInfoEngine: 0 - TrainStep1DataReadEngine: 0 - TrainStep1InferenceEngine: 0 - TrainStep1FilterEngine: 0 - TrainDivideEngine: 0 - TrainStep2DataReadEngine: 0 - TrainStep2InferenceEngine: 0 - TrainCharacterConversionEngine: 0 + ContainerStep1InferenceEngine: 0 + CornerInferenceEngine: 0 + Step1MergeEngine: 0 + ContainerStep2InferenceEngine: 0 + ContainerCharacterConversionEngine: 0 + ContainerDivideEngine: 0 + ContainerDivideEngine: 1 + ContainerDivideEngine: 2 SelectBestEngine: 0 SaveResultCSVEngine: 0 - ToHttpSrvEngine: 0 ToMinioSrvEngine: 0 SaveDebugImageEngine: 0 #engine连接 connects: + WSServerEngine_0_0: "ControlEngine_0_0 1024" VideoEngine_0_0: "VideoDecodeEngine_0_0 1024" - VideoDecodeEngine_0_0: "MoveEngine_0_0 1024" - MoveEngine_0_0: "SaveMoveImageEngine_0_0 1024" - MoveEngine_0_1: "SaveMoveInfoEngine_0_0 1024" - SaveMoveImageEngine_0_0: "TrainStep1DataReadEngine_0_0 1024" - TrainStep1DataReadEngine_0_0: "TrainStep1InferenceEngine_0_0 1024" - TrainStep1InferenceEngine_0_0: "TrainStep1FilterEngine_0_0 1024" - TrainStep1FilterEngine_0_0: "TrainDivideEngine_0_0 1024" - TrainDivideEngine_0_0: "TrainStep2DataReadEngine_0_0 1024" - TrainStep2DataReadEngine_0_0: "TrainStep2InferenceEngine_0_0 1024" - TrainStep2InferenceEngine_0_0: "TrainCharacterConversionEngine_0_0 1024" - TrainCharacterConversionEngine_0_0: "SelectBestEngine_0_0 1024" - TrainCharacterConversionEngine_0_1: "SaveDebugImageEngine_0_0 1024" - SelectBestEngine_0_0: "SaveResultCSVEngine_0_0 1024" - SaveResultCSVEngine_0_0: "ToHttpSrvEngine_0_0 1024" - SaveResultCSVEngine_0_1: "ToMinioSrvEngine_0_0 1024" + VideoEngine_1_0: "VideoDecodeEngine_1_0 1024" + VideoEngine_2_0: "VideoDecodeEngine_2_0 1024" + VideoDecodeEngine_0_0: "ControlEngine_0_1 1024" + VideoDecodeEngine_1_0: "ControlEngine_0_1 1024" + VideoDecodeEngine_2_0: "ControlEngine_0_1 1024" + ControlEngine_0_0: "WSServerEngine_0_0 1024" + ControlEngine_0_1: "ContainerStep1InferenceEngine_0_0 1024" + ControlEngine_0_2: "CornerInferenceEngine_0_0 1024" + ControlEngine_0_3: "SaveMoveInfoEngine_0_0 1024" + ControlEngine_0_4: "SaveMoveImageEngine_0_0 1024" + ContainerStep1InferenceEngine_0_0: "Step1MergeEngine_0_0 1024" + CornerInferenceEngine_0_0: "Step1MergeEngine_0_1 1024" + Step1MergeEngine_0_0: "ContainerStep2InferenceEngine_0_0 1024" + ContainerStep2InferenceEngine_0_0: "ContainerCharacterConversionEngine_0_0 1024" + ContainerCharacterConversionEngine_0_0: "ContainerDivideEngine_0_0 1024" + ContainerCharacterConversionEngine_0_1: "ContainerDivideEngine_1_0 1024" + ContainerCharacterConversionEngine_0_2: "ContainerDivideEngine_2_0 1024" + ContainerCharacterConversionEngine_0_3: "SaveDebugImageEngine_0_0 1024" + ContainerDivideEngine_0_0: "SelectBestEngine_0_0 1024" + ContainerDivideEngine_1_0: "SelectBestEngine_0_0 1024" + ContainerDivideEngine_2_0: "SelectBestEngine_0_0 1024" + SelectBestEngine_0_0: "WSServerEngine_0_0 1024" + SelectBestEngine_0_1: "ToMinioSrvEngine_0_0 1024" + SelectBestEngine_0_2: "SaveResultCSVEngine_0_0 1024" diff --git a/app/config/model_config.yaml b/app/config/model_config.yaml index 030d784..4736eaa 100644 --- a/app/config/model_config.yaml +++ b/app/config/model_config.yaml @@ -39,9 +39,17 @@ train_step2_model: container_step1_model: model_path: "./model/container_step1/con1.engine" score_threshold: 0.6 - class: [] + class: ["CONTAINERNUM","CONTAINERNUM_REVERSE"] # ,"SPACE_T","SPACENX_T","SPACEG_T","SPACEP_T","SPACEP_T" # 集装箱字符识别 container_step2_model: model_path: "./model/container_step2/con2.engine" score_threshold: 0.7 - class: [] \ No newline at end of file + class: ["0","1","2","3","4","5","6","7","8","9", + "A","B","C","D","E","F","G","H","I","J","K","L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V","W", "X", "Y", "Z", + "change", "load", "m", "self", "t", "volume", "meter",")", "(", "?", "-" + ] +# 集装箱箱角识别 +corner_model: + model_path: "./model/corner/corner.engine" + score_threshold: 0.7 + class: ["CNTR_CORNER","CNTR_CORNER_TOP"] \ No newline at end of file diff --git a/common/CommonStruct.h b/common/CommonStruct.h index dbf747d..70a9219 100644 --- a/common/CommonStruct.h +++ b/common/CommonStruct.h @@ -380,4 +380,22 @@ typedef struct } DetectResultData; + +// 存图数据 +typedef struct +{ + // 数据来源标识 + int iDataSource; + std::string strDetectDate; + std::string strDetectTime; + // 帧序号 + int iFrameId; + // 箱号大框以及对应小框的集合 + Step2ResultData step2ResultData; + // 箱角大框 + std::vector vecCornerResultData; + // 图片 + cv::Mat cvImage; +} SaveDebugImgData; + #endif //TRAIN_COMMONSTRUCT_H diff --git a/config/config.yaml b/config/config.yaml index d0b5b93..b779733 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -77,6 +77,10 @@ identify: target_min_y: 550 # 单次识别最大帧数 max_identify_frame: 600 + # 两个箱子的箱角最大差值X + max_container_space_x: 600 + # 两个箱子的箱角最大差值Y + max_container_space_y: 500 # websocket_server 的服务端参数 wsocket_server: diff --git a/config/matrix.yaml b/config/matrix.yaml index 4218bd5..084f9f5 100644 --- a/config/matrix.yaml +++ b/config/matrix.yaml @@ -38,7 +38,7 @@ connects: ControlEngine_0_1: "ContainerStep1InferenceEngine_0_0 1024" ControlEngine_0_2: "CornerInferenceEngine_0_0 1024" ControlEngine_0_3: "SaveMoveInfoEngine_0_0 1024" - ControlEngine_0_4: "SaveMoveImageEngine_0_0 1024" + ControlEngine_0_4: "SaveMoveImageEngine_0_0 1024" ContainerStep1InferenceEngine_0_0: "Step1MergeEngine_0_0 1024" CornerInferenceEngine_0_0: "Step1MergeEngine_0_1 1024" Step1MergeEngine_0_0: "ContainerStep2InferenceEngine_0_0 1024" diff --git a/engine/CharacterConversionEngine/ContainerCharacterConversionEngine.cpp b/engine/CharacterConversionEngine/ContainerCharacterConversionEngine.cpp index 98be92a..436362f 100644 --- a/engine/CharacterConversionEngine/ContainerCharacterConversionEngine.cpp +++ b/engine/CharacterConversionEngine/ContainerCharacterConversionEngine.cpp @@ -1 +1 @@ -#include "ContainerCharacterConversionEngine.h" using namespace ai_matrix; namespace { //按照x坐标排列 bool CompareX(const SingleData &v1, const SingleData &v2) { return (v1.fLTX < v2.fLTX); } //按照y坐标排列 bool CompareY(const SingleData &v1, const SingleData &v2) { return (v1.fLTY < v2.fLTY); } } ContainerCharacterConversionEngine::ContainerCharacterConversionEngine() {} ContainerCharacterConversionEngine::~ContainerCharacterConversionEngine() {} APP_ERROR ContainerCharacterConversionEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort3_ = engineName_ + "_" + std::to_string(engineId_) + "_3"; this->modelConfig_ = Config::getins()->getModelByContainerStep2Config(); this->baseConfig_ = Config::getins()->getBaseConfig(); LogInfo << "ContainerCharacterConversionEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerCharacterConversionEngine::DeInit() { LogInfo << "ContainerCharacterConversionEngine DeInit ok"; return APP_ERR_OK; } /** * 验证集装箱号是否满足规则(前10位依次与2^0 ~2^9相乘)/11 所得余数,即是校验位) * inParam : std::string &strContainerNo 集装箱号信息 * outParam: N/A * return : true(校验通过)/false(校验失败) */ bool ContainerCharacterConversionEngine::verifyContainerNo(std::string &strContainerNo) { bool bChkFlag = false; if(strContainerNo.length() != 11) { return bChkFlag; } int iSum = 0; for (int i = 0; i < strContainerNo.length()-1; ++i) { iSum += this->mapExchange_[strContainerNo.substr(i, 1)] * int(pow(2.0, i)); } //当校验位等于10时要继续模运算,iSum % 11 % 10,保证最终结果为0~9之间的数 int iChkValue = iSum % 11 % 10; if (iChkValue == atoi(strContainerNo.substr(strContainerNo.length()-1, 1).c_str())) { bChkFlag = true; } return bChkFlag; } void ContainerCharacterConversionEngine::transContainerType(Step2ResultData &step2ResultData, std::map> &mapLine) { TransInfo info; info.iLine = 1; //集装箱型号(4位 字母或数字) if (mapLine.find(3) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(3).size(); j++) { strTemp += vecClassNames_.at(mapLine.at(3).at(j).iClassId); } int nTypesize = strTemp.length(); nTypesize = nTypesize > 4 ? 4 : nTypesize; info.strTmpResult = strTemp.substr(0, nTypesize); } if (info.strTmpResult.length() != 4) { info.bIsChkFlag = false; } // step2ResultData.transInfo = info; } /** * 集装箱框内容转换 * inParam : std::map> &mapLine * outParam: TransSubData &transSubData * return : N/A */ void ContainerCharacterConversionEngine::transContainerNum(Step2ResultData &step2ResultData, std::map> &mapLine) { TransInfo info; info.iLine = 0; // 箱主代码+设备识别码(4位英文字母) if (mapLine.find(0) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(0).size(); j++) { std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(0).at(j).iClassId); // 过滤非字母 if (strOne[0] < 'A' || strOne[0] > 'Z') { // LogDebug << strOne << " not A-Z in container"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(0).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(0).at(j).fScore; } info.strTmpResult += strTemp; } // 箱号(6位数字) if (mapLine.find(1) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(1).size(); j++) { std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(1).at(j).iClassId); // 过滤非数字 if (strOne[0] < '0' || strOne[0] > '9') { // LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in num"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(1).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(1).at(j).fScore; } info.strTmpResult += strTemp; } //校验码(1位数字) if (mapLine.find(2) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(2).size(); j++) { //过滤非数字 std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(2).at(j).iClassId); if (strOne[0] < '0' || strOne[0] > '9') { // LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in container_2"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(2).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(2).at(j).fScore; } info.strTmpResult += strTemp; } if (this->verifyContainerNo(info.strTmpResult)) { info.bIsChkFlag = true; } else { info.strTmpResult = "invalid-" + info.strTmpResult; } step2ResultData.transInfo = info; } APP_ERROR ContainerCharacterConversionEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms continue; } std::shared_ptr pVStep2OutputData = std::static_pointer_cast(pVoidData0); if (pVStep2OutputData->bIsEnd) { outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast(pVStep2OutputData), true); outputQueMap_[strPort3_]->push(std::static_pointer_cast(pVStep2OutputData), true); } std::vector vecSingleData = pVStep2OutputData->step2ResultData.vecSingleData; if (pVStep2OutputData->step2ResultData.fScore == 0.0f) continue; std::map> mapLine; for (auto & it_singleData : vecSingleData) { mapLine[it_singleData.iLine].push_back(it_singleData); } bool bSortByX = (pVStep2OutputData->step2ResultData.fRBY - pVStep2OutputData->step2ResultData.fLTY) < ((pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX) * 1.5); //每一行按x坐标排序 for (auto & it : mapLine) { if (it.second.size() > 2) { std::set setX; std::set setY; for (auto & it_singleData : it.second) { setX.insert(it_singleData.fLTX); setY.insert(it_singleData.fLTY); } float X = *setX.rbegin() - *setX.begin(); float Y = *setY.rbegin() - *setY.begin(); bSortByX = (X > Y); } if (bSortByX) { std::sort(it.second.begin(), it.second.end(), CompareX); } else { std::sort(it.second.begin(), it.second.end(), CompareY); } // std::string strTemp; // for (auto & it_singleData : it.second) // { // strTemp += this->modelConfig_.vecClass.at(it_singleData.iClassId); // } } switch (pVStep2OutputData->step2ResultData.iClassId) { case 0: this->transContainerNum(pVStep2OutputData->step2ResultData, mapLine); break; default: break; } // 模型识别不稳定时才用。 // if (bSortByX && pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag) // { // if (mapLine.find(0) != mapLine.end() && mapLine.find(1) != mapLine.end()) // { // if (mapLine.at(1).at(0).fLTX < mapLine.at(0).at(0).fLTX) // { // pVStep2OutputData->step2ResultData.transInfo.strTmpResult = "invalid-" + pVStep2OutputData->step2ResultData.transInfo.strTmpResult; // pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag = false; // } // } // } outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast(pVStep2OutputData), true); outputQueMap_[strPort3_]->push(std::static_pointer_cast(pVStep2OutputData), true); } return APP_ERR_OK; } \ No newline at end of file +#include "ContainerCharacterConversionEngine.h" using namespace ai_matrix; namespace { //按照x坐标排列 bool CompareX(const SingleData &v1, const SingleData &v2) { return (v1.fLTX < v2.fLTX); } //按照y坐标排列 bool CompareY(const SingleData &v1, const SingleData &v2) { return (v1.fLTY < v2.fLTY); } } ContainerCharacterConversionEngine::ContainerCharacterConversionEngine() {} ContainerCharacterConversionEngine::~ContainerCharacterConversionEngine() {} APP_ERROR ContainerCharacterConversionEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort3_ = engineName_ + "_" + std::to_string(engineId_) + "_3"; this->modelConfig_ = Config::getins()->getModelByContainerStep2Config(); this->baseConfig_ = Config::getins()->getBaseConfig(); LogInfo << "ContainerCharacterConversionEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerCharacterConversionEngine::DeInit() { LogInfo << "ContainerCharacterConversionEngine DeInit ok"; return APP_ERR_OK; } /** * 验证集装箱号是否满足规则(前10位依次与2^0 ~2^9相乘)/11 所得余数,即是校验位) * inParam : std::string &strContainerNo 集装箱号信息 * outParam: N/A * return : true(校验通过)/false(校验失败) */ bool ContainerCharacterConversionEngine::verifyContainerNo(std::string &strContainerNo) { bool bChkFlag = false; if(strContainerNo.length() != 11) { return bChkFlag; } int iSum = 0; for (int i = 0; i < strContainerNo.length()-1; ++i) { iSum += this->mapExchange_[strContainerNo.substr(i, 1)] * int(pow(2.0, i)); } //当校验位等于10时要继续模运算,iSum % 11 % 10,保证最终结果为0~9之间的数 int iChkValue = iSum % 11 % 10; if (iChkValue == atoi(strContainerNo.substr(strContainerNo.length()-1, 1).c_str())) { bChkFlag = true; } return bChkFlag; } void ContainerCharacterConversionEngine::transContainerType(Step2ResultData &step2ResultData, std::map> &mapLine) { TransInfo info; info.iLine = 1; //集装箱型号(4位 字母或数字) if (mapLine.find(3) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(3).size(); j++) { strTemp += vecClassNames_.at(mapLine.at(3).at(j).iClassId); } int nTypesize = strTemp.length(); nTypesize = nTypesize > 4 ? 4 : nTypesize; info.strTmpResult = strTemp.substr(0, nTypesize); } if (info.strTmpResult.length() != 4) { info.bIsChkFlag = false; } // step2ResultData.transInfo = info; } /** * 集装箱框内容转换 * inParam : std::map> &mapLine * outParam: TransSubData &transSubData * return : N/A */ void ContainerCharacterConversionEngine::transContainerNum(Step2ResultData &step2ResultData, std::map> &mapLine) { TransInfo info; info.iLine = 0; // 箱主代码+设备识别码(4位英文字母) if (mapLine.find(0) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(0).size(); j++) { std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(0).at(j).iClassId); // 过滤非字母 if (strOne[0] < 'A' || strOne[0] > 'Z') { // LogDebug << strOne << " not A-Z in container"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(0).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(0).at(j).fScore; } info.strTmpResult += strTemp; } // 箱号(6位数字) if (mapLine.find(1) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(1).size(); j++) { std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(1).at(j).iClassId); // 过滤非数字 if (strOne[0] < '0' || strOne[0] > '9') { // LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in num"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(1).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(1).at(j).fScore; } info.strTmpResult += strTemp; } //校验码(1位数字) if (mapLine.find(2) != mapLine.end()) { std::string strTemp; for (auto j = 0; j < mapLine.at(2).size(); j++) { //过滤非数字 std::string strOne = this->modelConfig_.vecClass.at(mapLine.at(2).at(j).iClassId); if (strOne[0] < '0' || strOne[0] > '9') { // LogDebug << "engineId:" << engineId_ << " " << strOne << " not digit in container_2"; continue; } strTemp += strOne; info.vecValue.emplace_back(strOne); info.vecScore.emplace_back(mapLine.at(2).at(j).fScore); step2ResultData.fSubScoreSum += mapLine.at(2).at(j).fScore; } info.strTmpResult += strTemp; } if (this->verifyContainerNo(info.strTmpResult)) { info.bIsChkFlag = true; } else { info.strTmpResult = "invalid-" + info.strTmpResult; } step2ResultData.transInfo = info; } APP_ERROR ContainerCharacterConversionEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms continue; } std::shared_ptr pVStep2OutputData = std::static_pointer_cast(pVoidData0); std::shared_ptr pSaveDebugImgData = std::make_shared(); pSaveDebugImgData->iFrameId = pVStep2OutputData->iFrameId; pSaveDebugImgData->iDataSource = pVStep2OutputData->iDataSource; pSaveDebugImgData->strDetectDate = pVStep2OutputData->strDetectDate; pSaveDebugImgData->strDetectTime = pVStep2OutputData->strDetectTime; pSaveDebugImgData->cvImage = pVStep2OutputData->cvImage.clone(); pSaveDebugImgData->step2ResultData = pVStep2OutputData->step2ResultData; pSaveDebugImgData->vecCornerResultData = pVStep2OutputData->vecCornerResultData; if (pVStep2OutputData->bIsEnd) { outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast(pVStep2OutputData), true); // outputQueMap_[strPort3_]->push(std::static_pointer_cast(pSaveDebugImgData), true); continue; } std::vector vecSingleData = pVStep2OutputData->step2ResultData.vecSingleData; if (pVStep2OutputData->step2ResultData.fScore == 0.0f) { outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast(pVStep2OutputData), true); // outputQueMap_[strPort3_]->push(std::static_pointer_cast(pSaveDebugImgData), true); continue; } std::map> mapLine; for (auto & it_singleData : vecSingleData) { mapLine[it_singleData.iLine].push_back(it_singleData); } bool bSortByX = (pVStep2OutputData->step2ResultData.fRBY - pVStep2OutputData->step2ResultData.fLTY) < ((pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX) * 1.5); //每一行按x坐标排序 for (auto & it : mapLine) { if (it.second.size() > 2) { std::set setX; std::set setY; for (auto & it_singleData : it.second) { setX.insert(it_singleData.fLTX); setY.insert(it_singleData.fLTY); } float X = *setX.rbegin() - *setX.begin(); float Y = *setY.rbegin() - *setY.begin(); bSortByX = (X > Y); } if (bSortByX) { std::sort(it.second.begin(), it.second.end(), CompareX); } else { std::sort(it.second.begin(), it.second.end(), CompareY); } // std::string strTemp; // for (auto & it_singleData : it.second) // { // strTemp += this->modelConfig_.vecClass.at(it_singleData.iClassId); // } } switch (pVStep2OutputData->step2ResultData.iClassId) { case 0: this->transContainerNum(pVStep2OutputData->step2ResultData, mapLine); break; default: break; } // 模型识别不稳定时才用。 // if (bSortByX && pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag) // { // if (mapLine.find(0) != mapLine.end() && mapLine.find(1) != mapLine.end()) // { // if (mapLine.at(1).at(0).fLTX < mapLine.at(0).at(0).fLTX) // { // pVStep2OutputData->step2ResultData.transInfo.strTmpResult = "invalid-" + pVStep2OutputData->step2ResultData.transInfo.strTmpResult; // pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag = false; // } // } // } pSaveDebugImgData->step2ResultData = pVStep2OutputData->step2ResultData; outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_" + std::to_string(pVStep2OutputData->iDataSource)]->push(std::static_pointer_cast(pVStep2OutputData), true); // outputQueMap_[strPort3_]->push(std::static_pointer_cast(pSaveDebugImgData), true); } return APP_ERR_OK; } \ No newline at end of file diff --git a/engine/ControlEngine/ControlEngine.cpp b/engine/ControlEngine/ControlEngine.cpp index 100589c..14dc312 100644 --- a/engine/ControlEngine/ControlEngine.cpp +++ b/engine/ControlEngine/ControlEngine.cpp @@ -47,7 +47,9 @@ void ControlEngine::initParam() this->strDetectDate_ = ""; for (int i = 0; i < this->vecDataSourceConfig_.size(); ++i) { - this->mapDetectNO_[i] = 1; + this->mapDetectNO_[i] = 0; + this->mapIdentifyType_[i] = IDENTIFY_INIT; + } } @@ -62,18 +64,10 @@ void ControlEngine::endIdentify(int iDataSource) outputQueMap_[strPort1_]->push(std::static_pointer_cast(pVDetectInfo), true); outputQueMap_[strPort2_]->push(std::static_pointer_cast(pVDetectInfo), true); - this->mapDetectNO_[iDataSource] = 1; + this->mapDetectNO_[iDataSource] = 0; + this->mapIdentifyType_[iDataSource] = IDENTIFY_INIT; - bool bAllEnd = true; - for (const auto & dataSource_it : this->mapDetectNO_) - { - if (dataSource_it.second != 1) bAllEnd = false; - } - if (bAllEnd) - { - g_identify_type = IDENTIFY_INIT; - this->strDetectDate_ = ""; - } + LogInfo << " 数据源:" << iDataSource << " --- 识别结束!"; } void ControlEngine::sendWSEngine(std::string msg) @@ -83,6 +77,19 @@ void ControlEngine::sendWSEngine(std::string msg) outputQueMap_[strPort0_]->push(std::static_pointer_cast(std::make_shared(msg))); } +bool ControlEngine::isDetecting() +{ + for (const auto & dataSource : this->mapIdentifyType_) + { + if (dataSource.second == IDENTIFY_START) + { + return true; + } + } + + return false; +} + void ControlEngine::detectControl(std::shared_ptr pWSServerOrder) { Json::CharReaderBuilder readerBuilder; @@ -116,24 +123,25 @@ void ControlEngine::detectControl(std::shared_ptr pWSServerOrder) switch (jvOrder["commandType"].asInt()) { case IDENTIFY_START: - if (g_identify_type == 1) + + if (this->isDetecting()) { std::string msg = "当前正在识别,无需重复发送识别信号"; LogWarn << msg; this->sendWSEngine(msg); break; } - g_identify_type = IDENTIFY_START; + this->mapIdentifyType_ = {{0, IDENTIFY_START}, {1, IDENTIFY_START}, {2, IDENTIFY_START}}; break; case IDENTIFY_STOP: - if (!g_identify_type) + if (!this->isDetecting()) { std::string msg = "当前已停止识别,无需重复发送结束信号"; LogWarn << msg; this->sendWSEngine(msg); break; } - g_identify_type = IDENTIFY_INIT; + this->mapIdentifyType_ = {{0, IDENTIFY_INIT}, {1, IDENTIFY_INIT}, {2, IDENTIFY_INIT}}; break; case IDENTIFY_RECORD: if (!jvOrder.isMember("containerNo")) @@ -181,29 +189,36 @@ APP_ERROR ControlEngine::Process() if (pProcessData->bIsEnd) { - // 仅读是视频模式下会进行 - if (this->mapDetectNO_[pProcessData->iDataSource] == 1) continue; + if (!this->isDetecting()) continue; this->endIdentify(pProcessData->iDataSource); - LogInfo << "数据源:" << pProcessData->iDataSource << " 视频画面播放结束:停止识别!"; + LogInfo << "数据源:" << pProcessData->iDataSource << " 画面读取结束:停止识别!"; continue; } - if (!g_identify_type) + if (!this->isDetecting()) { - if (this->mapDetectNO_[pProcessData->iDataSource] != 1) + if (this->mapDetectNO_[pProcessData->iDataSource] > 0) { this->endIdentify(pProcessData->iDataSource); } + this->strDetectDate_ = ""; + continue; + } + + if (this->mapIdentifyType_[pProcessData->iDataSource] == IDENTIFY_INIT) + { continue; } if (this->mapDetectNO_[pProcessData->iDataSource] > this->identifyConfig_.iMaxIdentifyFrame) { + LogInfo << " 数据源:" << pProcessData->iDataSource << " 超过最大允许识别帧数:" << this->identifyConfig_.iMaxIdentifyFrame << " 停止识别!"; this->endIdentify(pProcessData->iDataSource); - LogInfo << "数据源:" << pProcessData->iDataSource << " 超过最大允许识别帧数:" << this->identifyConfig_.iMaxIdentifyFrame << " 停止识别!"; continue; } + this->mapDetectNO_[pProcessData->iDataSource]++; + cv::Mat image(pProcessData->dataSourceInfo.iHeight, pProcessData->dataSourceInfo.iWidth, CV_8UC3, @@ -245,14 +260,14 @@ APP_ERROR ControlEngine::Process() outputQueMap_[strPort3_]->push(std::static_pointer_cast(pVDetectInfo), true); // 存图 -// std::shared_ptr pSaveImgData = std::make_shared(); -// pSaveImgData->strFilePath = strFilePath; -// pSaveImgData->strFileName = std::to_string(this->mapDetectNO_[pProcessData->iDataSource]) + "_" + std::to_string(pProcessData->iDataSource) + ".jpg"; -// pSaveImgData->cvImage = image; -// pSaveImgData->bIsEnd = pProcessData->bIsEnd; -// outputQueMap_[strPort4_]->push(std::static_pointer_cast(pSaveImgData), true); + std::shared_ptr pSaveImgData = std::make_shared(); + pSaveImgData->strFilePath = strFilePath; + pSaveImgData->strFileName = std::to_string(this->mapDetectNO_[pProcessData->iDataSource]) + "_" + std::to_string(pProcessData->iDataSource) + ".jpg"; + pSaveImgData->cvImage = image; + pSaveImgData->bIsEnd = pProcessData->bIsEnd; + outputQueMap_[strPort4_]->push(std::static_pointer_cast(pSaveImgData), true); + - this->mapDetectNO_[pProcessData->iDataSource]++; } } diff --git a/engine/ControlEngine/ControlEngine.h b/engine/ControlEngine/ControlEngine.h index e832836..2af0e80 100644 --- a/engine/ControlEngine/ControlEngine.h +++ b/engine/ControlEngine/ControlEngine.h @@ -36,6 +36,7 @@ private: uint32_t iDetectNO_ = 1; //动态检测数据编号 std::map mapDetectNO_; + std::map mapIdentifyType_; std::string strDetectDate_; std::string strDetectTime_; @@ -45,6 +46,7 @@ private: void endIdentify(int iDataSource); void sendWSEngine(std::string msg); void detectControl(std::shared_ptr pWSServerOrder); + bool isDetecting(); }; diff --git a/engine/DataSourceEngine/VideoEngine.cpp b/engine/DataSourceEngine/VideoEngine.cpp index 1837309..33b34eb 100644 --- a/engine/DataSourceEngine/VideoEngine.cpp +++ b/engine/DataSourceEngine/VideoEngine.cpp @@ -1 +1 @@ -#include "VideoEngine.h" using namespace ai_matrix; namespace { const int LOW_THRESHOLD = 128; const int MAX_THRESHOLD = 4096; const uint16_t DELAY_TIME = 10000; } VideoEngine::VideoEngine() {} VideoEngine::~VideoEngine() {} APP_ERROR VideoEngine::Init() { std::vector vecDataSourceConfig = Config::getins()->getAllDataSourceConfig(); if (vecDataSourceConfig.size() <= this->engineId_) { LogWarn << " -- " << engineName_ << "_" << engineId_ << " dataSource no set, Engine DeInit"; return APP_ERR_OK; } dataSourceConfig_ = vecDataSourceConfig.at(engineId_); strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; LogInfo << "engineId_:" << engineId_ << " VideoEngine Init ok"; return APP_ERR_OK; } APP_ERROR VideoEngine::DeInit() { ResetCamera(); LogInfo << "engineId_:" << engineId_ << " VideoEngine DeInit ok"; return APP_ERR_OK; } void VideoEngine::ResetCamera() { if (pFormatCtx_ != nullptr) { // clear th cache of the queue avformat_close_input(&pFormatCtx_); pFormatCtx_ = nullptr; } } APP_ERROR VideoEngine::ConnectCamera() { pFormatCtx_ = CreateFormatContext(); // create context if (pFormatCtx_ == nullptr) { LogError << "engineId_:" << engineId_ << " pFormatCtx_ null!"; return APP_ERR_COMM_FAILURE; } //0-代表输入 av_dump_format(pFormatCtx_, 0, dataSourceConfig_.strUrl.c_str(), 0); // get stream infomation int iRet = APP_ERR_OK; iRet = GetStreamInfo(); if (iRet != APP_ERR_OK) { LogError << "engineId_:" << engineId_ << " Stream Info Check failed, iRet = " << iRet; return APP_ERR_COMM_FAILURE; } return APP_ERR_OK; } APP_ERROR VideoEngine::GetStreamInfo() { if (pFormatCtx_ != nullptr) { iVideoStream_ = -1; iAudioStream_ = -1; //frameInfo_.iFrameId = 0; //帧号从0开始 for (unsigned int i = 0; i < pFormatCtx_->nb_streams; i++) { AVStream *inStream = pFormatCtx_->streams[i]; if (inStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { iVideoStream_ = i; frameInfo_.iHeight = inStream->codecpar->height; frameInfo_.iWidth = inStream->codecpar->width; //获取帧率,帧率的打印都在流中的两个成员.且应取平均帧率为先,为{x,0}或者{0,1}则取实时帧率 if (inStream->avg_frame_rate.den == 0 || (inStream->avg_frame_rate.num == 0 && inStream->avg_frame_rate.den == 1)) { frameInfo_.iRate = inStream->r_frame_rate.num / inStream->r_frame_rate.den; } else { frameInfo_.iRate = inStream->avg_frame_rate.num / inStream->avg_frame_rate.den; } frameInfo_.iRate = frameInfo_.iRate == 0 ? 25 : frameInfo_.iRate; LogDebug << "engineId_:" << engineId_ << " width:" << frameInfo_.iWidth << " height:" << frameInfo_.iHeight << " rate:" << frameInfo_.iRate << " iVideoStream_:" << iVideoStream_; } // else if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) // { // iAudioStream_ = i; // LogDebug << "engineId_:" << engineId_ << " iAudioStream_:" << iAudioStream_; // } } if (iVideoStream_ == -1) { LogError << "engineId_:" << engineId_ << " Didn't find a video stream!"; return APP_ERR_COMM_FAILURE; } if (frameInfo_.iHeight < LOW_THRESHOLD || frameInfo_.iWidth < LOW_THRESHOLD || frameInfo_.iHeight > MAX_THRESHOLD || frameInfo_.iWidth > MAX_THRESHOLD) { LogError << "engineId_:" << engineId_ << " Size of frame is not supported in DVPP Video Decode!"; return APP_ERR_COMM_FAILURE; } pCodecParameters_ = pFormatCtx_->streams[iVideoStream_]->codecpar; } return APP_ERR_OK; } AVFormatContext *VideoEngine::CreateFormatContext() { // create message for stream pull AVFormatContext *pFormatContext = nullptr; AVDictionary *pOptions = nullptr; // formatContext = avformat_alloc_context(); if (dataSourceConfig_.strUrl.find("rtsp:") != std::string::npos) // rtsp { //设置缓存大小,1080p可将值调大 av_dict_set(&pOptions, "buffer_size", "8192000", 0); //以tcp方式打开,如果以udp方式打开将tcp替换为udp av_dict_set(&pOptions, "rtsp_transport", "tcp", 0); //设置超时断开连接时间,单位微秒,3000000表示3秒 av_dict_set(&pOptions, "stimeout", "3000000", 0); //设置最大时延,单位微秒,1000000表示1秒 av_dict_set(&pOptions, "max_delay", "1000000", 0); //自动开启线程数 av_dict_set(&pOptions, "threads", "auto", 0); } //av_register_all(); //注册所有支持的格式(这里一定注册这些,否则会因为协议解析问题报错!!!) //avcodec_register_all(); //注册编解码器 //avformat_network_init(); //注册网格格式,如果为本地文件则可以去掉该代码 int iRet = avformat_open_input(&pFormatContext, dataSourceConfig_.strUrl.c_str(), nullptr, &pOptions); if (nullptr != pOptions) { av_dict_free(&pOptions); } if (iRet != 0) { LogError << "engineId_:" << engineId_ << " Couldn't open input stream " << dataSourceConfig_.strUrl.c_str() << ", iRet=" << iRet; return nullptr; } // pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // pFormatContext->pb->flags |= AVIO_FLAG_NONBLOCK; // av_dict_set(&pFormatContext->interrupt_callback.callback, "timeout", "3000", 0); // iRet = avio_open2(&pFormatContext->pb, dataSourceConfig_.strUrl.c_str(), AVIO_FLAG_READ, NULL, NULL) < 0; // { // // 处理错误 // LogError << "engineId_:" << engineId_ << "avio_open2 iRet=" << iRet; // return nullptr; // } iRet = avformat_find_stream_info(pFormatContext, nullptr); if (iRet != 0) { LogError << "engineId_:" << engineId_ << " Couldn't find stream information, iRet = " << iRet; return nullptr; } return pFormatContext; } //av_read_frame的中断回调函数 // int VideoEngine::InterruptCallback(void *pData) // { // TimeoutContext* pTimeOutCtx = (TimeoutContext*)pData; // LogDebug << "InterruptCallback i64Timeout:" << pTimeOutCtx->i64Timeout; // return std::chrono::duration_cast( // std::chrono::system_clock::now().time_since_epoch()) // .count() >= pTimeOutCtx->i64Timeout // ? AVERROR_EXIT // : 0; // } APP_ERROR VideoEngine::Process() { int iRet = APP_ERR_OK; // Pull data cyclically AVPacket pkt; while (!isStop_) { //重连相机 if (bConnectFlag_) { iRet = ConnectCamera(); if (iRet == APP_ERR_OK) { LogInfo << "engineId_:" << engineId_ << " Start the stream......"; bConnectFlag_ = false; } else { // outputQueMap_[strPort1_]->push(std::static_pointer_cast(std::make_shared("摄像头连接失败!"))); ResetCamera(); bConnectFlag_ = true; std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒后重连 continue; } } //设置av_read_frame中断函数 (中断函数中超过1s,则中断处理) // TimeoutContext timeoutCtx = { std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() + 1000 }; // pFormatCtx_->interrupt_callback.callback = &VideoEngine::InterruptCallback; // pFormatCtx_->interrupt_callback.opaque = &timeoutCtx; av_init_packet(&pkt); //init pkt iRet = av_read_frame(pFormatCtx_, &pkt); //需要一直读取,否则获取到的是历史数据 if (iRet != 0) { av_packet_unref(&pkt); if (dataSourceConfig_.strUrl.find("rtsp:") != std::string::npos) { LogError << "engineId_:" << engineId_ << " Read frame failed, reconnect iRet:" << iRet; //重连相机 ResetCamera(); bConnectFlag_ = true; } else { // LogWarn << "----- 视频播放完毕 -----"; // //重连相机 // ResetCamera(); // bConnectFlag_ = true; //组织数据 std::shared_ptr pProcessData = std::make_shared(); pProcessData->iDataSource = this->engineId_; pProcessData->sourceFrameData.i64TimeStamp = TimeUtil::getins()->getCurrentTimeMillis(true); pProcessData->bIsEnd = true; //push端口0,视频解码 iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast(pProcessData), true); if (iRet != APP_ERR_OK) { LogError << "数据推动失败,解码引擎关闭..."; } std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒 }; continue; } if (pkt.stream_index == iVideoStream_) //只解码视频流 { // LogDebug << "iRet:" << iRet << " pkt.size:" << pkt.size; if (pkt.size <= 0) { LogError << "engineId_:" << engineId_ << " Invalid pkt.size: " << pkt.size; av_packet_unref(&pkt); continue; } if (dataSourceConfig_.strUrl.find(".mp4") != std::string::npos) { const char szStartCode[4] = {0, 0, 0, 1}; if (bIsAvc_ || memcmp(szStartCode, pkt.data, 4) != 0) { // is avc1 code, have no start code of H264 int iLen = 0; uint8_t *p = pkt.data; bIsAvc_ = true; do { // add start_code for each NAL, one frame may have multi NALs. iLen = ntohl(*((long *)p)); memcpy(p, szStartCode, 4); p += 4; p += iLen; if (p >= pkt.data + pkt.size) { break; } } while (true); } } void* pH264Buffer = nullptr; pH264Buffer = new uint8_t[pkt.size]; memcpy(pH264Buffer, pkt.data, pkt.size); //组织数据 std::shared_ptr pProcessData = std::make_shared(); pProcessData->iDataSource = this->engineId_; pProcessData->pCodecParameters_ = this->pCodecParameters_; pProcessData->dataSourceInfo = frameInfo_; pProcessData->sourceFrameData.i64TimeStamp = TimeUtil::getins()->getCurrentTimeMillis(true); pProcessData->sourceFrameData.iSize = pkt.size; pProcessData->sourceFrameData.pData.reset(pH264Buffer, [](void* data){if(data) {delete[] data; data = nullptr;}}); //智能指针管理内存 //push端口0,视频解码 iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast(pProcessData), true); if (iRet != APP_ERR_OK) { LogError << "数据推动失败,解码引擎关闭..."; } } else { // LogError << "engineId_:" << engineId_ << " stream err stream_index:" << pkt.stream_index; } av_packet_unref(&pkt); //unref if (dataSourceConfig_.strUrl.find("rtsp:") == std::string::npos) // 如果不是rtsp,定时发送 { std::this_thread::sleep_for(std::chrono::milliseconds(1000 / frameInfo_.iRate)); if (this->isStop_) return APP_ERR_OK; } } return APP_ERR_OK; } \ No newline at end of file +#include "VideoEngine.h" using namespace ai_matrix; namespace { const int LOW_THRESHOLD = 128; const int MAX_THRESHOLD = 4096; const uint16_t DELAY_TIME = 10000; } VideoEngine::VideoEngine() {} VideoEngine::~VideoEngine() {} APP_ERROR VideoEngine::Init() { std::vector vecDataSourceConfig = Config::getins()->getAllDataSourceConfig(); if (vecDataSourceConfig.size() <= this->engineId_) { LogWarn << " -- " << engineName_ << "_" << engineId_ << " dataSource no set, Engine DeInit"; return APP_ERR_OK; } dataSourceConfig_ = vecDataSourceConfig.at(engineId_); strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; LogInfo << "engineId_:" << engineId_ << " VideoEngine Init ok"; return APP_ERR_OK; } APP_ERROR VideoEngine::DeInit() { ResetCamera(); LogInfo << "engineId_:" << engineId_ << " VideoEngine DeInit ok"; return APP_ERR_OK; } void VideoEngine::ResetCamera() { if (pFormatCtx_ != nullptr) { // clear th cache of the queue avformat_close_input(&pFormatCtx_); pFormatCtx_ = nullptr; } } APP_ERROR VideoEngine::ConnectCamera() { pFormatCtx_ = CreateFormatContext(); // create context if (pFormatCtx_ == nullptr) { LogError << "engineId_:" << engineId_ << " pFormatCtx_ null!"; return APP_ERR_COMM_FAILURE; } //0-代表输入 av_dump_format(pFormatCtx_, 0, dataSourceConfig_.strUrl.c_str(), 0); // get stream infomation int iRet = APP_ERR_OK; iRet = GetStreamInfo(); if (iRet != APP_ERR_OK) { LogError << "engineId_:" << engineId_ << " Stream Info Check failed, iRet = " << iRet; return APP_ERR_COMM_FAILURE; } return APP_ERR_OK; } APP_ERROR VideoEngine::GetStreamInfo() { if (pFormatCtx_ != nullptr) { iVideoStream_ = -1; iAudioStream_ = -1; //frameInfo_.iFrameId = 0; //帧号从0开始 for (unsigned int i = 0; i < pFormatCtx_->nb_streams; i++) { AVStream *inStream = pFormatCtx_->streams[i]; if (inStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { iVideoStream_ = i; frameInfo_.iHeight = inStream->codecpar->height; frameInfo_.iWidth = inStream->codecpar->width; //获取帧率,帧率的打印都在流中的两个成员.且应取平均帧率为先,为{x,0}或者{0,1}则取实时帧率 if (inStream->avg_frame_rate.den == 0 || (inStream->avg_frame_rate.num == 0 && inStream->avg_frame_rate.den == 1)) { frameInfo_.iRate = inStream->r_frame_rate.num / inStream->r_frame_rate.den; } else { frameInfo_.iRate = inStream->avg_frame_rate.num / inStream->avg_frame_rate.den; } frameInfo_.iRate = frameInfo_.iRate == 0 ? 25 : frameInfo_.iRate; LogDebug << "engineId_:" << engineId_ << " width:" << frameInfo_.iWidth << " height:" << frameInfo_.iHeight << " rate:" << frameInfo_.iRate << " iVideoStream_:" << iVideoStream_; } // else if (inStream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) // { // iAudioStream_ = i; // LogDebug << "engineId_:" << engineId_ << " iAudioStream_:" << iAudioStream_; // } } if (iVideoStream_ == -1) { LogError << "engineId_:" << engineId_ << " Didn't find a video stream!"; return APP_ERR_COMM_FAILURE; } if (frameInfo_.iHeight < LOW_THRESHOLD || frameInfo_.iWidth < LOW_THRESHOLD || frameInfo_.iHeight > MAX_THRESHOLD || frameInfo_.iWidth > MAX_THRESHOLD) { LogError << "engineId_:" << engineId_ << " Size of frame is not supported in DVPP Video Decode!"; return APP_ERR_COMM_FAILURE; } pCodecParameters_ = pFormatCtx_->streams[iVideoStream_]->codecpar; } return APP_ERR_OK; } AVFormatContext *VideoEngine::CreateFormatContext() { // create message for stream pull AVFormatContext *pFormatContext = nullptr; AVDictionary *pOptions = nullptr; // formatContext = avformat_alloc_context(); if (dataSourceConfig_.strUrl.find("rtsp:") != std::string::npos) // rtsp { //设置缓存大小,1080p可将值调大 av_dict_set(&pOptions, "buffer_size", "8192000", 0); //以tcp方式打开,如果以udp方式打开将tcp替换为udp av_dict_set(&pOptions, "rtsp_transport", "tcp", 0); //设置超时断开连接时间,单位微秒,3000000表示3秒 av_dict_set(&pOptions, "stimeout", "3000000", 0); //设置最大时延,单位微秒,1000000表示1秒 av_dict_set(&pOptions, "max_delay", "1000000", 0); //自动开启线程数 av_dict_set(&pOptions, "threads", "auto", 0); } //av_register_all(); //注册所有支持的格式(这里一定注册这些,否则会因为协议解析问题报错!!!) //avcodec_register_all(); //注册编解码器 //avformat_network_init(); //注册网格格式,如果为本地文件则可以去掉该代码 int iRet = avformat_open_input(&pFormatContext, dataSourceConfig_.strUrl.c_str(), nullptr, &pOptions); if (nullptr != pOptions) { av_dict_free(&pOptions); } if (iRet != 0) { LogError << "engineId_:" << engineId_ << " Couldn't open input stream " << dataSourceConfig_.strUrl.c_str() << ", iRet=" << iRet; return nullptr; } // pFormatContext->flags |= AVFMT_FLAG_NONBLOCK; // pFormatContext->pb->flags |= AVIO_FLAG_NONBLOCK; // av_dict_set(&pFormatContext->interrupt_callback.callback, "timeout", "3000", 0); // iRet = avio_open2(&pFormatContext->pb, dataSourceConfig_.strUrl.c_str(), AVIO_FLAG_READ, NULL, NULL) < 0; // { // // 处理错误 // LogError << "engineId_:" << engineId_ << "avio_open2 iRet=" << iRet; // return nullptr; // } iRet = avformat_find_stream_info(pFormatContext, nullptr); if (iRet != 0) { LogError << "engineId_:" << engineId_ << " Couldn't find stream information, iRet = " << iRet; return nullptr; } return pFormatContext; } //av_read_frame的中断回调函数 // int VideoEngine::InterruptCallback(void *pData) // { // TimeoutContext* pTimeOutCtx = (TimeoutContext*)pData; // LogDebug << "InterruptCallback i64Timeout:" << pTimeOutCtx->i64Timeout; // return std::chrono::duration_cast( // std::chrono::system_clock::now().time_since_epoch()) // .count() >= pTimeOutCtx->i64Timeout // ? AVERROR_EXIT // : 0; // } APP_ERROR VideoEngine::Process() { int iRet = APP_ERR_OK; // Pull data cyclically AVPacket pkt; while (!isStop_) { //重连相机 if (bConnectFlag_) { iRet = ConnectCamera(); if (iRet == APP_ERR_OK) { LogInfo << "engineId_:" << engineId_ << " Start the stream......"; bConnectFlag_ = false; } else { // outputQueMap_[strPort1_]->push(std::static_pointer_cast(std::make_shared("摄像头连接失败!"))); ResetCamera(); bConnectFlag_ = true; std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒后重连 continue; } } //设置av_read_frame中断函数 (中断函数中超过1s,则中断处理) // TimeoutContext timeoutCtx = { std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count() + 1000 }; // pFormatCtx_->interrupt_callback.callback = &VideoEngine::InterruptCallback; // pFormatCtx_->interrupt_callback.opaque = &timeoutCtx; av_init_packet(&pkt); //init pkt iRet = av_read_frame(pFormatCtx_, &pkt); //需要一直读取,否则获取到的是历史数据 if (iRet != 0) { av_packet_unref(&pkt); if (dataSourceConfig_.strUrl.find("rtsp:") != std::string::npos) { LogError << "engineId_:" << engineId_ << " Read frame failed, reconnect iRet:" << iRet; //重连相机 ResetCamera(); bConnectFlag_ = true; } else { // LogWarn << "----- 视频播放完毕 -----"; // //重连相机 // ResetCamera(); // bConnectFlag_ = true; std::this_thread::sleep_for(std::chrono::seconds(3)); //3秒 }; //组织数据 std::shared_ptr pProcessData = std::make_shared(); pProcessData->iDataSource = this->engineId_; pProcessData->sourceFrameData.i64TimeStamp = TimeUtil::getins()->getCurrentTimeMillis(true); pProcessData->bIsEnd = true; //push端口0,视频解码 iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast(pProcessData), true); if (iRet != APP_ERR_OK) { LogError << "数据推动失败,解码引擎关闭..."; } continue; } if (pkt.stream_index == iVideoStream_) //只解码视频流 { // LogDebug << "iRet:" << iRet << " pkt.size:" << pkt.size; if (pkt.size <= 0) { LogError << "engineId_:" << engineId_ << " Invalid pkt.size: " << pkt.size; av_packet_unref(&pkt); continue; } if (dataSourceConfig_.strUrl.find(".mp4") != std::string::npos) { const char szStartCode[4] = {0, 0, 0, 1}; if (bIsAvc_ || memcmp(szStartCode, pkt.data, 4) != 0) { // is avc1 code, have no start code of H264 int iLen = 0; uint8_t *p = pkt.data; bIsAvc_ = true; do { // add start_code for each NAL, one frame may have multi NALs. iLen = ntohl(*((long *)p)); memcpy(p, szStartCode, 4); p += 4; p += iLen; if (p >= pkt.data + pkt.size) { break; } } while (true); } } void* pH264Buffer = nullptr; pH264Buffer = new uint8_t[pkt.size]; memcpy(pH264Buffer, pkt.data, pkt.size); //组织数据 std::shared_ptr pProcessData = std::make_shared(); pProcessData->iDataSource = this->engineId_; pProcessData->pCodecParameters_ = this->pCodecParameters_; pProcessData->dataSourceInfo = frameInfo_; pProcessData->sourceFrameData.i64TimeStamp = TimeUtil::getins()->getCurrentTimeMillis(true); pProcessData->sourceFrameData.iSize = pkt.size; pProcessData->sourceFrameData.pData.reset(pH264Buffer, [](void* data){if(data) {delete[] data; data = nullptr;}}); //智能指针管理内存 //push端口0,视频解码 iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast(pProcessData), true); if (iRet != APP_ERR_OK) { LogError << "数据推动失败,解码引擎关闭..."; } } else { // LogError << "engineId_:" << engineId_ << " stream err stream_index:" << pkt.stream_index; } av_packet_unref(&pkt); //unref if (dataSourceConfig_.strUrl.find("rtsp:") == std::string::npos) // 如果不是rtsp,定时发送 { std::this_thread::sleep_for(std::chrono::milliseconds(1000 / frameInfo_.iRate)); if (this->isStop_) return APP_ERR_OK; } } return APP_ERR_OK; } \ No newline at end of file diff --git a/engine/DataUploadEngine/ToMinioSrvEngine.cpp b/engine/DataUploadEngine/ToMinioSrvEngine.cpp index 065d531..cfdbd6e 100644 --- a/engine/DataUploadEngine/ToMinioSrvEngine.cpp +++ b/engine/DataUploadEngine/ToMinioSrvEngine.cpp @@ -166,7 +166,7 @@ APP_ERROR ToMinioSrvEngine::Process() strMinIoPath, strLocalPath)) { - LogWarn << "数据上传失败! -- " << this->baseConfig_.strDebugResultPath; + LogWarn << "数据上传失败! -- " << strLocalPath; } else { diff --git a/engine/DecodeEngine/VideoDecodeEngine.cpp b/engine/DecodeEngine/VideoDecodeEngine.cpp index 7449fce..7f3f5a0 100644 --- a/engine/DecodeEngine/VideoDecodeEngine.cpp +++ b/engine/DecodeEngine/VideoDecodeEngine.cpp @@ -151,7 +151,7 @@ APP_ERROR VideoDecodeEngine::Process() } else { - LogError << " 硬解码失败... 返回失败信息:" << iDecodeRet; + LogError << "数据源:" << pProcessData->iDataSource << " 硬解码失败... 返回失败信息:" << iDecodeRet; } } } diff --git a/engine/DetectDivideEngine/ContainerDivideEngine.cpp b/engine/DetectDivideEngine/ContainerDivideEngine.cpp index 39d2c39..8647b98 100644 --- a/engine/DetectDivideEngine/ContainerDivideEngine.cpp +++ b/engine/DetectDivideEngine/ContainerDivideEngine.cpp @@ -1 +1 @@ -#include "ContainerDivideEngine.h" #include using namespace ai_matrix; ContainerDivideEngine::ContainerDivideEngine() {} ContainerDivideEngine::~ContainerDivideEngine() {} APP_ERROR ContainerDivideEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; this->vecDataSourceConfig_ = Config::getins()->getAllDataSourceConfig(); if (this->vecDataSourceConfig_.size() <= this->engineId_) { LogWarn << " -- " << engineName_ << "_" << engineId_ << " dataSource no set, Engine DeInit"; return APP_ERR_OK; } this->dataSourceConfig_ = this->vecDataSourceConfig_.at(engineId_); this->baseConfig_ = Config::getins()->getBaseConfig(); this->identifyConfig_ = Config::getins()->getIdentifyConfig(); this->initParam(); LogInfo << "DetectDivideEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerDivideEngine::DeInit() { LogInfo << "DetectDivideEngine DeInit ok"; return APP_ERR_OK; } /** * 初始化参数信息 * inParam : N/A * outParam: N/A * return : N/A */ void ContainerDivideEngine::initParam() { this->iContainerIndex = 0; this->vecContainerFail_.clear(); } void ContainerDivideEngine::sendBestData(const VSelectBestData& selectBestData) { // 直接发送第一个箱子的箱号 std::shared_ptr pVSelectBestData = std::make_shared(); *pVSelectBestData = selectBestData; outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); LogInfo << " 帧:" << selectBestData.iFrameId << " 数据源:" << selectBestData.iDataSource << " 节:" << selectBestData.iContainerIndex << " 发送识别结果 " << selectBestData.strNumResult; this->stdContainerResult_ = selectBestData.strNumResult; this->iContainerIndex++; } void ContainerDivideEngine::makeResult(const std::shared_ptr& pVStep2OutputData, VSelectBestData & selectBestData) const { selectBestData.strDetectDate = pVStep2OutputData->strDetectDate; selectBestData.strDetectTime = pVStep2OutputData->strDetectTime; selectBestData.iDataSource = pVStep2OutputData->iDataSource; selectBestData.iFrameId = pVStep2OutputData->iFrameId; selectBestData.strNumResult = pVStep2OutputData->step2ResultData.transInfo.strTmpResult; selectBestData.bIsChkFlag = pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag; selectBestData.fSumScore = pVStep2OutputData->step2ResultData.fSubScoreSum; selectBestData.iContainerIndex = this->iContainerIndex; selectBestData.bHaveTwoContainer = pVStep2OutputData->vecCornerResultData.size() > 2; } /** * 依据像素进行集装箱切分 * @param pVStep2OutputData */ void ContainerDivideEngine::divideByPixelInfo(std::shared_ptr pVStep2OutputData) { auto vCompare = [](std::string a, std::string b) { if (a.size() != b.size()) return 999; int count = 0; for (int i = 0; i < a.size(); ++i) { if (a[i] != b[i]) { ++count; } } return count; }; Step2ResultData step2ResultData_pre = this->pVStep2OutputDataPre_->step2ResultData; Step2ResultData step2ResultData = pVStep2OutputData->step2ResultData; float fCenterX = (step2ResultData.fRBX + step2ResultData.fLTX)/2; float fCenterY = (step2ResultData.fRBY + step2ResultData.fLTY)/2; float fCenterX_Pre = (step2ResultData_pre.fRBX + step2ResultData_pre.fLTX)/2; float fCenterY_Pre = (step2ResultData_pre.fRBY + step2ResultData_pre.fLTY)/2; LogDebug << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " Y差值:" << std::abs(fCenterY - fCenterY_Pre) << " X差值:" << std::abs(fCenterX - fCenterX_Pre); if ((pVStep2OutputData->iDataSource == 0 && std::abs(fCenterY - fCenterY_Pre) > this->identifyConfig_.iTop_Y_SplitSpanPx) || (pVStep2OutputData->iDataSource != 0 && std::abs(fCenterX - fCenterX_Pre) > this->identifyConfig_.iSide_X_SplitSpanPx)) { if (step2ResultData.transInfo.bIsChkFlag) { if (stdContainerResult_ != step2ResultData.transInfo.strTmpResult) { if (stdContainerResult_.empty()) { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } sendBestData(this->vecContainerFail_[iIndex]); } // 记录第二箱子 this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); } } else { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } if (this->vecContainerFail_.size() > 0 && this->iContainerIndex < 1) { sendBestData(this->vecContainerFail_[iIndex]); } // 把之前的清理掉再存新箱子的 (有风险,有可能切分错) this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->vecContainerFail_.emplace_back(selectBestData); } } else {// 不满足像素差 if (!this->stdContainerResult_.empty()) { if (step2ResultData.transInfo.bIsChkFlag) { if (this->stdContainerResult_ != step2ResultData.transInfo.strTmpResult) { // if (vCompare(this->stdContainerResult_, step2ResultData.transInfo.strTmpResult) > 2) // { this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); // } } } } else { if (step2ResultData.transInfo.bIsChkFlag) { this->stdContainerResult_ = step2ResultData.transInfo.strTmpResult; this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); } else { VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->vecContainerFail_.emplace_back(selectBestData); } } } } bool ContainerDivideEngine::setectBestByCorner() { if (!this->vecContainer_.empty()) { // 汇总下vecContainer中,有几种正确的识别结果,选出识别次数最多的 std::map mapContainer_count; std::map mapContainer_index; int i = 0; for (auto &container: this->vecContainer_) { mapContainer_count[container.strNumResult]++; mapContainer_index[container.strNumResult] = i; ++i; } std::string strBestContainer; int count = 0; // 取出现次数最高的 且与第一个箱子不一样的 for (auto &it_max: mapContainer_count) { if (it_max.first.empty()) continue; if (it_max.second >= count) { count = it_max.second; strBestContainer = it_max.first; } } this->sendBestData(this->vecContainer_[mapContainer_index[strBestContainer]]); this->vecContainer_.clear(); this->vecContainerFail_.clear(); } else { if (this->vecContainerFail_.empty()) return false; // 汇总下vecContainer中,有几种正确的识别结果,选出识别次数最多的 int iMaxSize = 0, iIndex = 0; std::map mapContainer_index; int i = 0; for (auto &container: this->vecContainerFail_) { if (container.strNumResult.size() > iMaxSize) { iMaxSize = container.strNumResult.size(); iIndex = i; } ++i; } this->sendBestData(this->vecContainerFail_[iIndex]); this->vecContainer_.clear(); this->vecContainerFail_.clear(); } return true; } /** * 依据箱角切分 * @param pVStep2OutputData */ void ContainerDivideEngine::divideByCornerInfo(std::shared_ptr pVStep2OutputData) { Step2ResultData step2ResultData = pVStep2OutputData->step2ResultData; if (pVStep2OutputData->vecCornerResultData.size() > 1 && this->iContainerIndex < 1) { if (pVStep2OutputData->vecCornerResultData.size() > 2) { LogWarn << "帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " ---- >>> 检测到超过2个箱角,疑似画面过滤倾斜或模型训练不足!"; return; } LogInfo << "帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " ---- >>> 检测到多个箱角,准备切分"; if (pVStep2OutputData->iDataSource == 0 || this->dataSourceConfig_.strRunDirection == "right") { if (this->vecContainerFail_.empty()) { VSelectBestData selectBestData; selectBestData.strDetectDate = pVStep2OutputData->strDetectDate; selectBestData.strDetectTime = pVStep2OutputData->strDetectTime; selectBestData.iDataSource = pVStep2OutputData->iDataSource; selectBestData.iFrameId = 1; selectBestData.strNumResult = "invalid-?"; selectBestData.iContainerIndex = this->iContainerIndex; selectBestData.bHaveTwoContainer = true; this->vecContainerFail_.emplace_back(selectBestData); } this->setectBestByCorner(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); if (step2ResultData.transInfo.bIsChkFlag) { this->vecContainer_.emplace_back(selectBestData); } else { this->vecContainerFail_.emplace_back(selectBestData); } return; } if (this->dataSourceConfig_.strRunDirection == "left") { LogWarn << "向左行驶的一侧暂不支持箱角识别,请及时修改参数 divide_mode: \"pixel\""; return; } } else { VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); if (step2ResultData.transInfo.bIsChkFlag) { this->vecContainer_.emplace_back(selectBestData); } else { this->vecContainerFail_.emplace_back(selectBestData); } } } /** * 切分车厢 * @param pVStep2OutputData */ void ContainerDivideEngine::divideInfo(std::shared_ptr pVStep2OutputData) { if (!this->pVStep2OutputDataPre_) return; if (this->iContainerIndex > 1) return; if (this->vecDataSourceConfig_[pVStep2OutputData->iDataSource].strDivideModel == "corner") { this->divideByCornerInfo(pVStep2OutputData); } else { this->divideByPixelInfo(pVStep2OutputData); } } APP_ERROR ContainerDivideEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { //pop端口0 std::shared_ptr pVoidData0 = nullptr; iRet = inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); continue; } std::shared_ptr pVStep2OutputData = std::static_pointer_cast(pVoidData0); if (pVStep2OutputData->bIsEnd) { std::shared_ptr pVSelectBestData = std::make_shared(); pVSelectBestData->bIsEnd = true; pVSelectBestData->iDataSource = pVStep2OutputData->iDataSource; pVSelectBestData->strDetectDate = pVStep2OutputData->strDetectDate; pVSelectBestData->strDetectTime = pVStep2OutputData->strDetectTime; if (this->iContainerIndex > 1) { outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); this->initParam(); continue; } if (this->vecDataSourceConfig_[pVStep2OutputData->iDataSource].strDivideModel == "corner") { if (!this->vecContainerFail_.empty() || !this->vecContainer_.empty()) { this->setectBestByCorner(); } } else { if (!this->vecContainerFail_.empty()) { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } this->vecContainerFail_[iIndex].bIsEnd = true; sendBestData(this->vecContainerFail_[iIndex]); this->initParam(); continue; } } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); this->initParam(); continue; } std::string strFilePath ; strFilePath = this->baseConfig_.strDebugResultPath + "/" + pVStep2OutputData->strDetectDate + "/" + StringUtil::getins()->replace_all_distinct(pVStep2OutputData->strDetectTime, ":", "-") + "/" + std::to_string(pVStep2OutputData->iFrameId) + "_" + std::to_string(pVStep2OutputData->iDataSource) + ".json"; // 先读取文本内容,追加新的信息后再写入 Json::Value jvFrameInfo; if (!FileUtil::getins()->readJsonInfo(jvFrameInfo, strFilePath)) { LogError << "read fail:" << strFilePath; } // jvFrameInfo["isEnd"] = (pVStep2OutputData->bIsEnd || jvFrameInfo["isEnd"].asBool()); // 识别结果存储 float fCenter = pVStep2OutputData->step2ResultData.fLTX + (pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX) / 2; // this->mapContainerCenterInfo_.insert(std::make_pair(pVStep2OutputData->iFrameId, fCenter)); Json::Value jvInfo; jvInfo["classid"] = pVStep2OutputData->step2ResultData.iClassId; jvInfo["score"] = pVStep2OutputData->step2ResultData.fScore; jvInfo["ltx"] = pVStep2OutputData->step2ResultData.fLTX; jvInfo["lty"] = pVStep2OutputData->step2ResultData.fLTY; jvInfo["rbx"] = pVStep2OutputData->step2ResultData.fRBX; jvInfo["rby"] = pVStep2OutputData->step2ResultData.fRBY; jvFrameInfo["step1"].append(jvInfo); for (auto &step2ResultData : pVStep2OutputData->vecCornerResultData) { float fCenter = step2ResultData.fLTX + (step2ResultData.fRBX - step2ResultData.fLTX) / 2; // this->mapContainerCenterInfo_.insert(std::make_pair(pVStep2OutputData->iFrameId, fCenter)); Json::Value jvInfo; jvInfo["classid"] = step2ResultData.iClassId; jvInfo["score"] = step2ResultData.fScore; jvInfo["ltx"] = step2ResultData.fLTX; jvInfo["lty"] = step2ResultData.fLTY; jvInfo["rbx"] = step2ResultData.fRBX; jvInfo["rby"] = step2ResultData.fRBY; jvFrameInfo["step1"].append(jvInfo); } FileUtil::getins()->writeJsonInfo(jvFrameInfo, strFilePath); if (pVStep2OutputData->step2ResultData.fScore != 0.0f) { LogDebug << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " - "<< pVStep2OutputData->step2ResultData.transInfo.strTmpResult; } this->divideInfo(pVStep2OutputData); this->pVStep2OutputDataPre_ = pVStep2OutputData; } return APP_ERR_OK; } \ No newline at end of file +#include "ContainerDivideEngine.h" #include using namespace ai_matrix; ContainerDivideEngine::ContainerDivideEngine() {} ContainerDivideEngine::~ContainerDivideEngine() {} APP_ERROR ContainerDivideEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; this->vecDataSourceConfig_ = Config::getins()->getAllDataSourceConfig(); if (this->vecDataSourceConfig_.size() <= this->engineId_) { LogWarn << " -- " << engineName_ << "_" << engineId_ << " dataSource no set, Engine DeInit"; return APP_ERR_OK; } this->dataSourceConfig_ = this->vecDataSourceConfig_.at(engineId_); this->baseConfig_ = Config::getins()->getBaseConfig(); this->identifyConfig_ = Config::getins()->getIdentifyConfig(); this->initParam(); LogInfo << "DetectDivideEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerDivideEngine::DeInit() { LogInfo << "DetectDivideEngine DeInit ok"; return APP_ERR_OK; } /** * 初始化参数信息 * inParam : N/A * outParam: N/A * return : N/A */ void ContainerDivideEngine::initParam() { this->iContainerIndex = 0; this->pVStep2OutputDataPre_ = nullptr; this->vecContainerFail_.clear(); } void ContainerDivideEngine::sendBestData(const VSelectBestData& selectBestData) { // 直接发送第一个箱子的箱号 std::shared_ptr pVSelectBestData = std::make_shared(); *pVSelectBestData = selectBestData; outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); LogInfo << " 帧:" << selectBestData.iFrameId << " 数据源:" << selectBestData.iDataSource << " 节:" << selectBestData.iContainerIndex << " 发送识别结果 " << selectBestData.strNumResult; this->stdContainerResult_ = selectBestData.strNumResult; this->iContainerIndex++; } void ContainerDivideEngine::makeResult(const std::shared_ptr& pVStep2OutputData, VSelectBestData & selectBestData) const { selectBestData.strDetectDate = pVStep2OutputData->strDetectDate; selectBestData.strDetectTime = pVStep2OutputData->strDetectTime; selectBestData.iDataSource = pVStep2OutputData->iDataSource; selectBestData.iFrameId = pVStep2OutputData->iFrameId; selectBestData.strNumResult = pVStep2OutputData->step2ResultData.transInfo.strTmpResult; selectBestData.bIsChkFlag = pVStep2OutputData->step2ResultData.transInfo.bIsChkFlag; selectBestData.fSumScore = pVStep2OutputData->step2ResultData.fSubScoreSum; selectBestData.iContainerIndex = this->iContainerIndex; selectBestData.bHaveTwoContainer = pVStep2OutputData->vecCornerResultData.size() > 2; } /** * 依据像素进行集装箱切分 * @param pVStep2OutputData */ void ContainerDivideEngine::divideByPixelInfo(std::shared_ptr pVStep2OutputData) { auto vCompare = [](std::string a, std::string b) { if (a.size() != b.size()) return 999; int count = 0; for (int i = 0; i < a.size(); ++i) { if (a[i] != b[i]) { ++count; } } return count; }; if (!this->pVStep2OutputDataPre_) { if (pVStep2OutputData->step2ResultData.fScore == 0.0f) return; this->pVStep2OutputDataPre_ = pVStep2OutputData; } Step2ResultData step2ResultData = pVStep2OutputData->step2ResultData; Step2ResultData step2ResultData_pre = this->pVStep2OutputDataPre_->step2ResultData; float fCenterX = (step2ResultData.fRBX + step2ResultData.fLTX)/2; float fCenterY = (step2ResultData.fRBY + step2ResultData.fLTY)/2; float fCenterX_Pre = (step2ResultData_pre.fRBX + step2ResultData_pre.fLTX)/2; float fCenterY_Pre = (step2ResultData_pre.fRBY + step2ResultData_pre.fLTY)/2; LogDebug << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " Y差值:" << std::abs(fCenterY - fCenterY_Pre) << " X差值:" << std::abs(fCenterX - fCenterX_Pre); if ((pVStep2OutputData->iDataSource == 0 && std::abs(fCenterY - fCenterY_Pre) > this->identifyConfig_.iTop_Y_SplitSpanPx) || (pVStep2OutputData->iDataSource != 0 && std::abs(fCenterX - fCenterX_Pre) > this->identifyConfig_.iSide_X_SplitSpanPx)) { if (step2ResultData.transInfo.bIsChkFlag) { if (stdContainerResult_ != step2ResultData.transInfo.strTmpResult) { if (stdContainerResult_.empty()) { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } sendBestData(this->vecContainerFail_[iIndex]); } // 记录第二箱子 this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); } } else { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } if (this->vecContainerFail_.size() > 0 && this->iContainerIndex < 1) { sendBestData(this->vecContainerFail_[iIndex]); } // 把之前的清理掉再存新箱子的 (有风险,有可能切分错) this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->vecContainerFail_.emplace_back(selectBestData); } } else {// 不满足像素差 if (!this->stdContainerResult_.empty()) { if (step2ResultData.transInfo.bIsChkFlag) { if (this->stdContainerResult_ != step2ResultData.transInfo.strTmpResult) { // if (vCompare(this->stdContainerResult_, step2ResultData.transInfo.strTmpResult) > 2) // { this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); // } } } } else { if (step2ResultData.transInfo.bIsChkFlag) { this->stdContainerResult_ = step2ResultData.transInfo.strTmpResult; this->vecContainerFail_.clear(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->sendBestData(selectBestData); } else { VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); this->vecContainerFail_.emplace_back(selectBestData); } } } } bool ContainerDivideEngine::setectBestByCorner() { if (!this->vecContainer_.empty()) { // 汇总下vecContainer中,有几种正确的识别结果,选出识别次数最多的 std::map mapContainer_count; std::map mapContainer_index; int i = 0; for (auto &container: this->vecContainer_) { mapContainer_count[container.strNumResult]++; mapContainer_index[container.strNumResult] = i; ++i; } std::string strBestContainer; int count = 0; // 取出现次数最高的 且与第一个箱子不一样的 for (auto &it_max: mapContainer_count) { if (it_max.first.empty()) continue; if (it_max.second >= count) { count = it_max.second; strBestContainer = it_max.first; } } this->sendBestData(this->vecContainer_[mapContainer_index[strBestContainer]]); this->vecContainer_.clear(); this->vecContainerFail_.clear(); } else { if (this->vecContainerFail_.empty()) return false; // 汇总下vecContainer中,有几种正确的识别结果,选出识别次数最多的 int iMaxSize = 0, iIndex = 0; std::map mapContainer_index; int i = 0; for (auto &container: this->vecContainerFail_) { if (container.strNumResult.size() > iMaxSize) { iMaxSize = container.strNumResult.size(); iIndex = i; } ++i; } this->sendBestData(this->vecContainerFail_[iIndex]); this->vecContainer_.clear(); this->vecContainerFail_.clear(); } return true; } /** * 依据箱角切分 * @param pVStep2OutputData */ void ContainerDivideEngine::divideByCornerInfo(std::shared_ptr pVStep2OutputData) { Step2ResultData step2ResultData = pVStep2OutputData->step2ResultData; if (pVStep2OutputData->vecCornerResultData.size() > 1 && this->iContainerIndex < 1) { if (pVStep2OutputData->vecCornerResultData.size() > 2) { LogWarn << "帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " ---- >>> 检测到超过2个箱角,疑似画面过于倾斜或模型训练不足!"; return; } float fDiffX = std::abs(pVStep2OutputData->vecCornerResultData[0].fLTX - pVStep2OutputData->vecCornerResultData[1].fLTX); float fDiffY = std::abs(pVStep2OutputData->vecCornerResultData[0].fLTY - pVStep2OutputData->vecCornerResultData[1].fLTY); if (fDiffX > this->identifyConfig_.iMaxContainerSpaceX || fDiffY > this->identifyConfig_.iMaxContainerSpaceY) { LogWarn << "帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " ---- >>> 检测到超过2个间隔过远的箱角,疑似画面过于倾斜看到一个箱子的多个角或模型训练不足!"; return; } LogInfo << "帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " ---- >>> 检测到多个箱角,准备切分"; if (pVStep2OutputData->iDataSource == 0 || this->dataSourceConfig_.strRunDirection == "right") { if (this->vecContainerFail_.empty()) { VSelectBestData selectBestData; selectBestData.strDetectDate = pVStep2OutputData->strDetectDate; selectBestData.strDetectTime = pVStep2OutputData->strDetectTime; selectBestData.iDataSource = pVStep2OutputData->iDataSource; selectBestData.iFrameId = 1; selectBestData.strNumResult = "invalid-?"; selectBestData.iContainerIndex = this->iContainerIndex; selectBestData.bHaveTwoContainer = true; this->vecContainerFail_.emplace_back(selectBestData); } this->setectBestByCorner(); VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); if (step2ResultData.transInfo.bIsChkFlag) { this->vecContainer_.emplace_back(selectBestData); } else { this->vecContainerFail_.emplace_back(selectBestData); } return; } if (this->dataSourceConfig_.strRunDirection == "left") { LogWarn << "向左行驶的一侧暂不支持箱角识别,请及时修改参数 divide_mode: \"pixel\""; return; } } else { VSelectBestData selectBestData; this->makeResult(pVStep2OutputData, selectBestData); if (step2ResultData.transInfo.bIsChkFlag) { this->vecContainer_.emplace_back(selectBestData); } else { this->vecContainerFail_.emplace_back(selectBestData); } } } /** * 切分车厢 * @param pVStep2OutputData */ void ContainerDivideEngine::divideInfo(std::shared_ptr pVStep2OutputData) { // if (!this->pVStep2OutputDataPre_) return; if (this->iContainerIndex > 1) return; if (this->vecDataSourceConfig_[pVStep2OutputData->iDataSource].strDivideModel == "corner") { this->divideByCornerInfo(pVStep2OutputData); } else { this->divideByPixelInfo(pVStep2OutputData); } } APP_ERROR ContainerDivideEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { //pop端口0 std::shared_ptr pVoidData0 = nullptr; iRet = inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); continue; } std::shared_ptr pVStep2OutputData = std::static_pointer_cast(pVoidData0); if (pVStep2OutputData->bIsEnd) { std::shared_ptr pVSelectBestData = std::make_shared(); pVSelectBestData->bIsEnd = true; pVSelectBestData->iDataSource = pVStep2OutputData->iDataSource; pVSelectBestData->strDetectDate = pVStep2OutputData->strDetectDate; pVSelectBestData->strDetectTime = pVStep2OutputData->strDetectTime; if (this->iContainerIndex > 1) { outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); this->initParam(); continue; } if (this->vecDataSourceConfig_[pVStep2OutputData->iDataSource].strDivideModel == "corner") { if (!this->vecContainerFail_.empty() || !this->vecContainer_.empty()) { this->setectBestByCorner(); } } else { if (!this->vecContainerFail_.empty()) { // 筛选不满足校验的部分 取最长的发送 int iSize = 0, iIndex = 0; std::string strContainer_tmp; for (int i = 0; i < this->vecContainerFail_.size(); i++) { this->vecContainerFail_[i]; if (iSize < this->vecContainerFail_[i].strNumResult.size()) { iSize = this->vecContainerFail_[i].strNumResult.size(); iIndex = i; strContainer_tmp = this->vecContainerFail_[i].strNumResult; } } this->vecContainerFail_[iIndex].bIsEnd = true; sendBestData(this->vecContainerFail_[iIndex]); this->initParam(); continue; } } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVSelectBestData), true); this->initParam(); continue; } std::string strFilePath ; strFilePath = this->baseConfig_.strDebugResultPath + "/" + pVStep2OutputData->strDetectDate + "/" + StringUtil::getins()->replace_all_distinct(pVStep2OutputData->strDetectTime, ":", "-") + "/" + std::to_string(pVStep2OutputData->iFrameId) + "_" + std::to_string(pVStep2OutputData->iDataSource) + ".json"; // 先读取文本内容,追加新的信息后再写入 Json::Value jvFrameInfo; if (!FileUtil::getins()->readJsonInfo(jvFrameInfo, strFilePath)) { LogError << "read fail:" << strFilePath; } // jvFrameInfo["isEnd"] = (pVStep2OutputData->bIsEnd || jvFrameInfo["isEnd"].asBool()); // 识别结果存储 float fCenter = pVStep2OutputData->step2ResultData.fLTX + (pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX) / 2; // this->mapContainerCenterInfo_.insert(std::make_pair(pVStep2OutputData->iFrameId, fCenter)); Json::Value jvInfo; jvInfo["classid"] = pVStep2OutputData->step2ResultData.iClassId; jvInfo["score"] = pVStep2OutputData->step2ResultData.fScore; jvInfo["ltx"] = pVStep2OutputData->step2ResultData.fLTX; jvInfo["lty"] = pVStep2OutputData->step2ResultData.fLTY; jvInfo["rbx"] = pVStep2OutputData->step2ResultData.fRBX; jvInfo["rby"] = pVStep2OutputData->step2ResultData.fRBY; jvFrameInfo["step1"].append(jvInfo); for (auto &step2ResultData : pVStep2OutputData->vecCornerResultData) { float fCenter = step2ResultData.fLTX + (step2ResultData.fRBX - step2ResultData.fLTX) / 2; // this->mapContainerCenterInfo_.insert(std::make_pair(pVStep2OutputData->iFrameId, fCenter)); Json::Value jvInfo; jvInfo["classid"] = step2ResultData.iClassId; jvInfo["score"] = step2ResultData.fScore; jvInfo["ltx"] = step2ResultData.fLTX; jvInfo["lty"] = step2ResultData.fLTY; jvInfo["rbx"] = step2ResultData.fRBX; jvInfo["rby"] = step2ResultData.fRBY; jvFrameInfo["step1"].append(jvInfo); } FileUtil::getins()->writeJsonInfo(jvFrameInfo, strFilePath); if (pVStep2OutputData->step2ResultData.fScore != 0.0f) { LogDebug << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " - "<< pVStep2OutputData->step2ResultData.transInfo.strTmpResult; } this->divideInfo(pVStep2OutputData); } return APP_ERR_OK; } \ No newline at end of file diff --git a/engine/MergeEngine/Step1MergeEngine.cpp b/engine/MergeEngine/Step1MergeEngine.cpp index 06f0024..eeb46a8 100644 --- a/engine/MergeEngine/Step1MergeEngine.cpp +++ b/engine/MergeEngine/Step1MergeEngine.cpp @@ -1 +1 @@ -#include "Step1MergeEngine.h" using namespace ai_matrix; namespace { //按照x坐标排列 bool CompareX(const SingleData &a, const SingleData &b) { return a.fLTX < b.fLTX; } } Step1MergeEngine::Step1MergeEngine() {} Step1MergeEngine::~Step1MergeEngine() {} APP_ERROR Step1MergeEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; this->baseConfig_ = Config::getins()->getBaseConfig(); this->identifyConfig_ = Config::getins()->getIdentifyConfig(); this->multiTypeQueue_ = new ai_matrix::MultiTypeQueue(2); LogInfo << "MergeEngine Init ok"; return APP_ERR_OK; } APP_ERROR Step1MergeEngine::DeInit() { LogInfo << "MergeEngine DeInit ok"; return APP_ERR_OK; } APP_ERROR Step1MergeEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); std::shared_ptr pVoidData1 = nullptr; inputQueMap_[strPort1_]->pop(pVoidData1); if (nullptr == pVoidData0 && nullptr == pVoidData1) { usleep(1000); //1ms continue; } if (pVoidData0) { this->multiTypeQueue_->PushData(0, pVoidData0); } if (pVoidData1) { this->multiTypeQueue_->PushData(1, pVoidData1); } if (!this->multiTypeQueue_->PopAllData(pVoidData0, pVoidData1)) { usleep(1000); //1ms continue; } std::shared_ptr pInferenceResultData = std::static_pointer_cast(pVoidData0); std::shared_ptr pInferenceResultData_container = std::static_pointer_cast(pVoidData1); pInferenceResultData->vecSingleData = pInferenceResultData_container->vecSingleData; std::sort(pInferenceResultData->vecSingleData.begin(), pInferenceResultData->vecSingleData.end(), CompareX); if (pInferenceResultData->singleData.fScore > 0.0f) { // 箱号 // LogDebug << " 帧:" << pInferenceResultData->iFrameId // << " 数据源:" << pInferenceResultData->iDataSource // << " --iClassId:" << pInferenceResultData->singleData.iClassId // << " confidence=" << pInferenceResultData->singleData.fScore // << " lx=" << pInferenceResultData->singleData.fLTX // << " ly=" << pInferenceResultData->singleData.fLTY // << " rx=" << pInferenceResultData->singleData.fRBX // << " ry=" << pInferenceResultData->singleData.fRBY // << " clear:" << pInferenceResultData->singleData.fClear; } // 箱角 for (const auto & it_result : pInferenceResultData->vecSingleData) { LogDebug << " 帧:" << pInferenceResultData->iFrameId << " 数据源:" << pInferenceResultData->iDataSource << " --iClassId:" << it_result.iClassId << " confidence=" << it_result.fScore << " lx=" << it_result.fLTX << " ly=" << it_result.fLTY << " rx=" << it_result.fRBX << " ry=" << it_result.fRBY; } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pInferenceResultData), true); } return APP_ERR_OK; } \ No newline at end of file +#include "Step1MergeEngine.h" using namespace ai_matrix; namespace { //按照x坐标排列 bool CompareX(const SingleData &a, const SingleData &b) { return a.fLTX < b.fLTX; } } Step1MergeEngine::Step1MergeEngine() {} Step1MergeEngine::~Step1MergeEngine() {} APP_ERROR Step1MergeEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; this->baseConfig_ = Config::getins()->getBaseConfig(); this->identifyConfig_ = Config::getins()->getIdentifyConfig(); this->multiTypeQueue_ = new ai_matrix::MultiTypeQueue(2); LogInfo << "MergeEngine Init ok"; return APP_ERR_OK; } APP_ERROR Step1MergeEngine::DeInit() { LogInfo << "MergeEngine DeInit ok"; return APP_ERR_OK; } APP_ERROR Step1MergeEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); std::shared_ptr pVoidData1 = nullptr; inputQueMap_[strPort1_]->pop(pVoidData1); if (nullptr == pVoidData0 && nullptr == pVoidData1) { usleep(1000); //1ms continue; } if (pVoidData0) { this->multiTypeQueue_->PushData(0, pVoidData0); } if (pVoidData1) { this->multiTypeQueue_->PushData(1, pVoidData1); } if (!this->multiTypeQueue_->PopAllData(pVoidData0, pVoidData1)) { usleep(1000); //1ms continue; } std::shared_ptr pInferenceResultData = std::static_pointer_cast(pVoidData0); std::shared_ptr pInferenceResultData_container = std::static_pointer_cast(pVoidData1); pInferenceResultData->vecSingleData = pInferenceResultData_container->vecSingleData; std::sort(pInferenceResultData->vecSingleData.begin(), pInferenceResultData->vecSingleData.end(), CompareX); if (pInferenceResultData->singleData.fScore > 0.0f) { // 箱号 LogDebug << " 帧:" << pInferenceResultData->iFrameId << " 数据源:" << pInferenceResultData->iDataSource << " --iClassId:" << pInferenceResultData->singleData.iClassId << " confidence=" << pInferenceResultData->singleData.fScore << " lx=" << pInferenceResultData->singleData.fLTX << " ly=" << pInferenceResultData->singleData.fLTY << " rx=" << pInferenceResultData->singleData.fRBX << " ry=" << pInferenceResultData->singleData.fRBY << " clear:" << pInferenceResultData->singleData.fClear; } // 箱角 for (const auto & it_result : pInferenceResultData->vecSingleData) { LogDebug << " 帧:" << pInferenceResultData->iFrameId << " 数据源:" << pInferenceResultData->iDataSource << " --iClassId:" << it_result.iClassId << " confidence=" << it_result.fScore << " lx=" << it_result.fLTX << " ly=" << it_result.fLTY << " rx=" << it_result.fRBX << " ry=" << it_result.fRBY; } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pInferenceResultData), true); } return APP_ERR_OK; } \ No newline at end of file diff --git a/engine/SaveDebugImageEngine/SaveDebugImageEngine.cpp b/engine/SaveDebugImageEngine/SaveDebugImageEngine.cpp index 160366c..95d8729 100644 --- a/engine/SaveDebugImageEngine/SaveDebugImageEngine.cpp +++ b/engine/SaveDebugImageEngine/SaveDebugImageEngine.cpp @@ -43,6 +43,7 @@ APP_ERROR SaveDebugImageEngine::Process() } std::shared_ptr pVStep2OutputData = std::static_pointer_cast(pvoidd); + cv::Mat image = pVStep2OutputData->cvImage.clone(); std::string strDataDir = this->baseConfig_.strDebugResultPath + "/" + pVStep2OutputData->strDetectDate + "/" @@ -66,9 +67,9 @@ APP_ERROR SaveDebugImageEngine::Process() // cv::Mat image = cv::imread(strImagePath); - if (pVStep2OutputData->cvImage.empty()) + if (image.empty()) { - LogWarn << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " debug图像未找到"; +// LogWarn << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " debug图像未找到"; continue; } @@ -86,7 +87,7 @@ APP_ERROR SaveDebugImageEngine::Process() cv::Size text_size = cv::getTextSize(i, cv::FONT_HERSHEY_SIMPLEX, 1, 2, 0); cv::Point baseline_loc(text_org); baseline_loc.y += base_line + text_size.height; - cv::putText(pVStep2OutputData->cvImage, i, baseline_loc, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0, 255), 2); + cv::putText(image, i, baseline_loc, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0, 255), 2); // 手动调整x位置,为下一个单词留出空间 text_org.x += text_size.width + 10; text_org.x = text_org.x > IMAGE_WIDTH ? 15 : text_org.x; @@ -98,17 +99,17 @@ APP_ERROR SaveDebugImageEngine::Process() float centerX = pVStep2OutputData->step2ResultData.fLTX + (pVStep2OutputData->step2ResultData.fRBX - pVStep2OutputData->step2ResultData.fLTX)/2; float centerY = pVStep2OutputData->step2ResultData.fLTY + (pVStep2OutputData->step2ResultData.fRBY - pVStep2OutputData->step2ResultData.fLTY)/2; // auto start = std::chrono::system_clock::now(); //计时开始 - cv::rectangle(pVStep2OutputData->cvImage, + cv::rectangle(image, cv::Point(pVStep2OutputData->step2ResultData.fLTX, pVStep2OutputData->step2ResultData.fLTY), cv::Point(pVStep2OutputData->step2ResultData.fRBX, pVStep2OutputData->step2ResultData.fRBY), cvScalar, 2); - cv::line(pVStep2OutputData->cvImage, + cv::line(image, cv::Point(centerX, pVStep2OutputData->step2ResultData.fLTY-30), cv::Point(centerX, pVStep2OutputData->step2ResultData.fRBY+30), cvScalar, 1); cv::Size text_size = cv::getTextSize(pVStep2OutputData->step2ResultData.transInfo.strTmpResult, cv::FONT_HERSHEY_SIMPLEX, 1, 2, 0); cv::Point linePoint(pVStep2OutputData->step2ResultData.fLTX, pVStep2OutputData->step2ResultData.fRBY + text_size.height + 5); - cv::putText(pVStep2OutputData->cvImage, + cv::putText(image, pVStep2OutputData->step2ResultData.transInfo.strTmpResult, linePoint, cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0, 180), 2); @@ -118,11 +119,11 @@ APP_ERROR SaveDebugImageEngine::Process() { cvScalar = {0, 255, 255, 255}; float centerX_corner = step2ResultData.fLTX + (step2ResultData.fRBX - step2ResultData.fLTX)/2; - cv::rectangle(pVStep2OutputData->cvImage, + cv::rectangle(image, cv::Point(step2ResultData.fLTX, step2ResultData.fLTY), cv::Point(step2ResultData.fRBX, step2ResultData.fRBY), cvScalar, 2); - cv::line(pVStep2OutputData->cvImage, + cv::line(image, cv::Point(centerX_corner, step2ResultData.fLTY-30), cv::Point(centerX_corner, step2ResultData.fRBY+30), cvScalar, 1); } @@ -131,7 +132,7 @@ APP_ERROR SaveDebugImageEngine::Process() // auto end = std::chrono::system_clock::now(); // LogDebug << "图片存储用时: " << std::chrono::duration_cast(end - start).count() << "ms " << strImagePath; - if (!cv::imwrite(strImagePath, pVStep2OutputData->cvImage, this->vecCompressionParams_)) + if (!cv::imwrite(strImagePath, image, this->vecCompressionParams_)) { LogError << "图片存储失败:" << strImagePath; } diff --git a/engine/SaveDebugImageEngine/SaveDebugImageEngine.h b/engine/SaveDebugImageEngine/SaveDebugImageEngine.h index bfb36a3..feb499d 100644 --- a/engine/SaveDebugImageEngine/SaveDebugImageEngine.h +++ b/engine/SaveDebugImageEngine/SaveDebugImageEngine.h @@ -24,7 +24,7 @@ private: ai_matrix::BaseConfig baseConfig_; std::string strPort0_; - int iPicQuality_ = 100; + int iPicQuality_ = 80; std::vector vecCompressionParams_; }; diff --git a/engine/SelectBestEngine/SelectBestEngine.cpp b/engine/SelectBestEngine/SelectBestEngine.cpp index 0f59f4f..ab3aa47 100644 --- a/engine/SelectBestEngine/SelectBestEngine.cpp +++ b/engine/SelectBestEngine/SelectBestEngine.cpp @@ -50,8 +50,7 @@ void SelectBestEngine::sendWSServer(DetectResultData &detectResultData) Json::Value jsonData; for (int i = 0; i < detectResultData.vecImage.size(); ++i) { - jsonData["bestImgSid" + std::to_string(i)] = detectResultData.vecImage[i]; - strImage += detectResultData.vecImage[i]; + strImage += (detectResultData.strDetectDate + "/" + ai_matrix::StringUtil::getins()->replace_all_distinct(detectResultData.strDetectTime, ":", "-") + "/" + detectResultData.vecImage[i]); if (i < detectResultData.vecImage.size() - 1) { strImage += ","; @@ -68,6 +67,8 @@ void SelectBestEngine::sendWSServer(DetectResultData &detectResultData) strContainerNo += ","; } } + jsonData["detectDate"] = detectResultData.strDetectDate; + jsonData["detectTime"] = detectResultData.strDetectTime; jsonData["containerNo"] = strContainerNo; jsonData["images"] = strImage; jsonData["status"] = "normal"; @@ -99,10 +100,24 @@ void SelectBestEngine::selectBest() auto contains = [] (const std::vector& vec, std::string value) -> bool { return std::find(vec.begin(), vec.end(), value) != vec.end(); }; + auto vCompare = [](std::string a, std::string b) { + if (a.size() != b.size()) return 999; + + int count = 0; + for (int i = 0; i < a.size(); ++i) + { + if (a[i] != b[i]) + { + ++count; + } + } + return count; + }; DetectResultData detectResultData; detectResultData.strDetectDate = this->strDetectDate_; detectResultData.strDetectTime = this->strDetectTime_; + std::string strAlternativeResult; bool bHaveTwoContainer = false; for (auto & it_container : this->mapIndex_Containers_) { bool bHaveVerify = false; @@ -129,21 +144,39 @@ void SelectBestEngine::selectBest() count = it_max.second; if (!contains(detectResultData.vecContainerNO, it_max.first)) { strBestContainer = it_max.first; + break; + } + } + } + if (mapContainer_count.size() > 1) + { + for (auto &it_max : mapContainer_count) + { + if (it_max.first != strBestContainer && vCompare(it_max.first, strBestContainer) > 2) + { + strAlternativeResult = it_max.first; } } } detectResultData.vecContainerNO.emplace_back(strBestContainer); } else { - // 取识别字数最长的 - std::string strBestContainer; - int iMaxSize = 0; - for (auto &it_max: mapContainer_count) { - if (it_max.first.size() > iMaxSize) { - iMaxSize = it_max.first.size(); - strBestContainer = it_max.first; - } + if (detectResultData.vecContainerNO.size() == 1 && !strAlternativeResult.empty()) + { + detectResultData.vecContainerNO.emplace_back(strAlternativeResult); + } + else + { + // 取识别字数最长的 + std::string strBestContainer; + int iMaxSize = 0; + for (auto &it_max: mapContainer_count) { + if (it_max.first.size() > iMaxSize) { + iMaxSize = it_max.first.size(); + strBestContainer = it_max.first; + } + } + detectResultData.vecContainerNO.emplace_back(strBestContainer); } - detectResultData.vecContainerNO.emplace_back(strBestContainer); } } if (bHaveTwoContainer && detectResultData.vecContainerNO.size() < 2) @@ -175,6 +208,12 @@ APP_ERROR SelectBestEngine::Process() if (pVSelectBestData->bIsEnd) { + if (this->strDetectDate_.empty()) + { + this->strDetectDate_ = pVSelectBestData->strDetectDate; + this->strDetectTime_ = pVSelectBestData->strDetectTime; + } + this->iEndCount_++; if (!(this->iEndCount_ % this->vecDataSourceConfig_.size())) { @@ -183,6 +222,7 @@ APP_ERROR SelectBestEngine::Process() } continue; } + this->iEndCount_ = 0; if (this->strImagePath_.empty()) { diff --git a/engine/Step1InferenceEngine/ContainerStep1InferenceEngine.cpp b/engine/Step1InferenceEngine/ContainerStep1InferenceEngine.cpp index 09c0ca1..1328405 100644 --- a/engine/Step1InferenceEngine/ContainerStep1InferenceEngine.cpp +++ b/engine/Step1InferenceEngine/ContainerStep1InferenceEngine.cpp @@ -268,6 +268,7 @@ APP_ERROR ContainerStep1InferenceEngine::Process() if (pVDetectInfo->cvImage.empty()) { + outputQueMap_[strPort0_]->push(std::static_pointer_cast(pInferenceResultData), true); usleep(1000); //1ms continue; } @@ -290,7 +291,7 @@ APP_ERROR ContainerStep1InferenceEngine::Process() pInferenceResultData->strDetectDate = pVDetectInfo->strDetectDate; pInferenceResultData->strDetectTime = pVDetectInfo->strDetectTime; - pInferenceResultData->cvImage = pVDetectInfo->cvImage; + pInferenceResultData->cvImage = pVDetectInfo->cvImage.clone(); // 筛选离中心点坐标最近的,如果一样近就选最右的 float fCenterX = IMAGE_WIDTH/2; @@ -323,7 +324,7 @@ APP_ERROR ContainerStep1InferenceEngine::Process() singledata.fLTY = inferenceResult.bbox[1]; singledata.fRBX = inferenceResult.bbox[2]; singledata.fRBY = inferenceResult.bbox[3]; - singledata.fClear = inferenceResult.clear_id; + singledata.fClear = inferenceResult.clear_conf; pInferenceResultData->singleData = singledata; diff --git a/engine/Step2InferenceEngine/ContainerStep2InferenceEngine.cpp b/engine/Step2InferenceEngine/ContainerStep2InferenceEngine.cpp index f6f7d68..e6acd64 100644 --- a/engine/Step2InferenceEngine/ContainerStep2InferenceEngine.cpp +++ b/engine/Step2InferenceEngine/ContainerStep2InferenceEngine.cpp @@ -1 +1 @@ -#include "ContainerStep2InferenceEngine.h" #include #include "myqueue.h" using namespace ai_matrix; ContainerStep2InferenceEngine::ContainerStep2InferenceEngine() {} ContainerStep2InferenceEngine::~ContainerStep2InferenceEngine() {} APP_ERROR ContainerStep2InferenceEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; this->modelConfig_ = Config::getins()->getModelByContainerStep2Config(); //读取模型信息 int iFolderExist = access(modelConfig_.strModelPath.c_str(), R_OK); if (iFolderExist == -1) { LogError << "模型:" << modelConfig_.strModelPath << " 不存在!"; return false; } class_num = this->modelConfig_.vecClass.size(); score_threshold = this->modelConfig_.fScoreThreshold; input_size = GET_INPUT_SIZE(model_width , model_height); output_size = GET_OUTPUT_SIZE(model_width, model_height, clear_num, class_num); det_size = clear_num + class_num + 5; int ret = initModel(); if (ret != APP_ERR_OK) { LogError << "Failed to read model info, ret = " << ret; return ret; } LogInfo << "ContainerStep2InferenceEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerStep2InferenceEngine::initModel() { modelinfo.yolov5ClearityModelParam.uiClassNum = class_num; modelinfo.yolov5ClearityModelParam.uiClearNum = clear_num; modelinfo.yolov5ClearityModelParam.uiDetSize = det_size; modelinfo.yolov5ClearityModelParam.fScoreThreshold = score_threshold; modelinfo.yolov5ClearityModelParam.fNmsThreshold = nms_threshold; modelinfo.modelCommonInfo.uiModelWidth = model_width; modelinfo.modelCommonInfo.uiModelHeight = model_height; modelinfo.modelCommonInfo.uiInputSize = input_size; modelinfo.modelCommonInfo.uiOutputSize = output_size; modelinfo.modelCommonInfo.uiChannel = INPUT_CHANNEL; modelinfo.modelCommonInfo.uiBatchSize = batch_size; modelinfo.modelCommonInfo.strInputBlobName = INPUT_BLOB_NAME; modelinfo.modelCommonInfo.strOutputBlobName = OUTPUT_BLOB_NAME; string strModelName; int nRet = yolov5model.YoloV5ClearityInferenceInit(&modelinfo, strModelName, this->modelConfig_.strModelPath); if (nRet != 0) { LogInfo << "YoloV5ClassifyInferenceInit nRet:" << nRet; return APP_ERR_COMM_READ_FAIL; } return APP_ERR_OK; } APP_ERROR ContainerStep2InferenceEngine::DeInit() { yolov5model.YoloV5ClearityInferenceDeinit(); LogInfo << "ContainerStep2InferenceEngine DeInit ok"; return APP_ERR_OK; } void ContainerStep2InferenceEngine::resetLocation(SingleData &singleData, SingleData &step1SingleData, float fResizeRatio) { singleData.fLTX = singleData.fLTX * fResizeRatio + step1SingleData.fLTX; singleData.fLTY = singleData.fLTY * fResizeRatio + step1SingleData.fLTY; singleData.fRBX = singleData.fRBX * fResizeRatio + step1SingleData.fLTX; singleData.fRBY = singleData.fRBY * fResizeRatio + step1SingleData.fLTY; singleData.fLTX = (singleData.fLTX < IMAGE_WIDTH) ? singleData.fLTX : IMAGE_WIDTH; singleData.fLTY = (singleData.fLTY < IMAGE_HEIGHT) ? singleData.fLTY : IMAGE_HEIGHT; singleData.fRBX = (singleData.fRBX < IMAGE_WIDTH) ? singleData.fRBX : IMAGE_WIDTH; singleData.fRBY = (singleData.fRBY < IMAGE_HEIGHT) ? singleData.fRBY : IMAGE_HEIGHT; } APP_ERROR ContainerStep2InferenceEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms continue; } std::shared_ptr pInferenceResultData = std::static_pointer_cast(pVoidData0); std::shared_ptr pVStep2OutputData = std::make_shared(); pVStep2OutputData->iDataSource = pInferenceResultData->iDataSource; pVStep2OutputData->bIsEnd = pInferenceResultData->bIsEnd; pVStep2OutputData->strDetectDate = pInferenceResultData->strDetectDate; pVStep2OutputData->strDetectTime = pInferenceResultData->strDetectTime; pVStep2OutputData->cvImage = pInferenceResultData->cvImage; if (pInferenceResultData->bIsEnd) { outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVStep2OutputData), true); continue; } pVStep2OutputData->strDetectDate = pInferenceResultData->strDetectDate; pVStep2OutputData->strDetectTime = pInferenceResultData->strDetectTime; pVStep2OutputData->iFrameId = pInferenceResultData->iFrameId; // LogWarn << "-- 0 -->" << pVStep2InputData->vecSingleData.size(); for (auto & single : pInferenceResultData->vecSingleData) { Step2ResultData step2ResultData; step2ResultData.fLTX = single.fLTX; step2ResultData.fLTY = single.fLTY; step2ResultData.fRBX = single.fRBX; step2ResultData.fRBY = single.fRBY; step2ResultData.iClassId = single.iClassId; step2ResultData.fScore = single.fScore; step2ResultData.iTrainIndex = single.iTrainIndex; if (single.iTargetType == CORNER) { pVStep2OutputData->vecCornerResultData.emplace_back(step2ResultData); continue; }; } if (pInferenceResultData->singleData.fScore > 0.0f) { pVStep2OutputData->step2ResultData.fLTX = pInferenceResultData->singleData.fLTX; pVStep2OutputData->step2ResultData.fLTY = pInferenceResultData->singleData.fLTY; pVStep2OutputData->step2ResultData.fRBX = pInferenceResultData->singleData.fRBX; pVStep2OutputData->step2ResultData.fRBY = pInferenceResultData->singleData.fRBY; pVStep2OutputData->step2ResultData.iClassId = pInferenceResultData->singleData.iClassId; pVStep2OutputData->step2ResultData.fScore = pInferenceResultData->singleData.fScore; pVStep2OutputData->step2ResultData.iTrainIndex = pInferenceResultData->singleData.iTrainIndex; cv::Rect rect(cv::Point(pInferenceResultData->singleData.fLTX, pInferenceResultData->singleData.fLTY), cv::Point(pInferenceResultData->singleData.fRBX, pInferenceResultData->singleData.fRBY)); cv::Mat image = pInferenceResultData->cvImage(rect).clone(); //进行推理 std::vector vecInferenceResult; auto start = std::chrono::system_clock::now(); // 计时开始 yolov5model.YoloV5ClearityInferenceModel(image, vecInferenceResult, 2); auto end = std::chrono::system_clock::now(); for (const auto & j : vecInferenceResult) { if (j.class_conf < STEP2_SCORE_THRESH) { continue; } SingleData singledata; singledata.iLine = j.clear_id; singledata.iClassId = j.class_id; singledata.fScore = j.class_conf; singledata.fLTX = j.bbox[0]; singledata.fLTY = j.bbox[1]; singledata.fRBX = j.bbox[2]; singledata.fRBY = j.bbox[3]; this->resetLocation(singledata, pInferenceResultData->singleData); pVStep2OutputData->step2ResultData.vecSingleData.emplace_back(singledata); // LogDebug << "frameId:" << pVStep2OutputData->iFrameId // << " --iClassId:" << singledata.iClassId // << " iLine:" << singledata.iLine // << " score=" << singledata.fScore // << " [" // << singledata.fLTX << "," << singledata.fLTY // << "],[" // << singledata.fRBX << "," << singledata.fRBY // << "]"; } } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVStep2OutputData), true); } return APP_ERR_OK; } \ No newline at end of file +#include "ContainerStep2InferenceEngine.h" #include #include "myqueue.h" using namespace ai_matrix; ContainerStep2InferenceEngine::ContainerStep2InferenceEngine() {} ContainerStep2InferenceEngine::~ContainerStep2InferenceEngine() {} APP_ERROR ContainerStep2InferenceEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; this->modelConfig_ = Config::getins()->getModelByContainerStep2Config(); //读取模型信息 int iFolderExist = access(modelConfig_.strModelPath.c_str(), R_OK); if (iFolderExist == -1) { LogError << "模型:" << modelConfig_.strModelPath << " 不存在!"; return false; } class_num = this->modelConfig_.vecClass.size(); score_threshold = this->modelConfig_.fScoreThreshold; input_size = GET_INPUT_SIZE(model_width , model_height); output_size = GET_OUTPUT_SIZE(model_width, model_height, clear_num, class_num); det_size = clear_num + class_num + 5; int ret = initModel(); if (ret != APP_ERR_OK) { LogError << "Failed to read model info, ret = " << ret; return ret; } LogInfo << "ContainerStep2InferenceEngine Init ok"; return APP_ERR_OK; } APP_ERROR ContainerStep2InferenceEngine::initModel() { modelinfo.yolov5ClearityModelParam.uiClassNum = class_num; modelinfo.yolov5ClearityModelParam.uiClearNum = clear_num; modelinfo.yolov5ClearityModelParam.uiDetSize = det_size; modelinfo.yolov5ClearityModelParam.fScoreThreshold = score_threshold; modelinfo.yolov5ClearityModelParam.fNmsThreshold = nms_threshold; modelinfo.modelCommonInfo.uiModelWidth = model_width; modelinfo.modelCommonInfo.uiModelHeight = model_height; modelinfo.modelCommonInfo.uiInputSize = input_size; modelinfo.modelCommonInfo.uiOutputSize = output_size; modelinfo.modelCommonInfo.uiChannel = INPUT_CHANNEL; modelinfo.modelCommonInfo.uiBatchSize = batch_size; modelinfo.modelCommonInfo.strInputBlobName = INPUT_BLOB_NAME; modelinfo.modelCommonInfo.strOutputBlobName = OUTPUT_BLOB_NAME; string strModelName; int nRet = yolov5model.YoloV5ClearityInferenceInit(&modelinfo, strModelName, this->modelConfig_.strModelPath); if (nRet != 0) { LogInfo << "YoloV5ClassifyInferenceInit nRet:" << nRet; return APP_ERR_COMM_READ_FAIL; } return APP_ERR_OK; } APP_ERROR ContainerStep2InferenceEngine::DeInit() { yolov5model.YoloV5ClearityInferenceDeinit(); LogInfo << "ContainerStep2InferenceEngine DeInit ok"; return APP_ERR_OK; } void ContainerStep2InferenceEngine::resetLocation(SingleData &singleData, SingleData &step1SingleData, float fResizeRatio) { singleData.fLTX = singleData.fLTX * fResizeRatio + step1SingleData.fLTX; singleData.fLTY = singleData.fLTY * fResizeRatio + step1SingleData.fLTY; singleData.fRBX = singleData.fRBX * fResizeRatio + step1SingleData.fLTX; singleData.fRBY = singleData.fRBY * fResizeRatio + step1SingleData.fLTY; singleData.fLTX = (singleData.fLTX < IMAGE_WIDTH) ? singleData.fLTX : IMAGE_WIDTH; singleData.fLTY = (singleData.fLTY < IMAGE_HEIGHT) ? singleData.fLTY : IMAGE_HEIGHT; singleData.fRBX = (singleData.fRBX < IMAGE_WIDTH) ? singleData.fRBX : IMAGE_WIDTH; singleData.fRBY = (singleData.fRBY < IMAGE_HEIGHT) ? singleData.fRBY : IMAGE_HEIGHT; } APP_ERROR ContainerStep2InferenceEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms continue; } std::shared_ptr pInferenceResultData = std::static_pointer_cast(pVoidData0); std::shared_ptr pVStep2OutputData = std::make_shared(); // VStep2OutputData vStep2OutputData; pVStep2OutputData->iFrameId = pInferenceResultData->iFrameId; pVStep2OutputData->iDataSource = pInferenceResultData->iDataSource; pVStep2OutputData->bIsEnd = pInferenceResultData->bIsEnd; pVStep2OutputData->strDetectDate = pInferenceResultData->strDetectDate; pVStep2OutputData->strDetectTime = pInferenceResultData->strDetectTime; pVStep2OutputData->cvImage = pInferenceResultData->cvImage.clone(); // *pVStep2OutputData = vStep2OutputData; if (pInferenceResultData->bIsEnd) { outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVStep2OutputData), true); continue; } if (pInferenceResultData->cvImage.empty()) { // LogWarn << " 帧:" << pVStep2OutputData->iFrameId << " 数据源:" << pVStep2OutputData->iDataSource << " 所传图像为空"; outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVStep2OutputData), true); usleep(1000); //1ms continue; } // LogWarn << "-- 0 -->" << pInferenceResultData->vecSingleData.size(); for (auto & single : pInferenceResultData->vecSingleData) { Step2ResultData step2ResultData; step2ResultData.fLTX = single.fLTX; step2ResultData.fLTY = single.fLTY; step2ResultData.fRBX = single.fRBX; step2ResultData.fRBY = single.fRBY; step2ResultData.iClassId = single.iClassId; step2ResultData.fScore = single.fScore; step2ResultData.iTrainIndex = single.iTrainIndex; if (single.iTargetType == CORNER) { pVStep2OutputData->vecCornerResultData.emplace_back(step2ResultData); continue; }; } // LogInfo << " -V--- " << pInferenceResultData->singleData.fScore; if (pInferenceResultData->singleData.fScore > 0.0f) { pVStep2OutputData->step2ResultData.fLTX = pInferenceResultData->singleData.fLTX; pVStep2OutputData->step2ResultData.fLTY = pInferenceResultData->singleData.fLTY; pVStep2OutputData->step2ResultData.fRBX = pInferenceResultData->singleData.fRBX; pVStep2OutputData->step2ResultData.fRBY = pInferenceResultData->singleData.fRBY; pVStep2OutputData->step2ResultData.iClassId = pInferenceResultData->singleData.iClassId; pVStep2OutputData->step2ResultData.fScore = pInferenceResultData->singleData.fScore; pVStep2OutputData->step2ResultData.iTrainIndex = pInferenceResultData->singleData.iTrainIndex; cv::Rect rect(cv::Point(pInferenceResultData->singleData.fLTX, pInferenceResultData->singleData.fLTY), cv::Point(pInferenceResultData->singleData.fRBX, pInferenceResultData->singleData.fRBY)); cv::Mat image = pInferenceResultData->cvImage(rect).clone(); //进行推理 std::vector vecInferenceResult; auto start = std::chrono::system_clock::now(); // 计时开始 yolov5model.YoloV5ClearityInferenceModel(image, vecInferenceResult, 2); auto end = std::chrono::system_clock::now(); for (const auto & j : vecInferenceResult) { if (j.class_conf < STEP2_SCORE_THRESH) { continue; } SingleData singledata; singledata.iLine = j.clear_id; singledata.iClassId = j.class_id; singledata.fScore = j.class_conf; singledata.fLTX = j.bbox[0]; singledata.fLTY = j.bbox[1]; singledata.fRBX = j.bbox[2]; singledata.fRBY = j.bbox[3]; this->resetLocation(singledata, pInferenceResultData->singleData); pVStep2OutputData->step2ResultData.vecSingleData.emplace_back(singledata); // LogDebug << "frameId:" << pVStep2OutputData->iFrameId // << " --iClassId:" << singledata.iClassId // << " iLine:" << singledata.iLine // << " score=" << singledata.fScore // << " [" // << singledata.fLTX << "," << singledata.fLTY // << "],[" // << singledata.fRBX << "," << singledata.fRBY // << "]"; } } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pVStep2OutputData), true); } return APP_ERR_OK; } \ No newline at end of file