1 line
19 KiB
C++
1 line
19 KiB
C++
#include "ContainerDivideEngine.h"
|
||
|
||
#include <utility>
|
||
|
||
|
||
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<VSelectBestData> pVSelectBestData = std::make_shared<VSelectBestData>();
|
||
*pVSelectBestData = selectBestData;
|
||
outputQueMap_[strPort0_]->push(std::static_pointer_cast<void>(pVSelectBestData), true);
|
||
LogInfo << " 帧:" << selectBestData.iFrameId
|
||
<< " 数据源:" << selectBestData.iDataSource
|
||
<< " 节:" << selectBestData.iContainerIndex
|
||
<< " 发送识别结果 " << selectBestData.strNumResult;
|
||
this->stdContainerResult_ = selectBestData.strNumResult;
|
||
this->iContainerIndex++;
|
||
}
|
||
|
||
void ContainerDivideEngine::makeResult(const std::shared_ptr<VStep2OutputData>& 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<VStep2OutputData> 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<std::string, int> mapContainer_count;
|
||
std::map<std::string, int> 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<std::string, int> 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<VStep2OutputData> 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<VStep2OutputData> 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<void> pVoidData0 = nullptr;
|
||
iRet = inputQueMap_[strPort0_]->pop(pVoidData0);
|
||
if (nullptr == pVoidData0)
|
||
{
|
||
usleep(1000);
|
||
continue;
|
||
}
|
||
std::shared_ptr<VStep2OutputData> pVStep2OutputData = std::static_pointer_cast<VStep2OutputData>(pVoidData0);
|
||
|
||
if (pVStep2OutputData->bIsEnd)
|
||
{
|
||
std::shared_ptr<VSelectBestData> pVSelectBestData = std::make_shared<VSelectBestData>();
|
||
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<void>(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<void>(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;
|
||
}
|