#include "SelectBestContainerEngine_NEW.h" #include "myutils.h" #define CONTAINER_LEN 11 using namespace ai_matrix; SelectBestContainerEngine_NEW::SelectBestContainerEngine_NEW() {} SelectBestContainerEngine_NEW::~SelectBestContainerEngine_NEW() {} APP_ERROR SelectBestContainerEngine_NEW::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; //获取几个摄像头识别集装箱 std::map mapUseDataSouceCfg = MyYaml::GetIns()->GetUseDataSourceConfig(); for (auto iter = mapUseDataSouceCfg.begin(); iter != mapUseDataSouceCfg.end(); iter++) { if (iter->second.strTarget.find("CONTAINER") != std::string::npos) { LogDebug << "DataSource:" << iter->first << " deal CONTAINER"; mapDataSourceIsEnd_[iter->first] = false; if (iter->second.strTarget.find("CONTAINER_T") != std::string::npos) { setTopContainerSid_.insert(iter->first); } } } InitParam(); LogInfo << "SelectBestContainerEngine_NEW Init ok"; return APP_ERR_OK; } APP_ERROR SelectBestContainerEngine_NEW::DeInit() { LogInfo << "SelectBestContainerEngine_NEW DeInit ok"; return APP_ERR_OK; } /** * 初始化参数信息 * inParam : N/A * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::InitParam() { for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++) { iter->second = false; } mapSidContainers0_.clear(); mapSidConBest0_.clear(); mapStep1Pre0_.clear(); mapSecondFlag0_.clear(); mapSidContainers1_.clear(); mapSidConBest1_.clear(); mapStep1Pre1_.clear(); mapSecondFlag1_.clear(); } /** * 验证集装箱号是否满足规则(前10位依次与2^0 ~2^9相乘)/11 所得余数,即是校验位) * inParam : std::string &strContainerNo 集装箱号信息 * outParam: N/A * return : true(校验通过)/false(校验失败) */ bool SelectBestContainerEngine_NEW::VerifyContainerNo(std::string &strContainerNo) { bool bChkFlag = false; if(strContainerNo.length() != CONTAINER_LEN) { return bChkFlag; } int iSum = 0; for (int i = 0; i < strContainerNo.length()-1; ++i) { iSum += 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; } /** * 构造最优集装箱信息 * inParam : N/A * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::MakeBestContainer(Container &containerBest, TransSubData *pTransSubData, std::shared_ptr pProcessData) { containerBest.iDataSource = pProcessData->iDataSource; containerBest.i64TimeStamp = pProcessData->i64TimeStamp; containerBest.bIsEnd = pProcessData->bIsEnd; containerBest.strTrainDate = pProcessData->strTrainDate; containerBest.strTrainName = pProcessData->strTrainName; containerBest.step1Location = pTransSubData->step1Location; containerBest.strBestImg = std::to_string(pProcessData->iFrameId) + ".jpg"; containerBest.fScoreSum = pTransSubData->fScoreSum; containerBest.strContainerNo = pTransSubData->strAllValue; } /** * 识别成功和失败中选取最优结果 * inParam : std::shared_ptr pTrainContainer 选优结果 * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::DealContainer(std::shared_ptr pProcessData, TransSubData &transSubData, std::map>> &mapSidContainers, std::map &mapStep1Pre, std::map &mapSecondFlag) { /* mapStep1Pre先保存第1个箱号上一帧识别结果的大框信息。当识别大框信息和保存上一个识别信息间隔大于画面一半时, 则说明识别到了第2个箱号,此时mapStep1Pre保存第2个箱号的上一帧的大框信息。 mapStep1Pre保存的第1个箱号时 和前帧识别大框间隔小于画面一半时,则属于第1个箱号,否则属于第2个箱号 mapStep1Pre保存的第2个箱号时 和前帧识别大框间隔小于画面一半时,则属于第2个箱号,否则属于第1个箱号 */ if (mapStep1Pre.find(pProcessData->iDataSource) == mapStep1Pre.end()) { mapStep1Pre[pProcessData->iDataSource] = transSubData.step1Location; } if (mapSecondFlag.find(pProcessData->iDataSource) == mapSecondFlag.end()) { mapSecondFlag[pProcessData->iDataSource] = false; } int iCompareValue = 0; int iPreCenter = 0; int iCurCenter = 0; if (setTopContainerSid_.count(pProcessData->iDataSource) != 0) { //顶部集装箱,使用Y坐标比较 iCompareValue = pProcessData->iHeight / 3; iPreCenter = mapStep1Pre[pProcessData->iDataSource].fLTY; iCurCenter = transSubData.step1Location.fLTY; } else { //侧部集装箱,使用X坐标比较 iCompareValue = pProcessData->iWidth / 3; iPreCenter = mapStep1Pre[pProcessData->iDataSource].fLTX; iCurCenter = transSubData.step1Location.fLTX; } int iIndex = 0; if (!mapSecondFlag[pProcessData->iDataSource]) { iIndex = 1; if (abs(iPreCenter - iCurCenter) > iCompareValue) { iIndex = 2; mapSecondFlag[pProcessData->iDataSource] = true; } mapStep1Pre[pProcessData->iDataSource] = transSubData.step1Location; } else { if (abs(iPreCenter - iCurCenter) > iCompareValue) { iIndex = 1; } else { iIndex = 2; mapStep1Pre[pProcessData->iDataSource] = transSubData.step1Location; } } //集装箱校验 bool bChkFlag = true; for (auto iter = transSubData.vecTransInfo.begin(); iter != transSubData.vecTransInfo.end(); ++iter) { bChkFlag &= iter->IsChkFlag; } if (bChkFlag) { bChkFlag = VerifyContainerNo(transSubData.strAllValue); } LogDebug << "datasource:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " iIndex:" << iIndex << " containerNo:" << transSubData.strAllValue << " chkflag:" << bChkFlag; Container containerBest; MakeBestContainer(containerBest, &transSubData, pProcessData); containerBest.bChkFlag = bChkFlag; mapSidContainers[pProcessData->iDataSource][iIndex].push_back(containerBest); } /** * 识别成功和失败中选取最优结果 * inParam : std::shared_ptr pTrainContainer 选优结果 * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::GetBestContainerBySid(std::map>> &mapSidContainers, std::map> &mapSidConBest) { for (auto iter = mapSidContainers.begin(); iter != mapSidContainers.end(); iter++) { for (auto iterSub = iter->second.begin(); iterSub != iter->second.end(); iterSub++) { std::map mapConCnt; Container containerSucc; Container containerFail; bool bNoSameFlag = false; for (int i = 0; i < iterSub->second.size(); i++) { if (!iterSub->second[i].bChkFlag) { // 校验失败的数据,找一个最长的识别即可 if (containerFail.strContainerNo.length() < iterSub->second[i].strContainerNo.length()) { containerFail = iterSub->second[i]; } continue; } //统计识别校验通过箱号的频次 if (mapConCnt.find(iterSub->second[i].strContainerNo) != mapConCnt.end()) { mapConCnt[iterSub->second[i].strContainerNo]++; } else { mapConCnt[iterSub->second[i].strContainerNo] = 1; } if (containerSucc.strContainerNo.empty()) { containerSucc = iterSub->second[i]; continue; } if (containerSucc.strContainerNo == iterSub->second[i].strContainerNo) { // 校验通过且相同的,选取得分最高的。 if (containerSucc.fScoreSum < iterSub->second[i].fScoreSum) { containerSucc = iterSub->second[i]; continue; } } else { LogDebug << "sourceid:" << iter->first << " frameid:" << iterSub->second[i].strBestImg << " containerNo:" << iterSub->second[i].strContainerNo << " no equal frameid:" << containerSucc.strBestImg << " containerNo:" << containerSucc.strContainerNo; bNoSameFlag = true; } } //有识别不相同时,选取识别次数最多的。 if (bNoSameFlag) { int iCnt = 0; std::string strMaxContainerNO; for (auto it = mapConCnt.begin(); it != mapConCnt.end(); it++) { LogDebug << "sourceid:" << iter->first << " containerNo:" << it->first << " cnt:" << it->second; if (iCnt < it->second) { iCnt = it->second; strMaxContainerNO = it->first; } } //根据识别次数最多的箱号,获取最优箱号图 float fMaxScoreSum = 0.0; for (int i = 0; i < iterSub->second.size(); i++) { if (iterSub->second[i].strContainerNo == strMaxContainerNO && iterSub->second[i].fScoreSum > fMaxScoreSum) { fMaxScoreSum = iterSub->second[i].fScoreSum; containerSucc = iterSub->second[i]; } } } if (mapSidConBest.find(iter->first) == mapSidConBest.end()) { mapSidConBest[iter->first] = std::vector(); } if (!containerSucc.strContainerNo.empty()) { mapSidConBest[iter->first].push_back(containerSucc); LogDebug << "sourceid:" << iter->first << " index:" << iterSub->first << " push frameid:" << containerSucc.strBestImg << " containerNo:" << containerSucc.strContainerNo << " chkFlag:" << containerSucc.bChkFlag; } else { mapSidConBest[iter->first].push_back(containerFail); LogDebug << "sourceid:" << iter->first << " index:" << iterSub->first << " push frameid:" << containerFail.strBestImg << " containerNo:" << containerFail.strContainerNo << " chkFlag:" << containerFail.bChkFlag; } } } } /** * 识别成功和失败中选取最优结果 * inParam : std::shared_ptr pTrainContainer 选优结果 * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::GetBestContainer(TrainContainer &trainContainerSucc, TrainContainer &trainContainerFail, std::map> &mapSidConBest) { int iBestContainerSid = 0; //默认主摄像头 bool bMainCamFlag = false; for (auto iter = mapSidConBest.begin(); iter != mapSidConBest.end(); iter++) { //获取2个箱号都识别的摄像头id if (iter->second.size() > 1) { if (iter->second.at(0).bChkFlag && iter->second.at(1).bChkFlag) { iBestContainerSid = iter->first; break; } if (!bMainCamFlag && (iter->second.at(0).bChkFlag || iter->second.at(1).bChkFlag)) { iBestContainerSid = iter->first; bMainCamFlag = (iter->first == 0 ? true : false); } } } LogDebug << "best sourceid:" << iBestContainerSid << " size:" << mapSidConBest[iBestContainerSid].size(); // 按一个摄像头,获取2次识别结果 if (mapSidConBest[iBestContainerSid].size() > 0) { if (mapSidConBest[iBestContainerSid].at(0).bChkFlag) { trainContainerSucc.container1 = mapSidConBest[iBestContainerSid].at(0); } else { trainContainerFail.container1 = mapSidConBest[iBestContainerSid].at(0); } } if (mapSidConBest[iBestContainerSid].size() > 1) { if (mapSidConBest[iBestContainerSid].at(1).bChkFlag) { trainContainerSucc.container2 = mapSidConBest[iBestContainerSid].at(1); } else { trainContainerFail.container2 = mapSidConBest[iBestContainerSid].at(1); } } /* 循环处理所有摄像头识别结果 1.识别正确,按得分比较取最优结果。 */ for (auto iter = mapSidConBest.begin(); iter != mapSidConBest.end(); iter++) { if (iter->first == iBestContainerSid) { continue; } if (iter->second.size() > 0) { if (iter->second.at(0).bChkFlag) { //都校验通过,且相等则按得分比较 if (trainContainerSucc.container1.bChkFlag) { if (trainContainerSucc.container1.strContainerNo == iter->second.at(0).strContainerNo && trainContainerSucc.container1.fScoreSum < iter->second.at(0).fScoreSum) { trainContainerSucc.container1 = iter->second.at(0); } } else { //一个校验通过,则需和箱号2判断是否相等,不一致则用校验通过替换,如果一致,则不替换。(防止一侧摄像头只能识别位置是2的箱号) if (trainContainerSucc.container2.strContainerNo != iter->second.at(0).strContainerNo) { trainContainerSucc.container1 = iter->second.at(0); } } } else { if (trainContainerFail.container1.strContainerNo.length() < iter->second.at(0).strContainerNo.length()) { trainContainerFail.container1 = iter->second.at(0); } } } if (iter->second.size() > 1) { if (iter->second.at(1).bChkFlag) { //都校验通过,且相等则按得分比较 if (trainContainerSucc.container2.bChkFlag) { if (trainContainerSucc.container2.strContainerNo == iter->second.at(1).strContainerNo && trainContainerSucc.container2.fScoreSum < iter->second.at(1).fScoreSum) { trainContainerSucc.container2 = iter->second.at(1); } } else { //一个校验通过,则需和箱号1判断是否相等,防止箱号1和2一致 if (trainContainerSucc.container1.strContainerNo != iter->second.at(1).strContainerNo) { trainContainerSucc.container2 = iter->second.at(1); } } } else { if (trainContainerFail.container2.strContainerNo.length() < iter->second.at(1).strContainerNo.length()) { trainContainerFail.container2 = iter->second.at(1); } } } } } /** * 识别成功和失败中选取最优结果 * inParam : std::shared_ptr pTrainContainer 选优结果 * outParam: N/A * return : N/A */ void SelectBestContainerEngine_NEW::SelectBestTrainContainer(std::shared_ptr pTrainContainer) { //1.获取正向校验通过数据 GetBestContainerBySid(mapSidContainers0_, mapSidConBest0_); TrainContainer trainContainerSucc0; TrainContainer trainContainerFail0; GetBestContainer(trainContainerSucc0, trainContainerFail0, mapSidConBest0_); *pTrainContainer = trainContainerSucc0; if (!trainContainerSucc0.container1.strContainerNo.empty() && !trainContainerSucc0.container2.strContainerNo.empty()) { //正向全部识别成功直接返回。 return; } //2. 正向没全部识别成功,获取反向校验通过数据 LogDebug << "select best reverse info"; GetBestContainerBySid(mapSidContainers1_, mapSidConBest1_); TrainContainer trainContainerSucc1; TrainContainer trainContainerFail1; GetBestContainer(trainContainerSucc1, trainContainerFail1, mapSidConBest1_); // 反向识别且和正向不相等则,按时间顺序设置。 if (!trainContainerSucc1.container1.strContainerNo.empty() && trainContainerSucc1.container1.strContainerNo != pTrainContainer->container1.strContainerNo) { // 正向没识别第一个时,反向识别,则反向作为第一个。 if (pTrainContainer->container1.strContainerNo.empty()) { pTrainContainer->container1 = trainContainerSucc1.container1; } else { // 正向识别第一个,则肯定没识别到第二个,因此按时间处理下。如果反向也只识别到第一个,则作为第二个集装箱号。 Container container1Temp = pTrainContainer->container1; if (container1Temp.i64TimeStamp >= trainContainerSucc1.container1.i64TimeStamp) { pTrainContainer->container2 = container1Temp; pTrainContainer->container1 = trainContainerSucc1.container1; } else if (trainContainerSucc1.container2.strContainerNo.empty()) //如果反向没识别第二个,则反向第一个做为第2个。 { pTrainContainer->container2 = trainContainerSucc1.container1; } } } if (!trainContainerSucc1.container2.strContainerNo.empty() && trainContainerSucc1.container2.strContainerNo != pTrainContainer->container2.strContainerNo) { if (pTrainContainer->container2.strContainerNo.empty() ) { pTrainContainer->container2 = trainContainerSucc1.container2; } } if (!pTrainContainer->container1.strContainerNo.empty() && !pTrainContainer->container2.strContainerNo.empty()) { return; } //3. 获取正向未校验通过数据 if (pTrainContainer->container1.strContainerNo.empty()) { pTrainContainer->container1 = trainContainerFail0.container1; } if (pTrainContainer->container2.strContainerNo.empty()) { pTrainContainer->container2 = trainContainerFail0.container2; } //4.获取反向未通过校验数据 (正向有内容不再取反向内容) if (pTrainContainer->container1.strContainerNo.empty() || pTrainContainer->container2.strContainerNo.empty()) { if (pTrainContainer->container1.strContainerNo.empty()) { pTrainContainer->container1 = trainContainerFail1.container1; } if (pTrainContainer->container2.strContainerNo.empty()) { pTrainContainer->container2 = trainContainerFail1.container2; } } } APP_ERROR SelectBestContainerEngine_NEW::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 pProcessData = std::static_pointer_cast(pVoidData0); std::shared_ptr pTransData = std::static_pointer_cast(pProcessData->pVoidData); if (pProcessData->bIsEnd) { mapDataSourceIsEnd_[pProcessData->iDataSource] = pProcessData->bIsEnd; } for (size_t i = 0; i < pTransData->vecTransSubData.size(); i++) { TransSubData transSubData = pTransData->vecTransSubData[i]; //正方向信息 if (transSubData.iBigClassId == 0) { DealContainer(pProcessData, transSubData, mapSidContainers0_, mapStep1Pre0_, mapSecondFlag0_); } //反方向信息 else if (transSubData.iBigClassId == 1) { LogDebug << "sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " reverse info"; DealContainer(pProcessData, transSubData, mapSidContainers1_, mapStep1Pre1_, mapSecondFlag1_); } } bool bAllEnd = true; for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++) { bAllEnd = bAllEnd && iter->second; } //4. 结束帧时,全部处理掉 if (bAllEnd) { std::shared_ptr pTrainContainer = std::make_shared(); SelectBestTrainContainer(pTrainContainer); if (pTrainContainer->container1.iDataSource == pTrainContainer->container2.iDataSource && pTrainContainer->container1.bChkFlag && pTrainContainer->container2.bChkFlag) { if (pTrainContainer->container1.i64TimeStamp > pTrainContainer->container2.i64TimeStamp) { LogWarn << "bestcontainer swap container1:" << pTrainContainer->container1.strBestImg << " " << pTrainContainer->container1.strContainerNo << " contianer2:" << pTrainContainer->container2.strBestImg << " " << pTrainContainer->container2.strContainerNo; Container containerTemp = pTrainContainer->container1; pTrainContainer->container1 = pTrainContainer->container2; pTrainContainer->container2 = containerTemp; } } outputQueMap_[strPort0_]->push(std::static_pointer_cast(pTrainContainer)); //push端口1,记录csv outputQueMap_[strPort1_]->push(std::static_pointer_cast(pTrainContainer)); //初始化参数变量 InitParam(); } } return APP_ERR_OK; }