513 lines
19 KiB
C++
513 lines
19 KiB
C++
#include "SelectBestContainerEngine.h"
|
||
#include "myutils.h"
|
||
|
||
#define CONTAINER_LEN 11
|
||
|
||
using namespace ai_matrix;
|
||
|
||
|
||
SelectBestContainerEngine::SelectBestContainerEngine() {}
|
||
|
||
SelectBestContainerEngine::~SelectBestContainerEngine() {}
|
||
|
||
APP_ERROR SelectBestContainerEngine::Init()
|
||
{
|
||
strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0";
|
||
strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1";
|
||
|
||
//获取几个摄像头识别集装箱
|
||
std::map<int, ai_matrix::DataSourceConfig> 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 Init ok";
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
APP_ERROR SelectBestContainerEngine::DeInit()
|
||
{
|
||
LogInfo << "SelectBestContainerEngine DeInit ok";
|
||
return APP_ERR_OK;
|
||
}
|
||
|
||
/**
|
||
* 初始化参数信息
|
||
* inParam : N/A
|
||
* outParam: N/A
|
||
* return : N/A
|
||
*/
|
||
void SelectBestContainerEngine::InitParam()
|
||
{
|
||
for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
|
||
{
|
||
iter->second = false;
|
||
}
|
||
mapTCFail0_.clear();
|
||
mapTCSucc0_.clear();
|
||
mapStep1Pre0_.clear();
|
||
mapSecondFlag0_.clear();
|
||
|
||
mapTCFail1_.clear();
|
||
mapTCSucc1_.clear();
|
||
mapStep1Pre1_.clear();
|
||
mapSecondFlag1_.clear();
|
||
}
|
||
|
||
/**
|
||
* 验证集装箱号是否满足规则(前10位依次与2^0 ~2^9相乘)/11 所得余数,即是校验位)
|
||
* inParam : std::string &strContainerNo 集装箱号信息
|
||
* outParam: N/A
|
||
* return : true(校验通过)/false(校验失败)
|
||
*/
|
||
bool SelectBestContainerEngine::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::MakeBestContainer(Container &containerBest,
|
||
TransSubData *pTransSubData,
|
||
std::shared_ptr<ProcessData> pProcessData)
|
||
{
|
||
// std::string strContainerInfo;
|
||
// for (size_t i = 0; i < pTransSubData->vecTransInfo.size(); i++)
|
||
// {
|
||
// TransInfo transInfo = pTransSubData->vecTransInfo[i];
|
||
// for (size_t j = 0; j < transInfo.vecValue.size(); j++)
|
||
// {
|
||
// strContainerInfo += transInfo.vecValue[j];
|
||
// }
|
||
// }
|
||
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 : TransSubData &transSubData 单个转换结果
|
||
: std::shared_ptr<ProcessData> pProcessData 帧处理信息
|
||
: int iIndex 第几个箱号
|
||
* outParam: N/A
|
||
* return : N/A
|
||
*/
|
||
void SelectBestContainerEngine::DealFailContianer(TransSubData &transSubData, std::shared_ptr<ProcessData> pProcessData,
|
||
int iIndex, std::map<int, TrainContainer> &mapTCFail)
|
||
{
|
||
if (mapTCFail.find(pProcessData->iDataSource) == mapTCFail.end())
|
||
{
|
||
mapTCFail[pProcessData->iDataSource] = TrainContainer();
|
||
}
|
||
|
||
Container containerTemp;
|
||
if (iIndex == 1)
|
||
{
|
||
containerTemp = mapTCFail[pProcessData->iDataSource].container1;
|
||
}
|
||
else if (iIndex == 2)
|
||
{
|
||
containerTemp = mapTCFail[pProcessData->iDataSource].container2;
|
||
}
|
||
|
||
if (transSubData.strAllValue.length() > containerTemp.strContainerNo.length())
|
||
{
|
||
Container containerBest;
|
||
MakeBestContainer(containerBest, &transSubData, pProcessData);
|
||
|
||
if (iIndex == 1)
|
||
{
|
||
mapTCFail[pProcessData->iDataSource].container1 = containerBest;
|
||
}
|
||
else if (iIndex == 2)
|
||
{
|
||
mapTCFail[pProcessData->iDataSource].container2 = containerBest;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 处理成功的集装箱信息
|
||
* inParam : TransSubData &transSubData 单个转换结果
|
||
: std::shared_ptr<ProcessData> pProcessData 帧处理信息
|
||
* outParam: N/A
|
||
* return : N/A
|
||
*/
|
||
void SelectBestContainerEngine::DealSuccContianer(TransSubData &transSubData, std::shared_ptr<ProcessData> pProcessData,
|
||
int iIndex, std::map<int, TrainContainer> &mapTCSucc)
|
||
{
|
||
if (mapTCSucc.find(pProcessData->iDataSource) == mapTCSucc.end())
|
||
{
|
||
mapTCSucc[pProcessData->iDataSource] = TrainContainer();
|
||
}
|
||
|
||
//iIndex == 1表示第一个集装箱,只有第一个时才设置到第一个集装箱中。防止第一个未校验通过,第二个校验通过的设置为1.
|
||
if (iIndex == 1)
|
||
{
|
||
Container containerTemp1 = mapTCSucc[pProcessData->iDataSource].container1;
|
||
if (containerTemp1.strContainerNo.empty() || transSubData.strAllValue == containerTemp1.strContainerNo)
|
||
{
|
||
if (transSubData.fScoreSum > containerTemp1.fScoreSum)
|
||
{
|
||
Container containerBest;
|
||
MakeBestContainer(containerBest, &transSubData, pProcessData);
|
||
mapTCSucc[pProcessData->iDataSource].container1 = containerBest;
|
||
}
|
||
return;
|
||
}
|
||
}
|
||
|
||
Container containerTemp2 = mapTCSucc[pProcessData->iDataSource].container2;
|
||
if (containerTemp2.strContainerNo.empty() || transSubData.strAllValue == containerTemp2.strContainerNo)
|
||
{
|
||
if (transSubData.fScoreSum > containerTemp2.fScoreSum)
|
||
{
|
||
Container containerBest;
|
||
MakeBestContainer(containerBest, &transSubData, pProcessData);
|
||
mapTCSucc[pProcessData->iDataSource].container2 = containerBest;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 识别成功和失败中选取最优结果
|
||
* inParam : std::shared_ptr<TrainContainer> pTrainContainer 选优结果
|
||
* outParam: N/A
|
||
* return : N/A
|
||
*/
|
||
void SelectBestContainerEngine::SelectBestTrainContainer(std::shared_ptr<TrainContainer> pTrainContainer)
|
||
{
|
||
Container container1;
|
||
Container container2;
|
||
/*
|
||
数据源之间选择时,正确的选得分高的,错误的选长度长的。
|
||
优先从正向数据中获取,正向未通过校验或正向无数据再取反向数据
|
||
*/
|
||
|
||
//1.获取正向校验通过数据
|
||
for (auto iterSucee = mapTCSucc0_.begin(); iterSucee != mapTCSucc0_.end(); iterSucee++)
|
||
{
|
||
LogDebug << "sourceid:" << iterSucee->first << " frameid:" << iterSucee->second.container1.strBestImg
|
||
<< " containerNo1:" << iterSucee->second.container1.strContainerNo << " frameid:" << iterSucee->second.container2.strBestImg
|
||
<< " containerNo2:" << iterSucee->second.container2.strContainerNo;
|
||
if (!iterSucee->second.container1.strContainerNo.empty() && iterSucee->second.container1.fScoreSum > container1.fScoreSum)
|
||
{
|
||
container1 = iterSucee->second.container1;
|
||
}
|
||
|
||
if (!iterSucee->second.container2.strContainerNo.empty() && iterSucee->second.container2.fScoreSum > container2.fScoreSum)
|
||
{
|
||
if (iterSucee->second.container2.strContainerNo == container1.strContainerNo)
|
||
{
|
||
LogError << "sourceid:" << iterSucee->first << " frameid:" << iterSucee->second.container2.strBestImg
|
||
<< " containerNo2:" << iterSucee->second.container2.strContainerNo << " equal containerNo1";
|
||
continue;
|
||
}
|
||
container2 = iterSucee->second.container2;
|
||
}
|
||
}
|
||
pTrainContainer->container1 = container1;
|
||
pTrainContainer->container2 = container2;
|
||
if (!pTrainContainer->container1.strContainerNo.empty() && !pTrainContainer->container2.strContainerNo.empty())
|
||
{
|
||
//正向全部识别成功直接返回。
|
||
return;
|
||
}
|
||
|
||
//2. 正向没全部识别成功,获取反向校验通过数据
|
||
Container containerRev1;
|
||
Container containerRev2;
|
||
for (auto iterSucee = mapTCSucc1_.begin(); iterSucee != mapTCSucc1_.end(); iterSucee++)
|
||
{
|
||
LogDebug << "reverse sourceid:" << iterSucee->first << " frameid:"<< iterSucee->second.container1.strBestImg
|
||
<< " containerNo1:" << iterSucee->second.container1.strContainerNo << " frameid:"<< iterSucee->second.container2.strBestImg
|
||
<< " containerNo2:" << iterSucee->second.container2.strContainerNo;
|
||
if (!iterSucee->second.container1.strContainerNo.empty() && iterSucee->second.container1.fScoreSum > containerRev1.fScoreSum)
|
||
{
|
||
containerRev1 = iterSucee->second.container1;
|
||
}
|
||
|
||
if (!iterSucee->second.container2.strContainerNo.empty() && iterSucee->second.container2.fScoreSum > containerRev2.fScoreSum)
|
||
{
|
||
containerRev2 = iterSucee->second.container2;
|
||
}
|
||
}
|
||
|
||
//反向识别且和正向不相等则,按时间顺序设置。
|
||
if (!containerRev1.strContainerNo.empty() && containerRev1.strContainerNo != pTrainContainer->container1.strContainerNo)
|
||
{
|
||
//正向没识别第一个时,反向识别,则反向作为第一个。
|
||
if (pTrainContainer->container1.strContainerNo.empty())
|
||
{
|
||
pTrainContainer->container1 = containerRev1;
|
||
}
|
||
else
|
||
{
|
||
//正向识别第一个,则肯定没识别到第二个,因此按时间处理下。如果反向也只识别到第一个,则作为第二个集装箱号。
|
||
Container container1Temp = pTrainContainer->container1;
|
||
if(container1Temp.i64TimeStamp >= containerRev1.i64TimeStamp)
|
||
{
|
||
pTrainContainer->container2 = container1Temp;
|
||
pTrainContainer->container1 = containerRev1;
|
||
}
|
||
else if (containerRev2.strContainerNo.empty())
|
||
{
|
||
pTrainContainer->container2 = containerRev1;
|
||
}
|
||
}
|
||
}
|
||
if (!containerRev2.strContainerNo.empty() && containerRev2.strContainerNo != pTrainContainer->container2.strContainerNo)
|
||
{
|
||
if (pTrainContainer->container2.strContainerNo.empty() )
|
||
{
|
||
pTrainContainer->container2 = containerRev2;
|
||
}
|
||
}
|
||
|
||
if (!pTrainContainer->container1.strContainerNo.empty() && !pTrainContainer->container2.strContainerNo.empty())
|
||
{
|
||
return;
|
||
}
|
||
|
||
//3. 获取正向未校验通过数据
|
||
for (auto iterFail = mapTCFail0_.begin(); iterFail != mapTCFail0_.end(); iterFail++)
|
||
{
|
||
LogDebug << "sourceid:" << iterFail->first << " frameid:"<< iterFail->second.container1.strBestImg
|
||
<< " containerNo1:" << iterFail->second.container1.strContainerNo << " frameid:"<< iterFail->second.container2.strBestImg
|
||
<< " containerNo2:" << iterFail->second.container2.strContainerNo;
|
||
|
||
if (pTrainContainer->container1.strContainerNo.empty())
|
||
{
|
||
if (iterFail->second.container1.strContainerNo.length() > pTrainContainer->container1.strContainerNo.length())
|
||
{
|
||
pTrainContainer->container1 = iterFail->second.container1;
|
||
}
|
||
}
|
||
if (pTrainContainer->container2.strContainerNo.empty())
|
||
{
|
||
if (iterFail->second.container2.strContainerNo.length() > pTrainContainer->container2.strContainerNo.length())
|
||
{
|
||
pTrainContainer->container2 = iterFail->second.container2;
|
||
}
|
||
}
|
||
}
|
||
|
||
//4.获取反向未通过校验数据 (正向有内容不再取反向内容)
|
||
if (pTrainContainer->container1.strContainerNo.empty() || pTrainContainer->container2.strContainerNo.empty())
|
||
{
|
||
for (auto iterFail = mapTCFail1_.begin(); iterFail != mapTCFail1_.end(); iterFail++)
|
||
{
|
||
LogDebug << "reverse sourceid:" << iterFail->first << " frameid:" << iterFail->second.container1.strBestImg
|
||
<< " containerNo1:" << iterFail->second.container1.strContainerNo << " frameid:" << iterFail->second.container2.strBestImg
|
||
<< " containerNo2:" << iterFail->second.container2.strContainerNo;
|
||
if (pTrainContainer->container1.strContainerNo.empty())
|
||
{
|
||
if (iterFail->second.container1.strContainerNo.length() > pTrainContainer->container1.strContainerNo.length())
|
||
{
|
||
pTrainContainer->container1 = iterFail->second.container1;
|
||
}
|
||
}
|
||
if (pTrainContainer->container2.strContainerNo.empty())
|
||
{
|
||
if (iterFail->second.container2.strContainerNo.length() > pTrainContainer->container2.strContainerNo.length())
|
||
{
|
||
pTrainContainer->container2 = iterFail->second.container2;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 识别成功和失败中选取最优结果
|
||
* inParam : std::shared_ptr<TrainContainer> pTrainContainer 选优结果
|
||
* outParam: N/A
|
||
* return : N/A
|
||
*/
|
||
void SelectBestContainerEngine::DealContainer(std::shared_ptr<ProcessData> pProcessData, TransSubData &transSubData,
|
||
std::map<int, TrainContainer> &mapTCSucc, std::map<int, TrainContainer> &mapTCFail,
|
||
std::map<int, Step1Location> &mapStep1Pre, std::map<int, bool> &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 / 2;
|
||
iPreCenter = mapStep1Pre[pProcessData->iDataSource].fLTY;
|
||
iCurCenter = transSubData.step1Location.fLTY;
|
||
}
|
||
else
|
||
{
|
||
//侧部集装箱,使用X坐标比较
|
||
iCompareValue = pProcessData->iWidth / 2;
|
||
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;
|
||
if (!bChkFlag)
|
||
{
|
||
DealFailContianer(transSubData, pProcessData, iIndex, mapTCFail);
|
||
}
|
||
else
|
||
{
|
||
DealSuccContianer(transSubData, pProcessData, iIndex, mapTCSucc);
|
||
}
|
||
}
|
||
|
||
|
||
APP_ERROR SelectBestContainerEngine::Process()
|
||
{
|
||
int iRet = APP_ERR_OK;
|
||
while (!isStop_)
|
||
{
|
||
//pop端口0
|
||
std::shared_ptr<void> pVoidData0 = nullptr;
|
||
iRet = inputQueMap_[strPort0_]->pop(pVoidData0);
|
||
if (nullptr == pVoidData0)
|
||
{
|
||
usleep(1000);
|
||
continue;
|
||
}
|
||
std::shared_ptr<ProcessData> pProcessData = std::static_pointer_cast<ProcessData>(pVoidData0);
|
||
std::shared_ptr<TransData> pTransData = std::static_pointer_cast<TransData>(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, mapTCSucc0_, mapTCFail0_, mapStep1Pre0_, mapSecondFlag0_);
|
||
}
|
||
//反方向信息
|
||
else if (transSubData.iBigClassId == 1)
|
||
{
|
||
LogDebug << "sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " reverse info";
|
||
DealContainer(pProcessData, transSubData, mapTCSucc1_, mapTCFail1_, mapStep1Pre1_, mapSecondFlag1_);
|
||
}
|
||
}
|
||
|
||
bool bAllEnd = true;
|
||
for (auto iter = mapDataSourceIsEnd_.begin(); iter != mapDataSourceIsEnd_.end(); iter++)
|
||
{
|
||
bAllEnd = bAllEnd && iter->second;
|
||
}
|
||
|
||
//4. 结束帧时,全部处理掉
|
||
if (bAllEnd)
|
||
{
|
||
std::shared_ptr<TrainContainer> pTrainContainer = std::make_shared<TrainContainer>();
|
||
SelectBestTrainContainer(pTrainContainer);
|
||
|
||
outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pTrainContainer));
|
||
//push端口1,记录csv
|
||
outputQueMap_[strPort1_]->push(std::static_pointer_cast<void>(pTrainContainer));
|
||
|
||
//初始化参数变量
|
||
InitParam();
|
||
}
|
||
}
|
||
return APP_ERR_OK;
|
||
}
|