#include "DataDealTwoEngine.h" using namespace ai_matrix; extern bool g_bNoDealStepTwoFlag; DataDealTwoEngine::DataDealTwoEngine() {} DataDealTwoEngine::~DataDealTwoEngine() {} APP_ERROR DataDealTwoEngine::Init() { strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; strPort2_ = engineName_ + "_" + std::to_string(engineId_) + "_2"; strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path"); iIntervalTime_ = 40 *1000; iSplitSpanPX_ = MyYaml::GetIns()->GetIntValue("gc_split_frame_span_px"); dataSourceConfig_ = MyYaml::GetIns()->GetDataSourceConfigById(engineId_); //获取摄像机参数 mapUseDataSouceCfg_ = MyYaml::GetIns()->GetUseDataSourceConfig(); std::string delimiter(","); for (auto iter = mapUseDataSouceCfg_.begin(); iter!=mapUseDataSouceCfg_.end(); iter++) { int iSourceId = iter->first; std::vector vecSplit = MyUtils::getins()->split(iter->second.strTarget, delimiter); std::vector vecPushPorts; for (auto iter = vecSplit.begin(); iter != vecSplit.end(); iter++) { if (*iter == "NUM") { vecPushPorts.push_back(strPort0_); } else if (*iter == "CHKDATE") { vecPushPorts.push_back(strPort1_); } else if(*iter == "CONTAINER" || *iter == "CONTAINER_T") { vecPushPorts.push_back(strPort2_); } } mapSourcePushPort_[iSourceId] = vecPushPorts; } InitParam(); LogInfo << "engineId_:" << engineId_ << " DataDealTwoEngine Init ok"; return APP_ERR_OK; } APP_ERROR DataDealTwoEngine::DeInit() { LogInfo << "engineId_:" << engineId_ << " DataDealTwoEngine DeInit ok"; return APP_ERR_OK; } /** * 参数初始化(列车结束时需调用) * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::InitParam() { iTrainIndex_ = 1; iDirection_ = DIRECTION_UNKNOWN; iDirectionAndFirst_ = DO_NOT_KNOW_DIRECTION; iLastSpaceX_ = 0; iLastSpaceFrameid_ = 0; iSpaceType_ = 0; } /** * 图片数据解码 * inParam : RawData &rawData :图片数据 * outParam: std::shared_ptr pDecodedData :解码数据 * return : true(编码成功)/false(编码失败) */ bool DataDealTwoEngine::GetJpegdOut(std::shared_ptr pDecodedData, RawData &rawData) { int iRet = APP_ERR_OK; return true; } /** * 获取大框信息 * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::GetPostSubDatas(std::vector &vecPostSubData, Json::Value &jvFrameInfo, Target tar, Json::Value &jvOneSplit) { std::string strKey; switch (tar) { case NUM: strKey = "step1Num"; break; case PRO: strKey = "step1Pro"; break; case CHKDATE: strKey = "step1ChkDate"; break; case CONTAINER: strKey = "step1Container"; break; default: break; } if (strKey.empty()) { return; } if (!jvFrameInfo.isMember(strKey.c_str())) { return; } float fSplitCenterX = jvOneSplit["splitX"].asFloat(); int iValidType = jvOneSplit["validType"].asInt(); Json::Value &jsArray = jvFrameInfo[strKey.c_str()]; for (int i = 0; i < jsArray.size(); i++) { float fCenterX = jsArray[i]["ltx"].asFloat() + (jsArray[i]["rbx"].asFloat() - jsArray[i]["ltx"].asFloat()) / 2; if (jvOneSplit["useY"].asBool()) { fCenterX = jsArray[i]["lty"].asFloat() + (jsArray[i]["rby"].asFloat() - jsArray[i]["lty"].asFloat()) / 2; } bool bChkFlag = false; if(iValidType == VALID_ALL) { bChkFlag = true; } else if(iValidType == VALID_LEFT && fCenterX < fSplitCenterX) { bChkFlag = true; } else if(iValidType == VALID_RIGHT && fCenterX > fSplitCenterX) { bChkFlag = true; } if (bChkFlag) { SingleData sdInfo; sdInfo.iClassId = jsArray[i]["classid"].asInt(); sdInfo.fScore = jsArray[i]["score"].asFloat(); sdInfo.fLTX = jsArray[i]["ltx"].asFloat(); sdInfo.fLTY = jsArray[i]["lty"].asFloat(); sdInfo.fRBX = jsArray[i]["rbx"].asFloat(); sdInfo.fRBY = jsArray[i]["rby"].asFloat(); sdInfo.fClear = jsArray[i]["clear"].asFloat(); PostSubData postSubData; postSubData.iBigClassId = sdInfo.iClassId; postSubData.iTargetType = tar; if (tar == NUM && postSubData.iBigClassId == 0) { postSubData.iTargetType = HEAD; } postSubData.vecSingleData.emplace_back(sdInfo); postSubData.step1Location.fLTX = sdInfo.fLTX; postSubData.step1Location.fLTY = sdInfo.fLTY; postSubData.step1Location.fRBX = sdInfo.fRBX; postSubData.step1Location.fRBY = sdInfo.fRBY; vecPostSubData.emplace_back(postSubData); } } } /** * 获取主摄像头车厢间隔坐标信息 * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::GetMainSplitInfo(Json::Value &jvMainSplit, std::shared_ptr pProcessData, Json::Value &jvFrameInfo, std::shared_ptr pTrainRange) { if (pProcessData->iDataSource != 0) { return; } Json::Value jvModelSpace; if (jvFrameInfo.isMember("step1Space")) { jvModelSpace = jvFrameInfo["step1Space"][0]; } int iValidType = VALID_ALL; //图像上大框有效类型 {0-全部有效; 1-左边有效; 2-右边有效} int iSpaceX = 0; //图像上车厢间隔位置 bool bNeedNum = true; //图像上车号框是否有效 bool bNeedPro = true; //图像上属性框是否有效 bool bNeedChkDate = true; //图像定检期框是否有效 bool bNeedContainer = true; //图像集装箱框是否有效 bool bOtherSideNeedNum = true; //另一侧图像上车号框是否有效 bool bOtherSideNeedPro = true; //另一侧图像上属性框是否有效 bool bOtherSideNeedChkDate = true; //另一侧图像上定检期框是否有效 bool bOtherSideNeedContainer = true; //另一侧图像上集装箱框是否有效 if (!jvModelSpace.empty()) { iSpaceX = jvModelSpace["ltx"].asFloat() + (jvModelSpace["rbx"].asFloat() - jvModelSpace["ltx"].asFloat()) / 2; /* 第一节只有结束间隔; 开始帧间隔为开始间隔; 向左行驶且当前间隔大于上次间隔为结束间隔,向右行驶当前间隔小于上次间隔为结束间隔。 */ bool bIntervalFlag = ((int)(pProcessData->iFrameId - iLastSpaceFrameid_) > dataSourceConfig_.iSkipInterval * 2); if (iTrainIndex_ == 1) { iSpaceType_ = 2; } else if (pTrainRange->iStartFrameId == pProcessData->iFrameId) { iSpaceType_ = 1; } else if ((pProcessData->iDirection == DIRECTION_LEFT && (iLastSpaceX_ < iSpaceX - iSplitSpanPX_) && bIntervalFlag) || (pProcessData->iDirection == DIRECTION_RIGHT && (iLastSpaceX_ - iSplitSpanPX_ > iSpaceX) && bIntervalFlag)) { iSpaceType_ = 2; } if (iSpaceType_ == 1) { iValidType = pProcessData->iDirection == DIRECTION_LEFT ? VALID_RIGHT : VALID_LEFT; } else if (iSpaceType_ == 2) { iValidType = pProcessData->iDirection == DIRECTION_LEFT ? VALID_LEFT : VALID_RIGHT; } LogDebug << " frameid:" << pProcessData->iFrameId << " 车节:" << pProcessData->iTrainIndex << " iSpaceType_:" << iSpaceType_ << " iSpaceX:" << iSpaceX << " iLastSpaceX_:" << iLastSpaceX_ << " iLastSpaceFrameid_:" << iLastSpaceFrameid_ << " bIntervalFlag:" << bIntervalFlag; iLastSpaceX_ = iSpaceX; iLastSpaceFrameid_ = pProcessData->iFrameId; } jvMainSplit["validType"] = iValidType; jvMainSplit["splitX"] = iSpaceX; jvMainSplit["needNum"] = bNeedNum; jvMainSplit["needPro"] = bNeedPro; jvMainSplit["needChkDate"] = bNeedChkDate; jvMainSplit["needContainer"] = bNeedContainer; jvMainSplit["otherSideNeedNum"] = bOtherSideNeedNum; jvMainSplit["otherSideNeedPro"] = bOtherSideNeedPro; jvMainSplit["otherSideNeedChkDate"] = bOtherSideNeedChkDate; jvMainSplit["otherSideNeedContainer"] = bOtherSideNeedContainer; jvMainSplit["mainWidth"] = pProcessData->iWidth; jvMainSplit["mainHeight"] = pProcessData->iHeight; if (pProcessData->bIsEnd) { iLastSpaceX_ = 0; iLastSpaceFrameid_ = 0; iSpaceType_ = 0; } } /** * 获取辅摄像头车厢间隔坐标信息 * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::GetSubSplitInfoByMain(Json::Value &jvOneSplit, std::shared_ptr pProcessData, Json::Value &jvFrameInfo) { if (pProcessData->iDataSource == 1) { if (pProcessData->iDirection == DIRECTION_RIGHT) { //向右行驶时,间隔坐标尽可能小一些,把未完全对其的定检期信息包含进来。 jvOneSplit["splitX"] = jvOneSplit["splitX"].asInt() - 100; } } else if (pProcessData->iDataSource == 2) { //顶部集装箱的重设splitX相关逻辑 if (jvOneSplit["rotate"].asInt() == 90) { jvOneSplit["useY"] = true; if (pProcessData->iHeight != jvOneSplit["mainWidth"].asInt()) { jvOneSplit["splitX"] = jvOneSplit["splitX"].asInt() * pProcessData->iHeight / jvOneSplit["mainWidth"].asInt(); } //顶部有间隔时,使用顶部间隔。 if (jvFrameInfo.isMember("step1TopSpace")) { Json::Value jvModelSpace = jvFrameInfo["step1TopSpace"][0]; int iSpaceX = jvModelSpace["lty"].asFloat() + (jvModelSpace["rby"].asFloat() - jvModelSpace["lty"].asFloat()) / 2; LogDebug << "sourceid" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " use TopSpace splitX:" << jvOneSplit["splitX"].asInt() << " newsplitX:" << iSpaceX; jvOneSplit["splitX"] = iSpaceX; //如果validType为0,则说明主摄像头间隔还未识别到结束间隔,则按顶部摄像头设置validType if (jvOneSplit["validType"] == VALID_ALL) { jvOneSplit["validType"] = pProcessData->iDirection == DIRECTION_LEFT ? VALID_LEFT : VALID_RIGHT; LogDebug << "sourceid" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << "reset validType:" << jvOneSplit["validType"].asInt(); } } } } else if (pProcessData->iDataSource == 3 || pProcessData->iDataSource == 4) { jvOneSplit["splitX"] = (int)(pProcessData->iWidth - jvOneSplit["splitX"].asInt()); int iValidType = jvOneSplit["validType"].asInt(); iValidType = iValidType == VALID_ALL ? iValidType : (iValidType == VALID_LEFT ? VALID_RIGHT : VALID_LEFT); jvOneSplit["validType"] = iValidType; jvOneSplit["needNum"] = jvOneSplit["otherSideNeedNum"].asBool(); jvOneSplit["needPro"] = jvOneSplit["otherSideNeedPro"].asBool(); jvOneSplit["needChkDate"] = jvOneSplit["otherSideNeedChkDate"].asBool(); jvOneSplit["needContainer"] = jvOneSplit["otherSideNeedContainer"].asBool(); if (pProcessData->iDataSource == 4 && pProcessData->iDirection == DIRECTION_LEFT) { jvOneSplit["splitX"] = jvOneSplit["splitX"].asInt() + 100; } } } /** * 获取大框有效方式和车厢间隔坐标 * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::GetValidTypeAndSplit(Json::Value &jvOneSplit, Json::Value &jvMainSplit, std::shared_ptr pProcessData, Json::Value &jvFrameInfo, std::shared_ptr pTrainRange) { if (pProcessData->iDataSource == 0) { GetMainSplitInfo(jvMainSplit, pProcessData, jvFrameInfo, pTrainRange); jvOneSplit = jvMainSplit; } else { GetSubSplitInfoByMain(jvOneSplit, pProcessData, jvFrameInfo); } // LogDebug << "sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId // << " trainIndex:" << pProcessData->iTrainIndex // << " validType:" << jvOneSplit["validType"].asInt() << " splitX:" << jvOneSplit["splitX"].asInt() // << " needNum:" << jvOneSplit["needNum"].asBool() << " needPro:" << jvOneSplit["needPro"].asBool() // << " needChkDate:" << jvOneSplit["needChkDate"].asBool() << " needContainer:" << jvOneSplit["needContainer"].asBool(); } /** * 获取大框信息 * inParam : N/A * outParam: N/A * return : N/A */ int DataDealTwoEngine::GetPostData(std::shared_ptr pProcessData, Json::Value &jvFrameInfo, Json::Value &jvOneSplit) { std::shared_ptr pPostData = std::make_shared(); pProcessData->pVoidData = std::static_pointer_cast(pPostData); if (jvOneSplit["needNum"].asBool()) { GetPostSubDatas(pPostData->vecPostSubData, jvFrameInfo, NUM, jvOneSplit); } if (jvOneSplit["needPro"].asBool()) { GetPostSubDatas(pPostData->vecPostSubData, jvFrameInfo, PRO, jvOneSplit); } if (jvOneSplit["needChkDate"].asBool()) { /* 向右行驶且间隔右边数据有效时,此时画面就1个定检期,画面上的定检期信息全部有效。 向左行驶且间隔左边数据有效时,此时画面就1个定检期,画面上的定检期信息全部有效。 */ int iValidTypeTemp = jvOneSplit["validType"].asInt(); if ((iValidTypeTemp == VALID_RIGHT && pProcessData->iDataSource == 1 && pProcessData->iDirection == DIRECTION_RIGHT) || (iValidTypeTemp == VALID_RIGHT && pProcessData->iDataSource == 4 && pProcessData->iDirection == DIRECTION_LEFT) || (iValidTypeTemp == VALID_LEFT && pProcessData->iDataSource == 1 && pProcessData->iDirection == DIRECTION_LEFT) || (iValidTypeTemp == VALID_LEFT && pProcessData->iDataSource == 4 && pProcessData->iDirection == DIRECTION_RIGHT)) { jvOneSplit["validType"] = 0; } GetPostSubDatas(pPostData->vecPostSubData, jvFrameInfo, CHKDATE, jvOneSplit); jvOneSplit["validType"] = iValidTypeTemp; } if (jvOneSplit["needContainer"].asBool()) { GetPostSubDatas(pPostData->vecPostSubData, jvFrameInfo, CONTAINER, jvOneSplit); } return pPostData->vecPostSubData.size(); } /** * push数据到队列,队列满时则休眠一段时间再push。 * inParam : const std::string strPort push的端口 : const std::shared_ptr &pProcessData push的数据 * outParam: N/A * return : N/A */ void DataDealTwoEngine::PushData(const std::string &strPort, const std::shared_ptr &pProcessData) { while (true) { int iRet = outputQueMap_[strPort]->push(std::static_pointer_cast(pProcessData)); if (iRet != 0) { LogDebug << "sourceid:" << pProcessData->iDataSource << " frameid:" << pProcessData->iFrameId << " push fail iRet:" << iRet; if (iRet == 2) { usleep(10000); // 10ms continue; } } break; } } /** * 构造处理数据并push * inParam : N/A * outParam: N/A * return : N/A */ void DataDealTwoEngine::MakeProcessData(std::shared_ptr pTrainRange) { int iRet = APP_ERR_OK; int iDataNO = 1; std::string strDataDir = strResultPath_ + pTrainRange->strTrainDate + "/" + pTrainRange->strTrainName + "/"; for (int iFrameId = pTrainRange->iStartFrameId; iFrameId <= pTrainRange->iEndFrameId; iFrameId += dataSourceConfig_.iSkipInterval) { Json::Value jvMainSplit; //主摄像头车厢间隔坐标信息 int iStatus = TRAINSTATUS_RUN; int iTagTotalCnt = 0; for (auto iter = mapUseDataSouceCfg_.begin(); iter != mapUseDataSouceCfg_.end(); iter++) { int iSourceId = iter->first; char szCameraNo[5] = {0}; sprintf(szCameraNo, "%03d/", iSourceId + 1); bool bIsEndFlag = (pTrainRange->iEndFrameId == iFrameId); // LogInfo << "sourceid:" << iSourceId << " StepTwo MakeProcessData trainIndex:" << pTrainRange->iTrainIndex // << " iFrameId:" << iFrameId << " bIsEndFlag:" << bIsEndFlag; std::string strImgName = strDataDir + szCameraNo + std::to_string(iFrameId); strImgName += (iter->second.iRotate != 0) ? "_rotate.jpg" : ".jpg"; std::string strFileName = strDataDir + szCameraNo + std::to_string(iFrameId) + ".txt"; // 获取大框信息 Json::Value jvFrameInfo; bool bReadFlag = MyUtils::getins()->ReadJsonInfo(jvFrameInfo, strFileName, 0); if (!bIsEndFlag && !bReadFlag) { //非车厢结束帧且没有txt信息时不处理。 continue; } iStatus = (iSourceId == 0 ? jvFrameInfo["status"].asInt() : iStatus); // 构造处理数据信息 std::shared_ptr pProcessData = std::make_shared(); pProcessData->iDataSource = iSourceId; pProcessData->iFrameId = iFrameId; pProcessData->strTrainDate = pTrainRange->strTrainDate; pProcessData->strTrainName = pTrainRange->strTrainName; pProcessData->bIsEnd = bIsEndFlag; pProcessData->iStatus = iStatus; pProcessData->iDirection = iDirection_; pProcessData->iDataNO = iDataNO; pProcessData->iTrainIndex = pTrainRange->iTrainIndex; pProcessData->bIsTrainEnd = pTrainRange->bIsEnd; pProcessData->strPicFilePath = strImgName; pProcessData->i64TimeStamp = jvFrameInfo["timeStamp"].asUInt64(); pProcessData->iWidth = jvFrameInfo["width"].asInt(); pProcessData->iHeight = jvFrameInfo["height"].asInt(); Json::Value jvOneSplit; jvOneSplit = jvMainSplit; jvOneSplit["rotate"] = iter->second.iRotate; GetValidTypeAndSplit(jvOneSplit, jvMainSplit, pProcessData, jvFrameInfo, pTrainRange); // 获取有效的大框信息 int iRetCnt = GetPostData(pProcessData, jvFrameInfo, jvOneSplit); iTagTotalCnt += iRetCnt; if (iRetCnt > 0 && iStatus == TRAINSTATUS_RUN) { cv::Mat cvframe = cv::imread(pProcessData->strPicFilePath); int iBufferSize = pProcessData->iWidth * pProcessData->iHeight * 3; void *pBGRBufferobj = nullptr; pBGRBufferobj = new uint8_t[iBufferSize]; memcpy(pBGRBufferobj, cvframe.data, iBufferSize); pProcessData->pData.reset(pBGRBufferobj, [](void *data){if(data) {delete[] data; data = nullptr;}}); pProcessData->iSize = iBufferSize; } std::vector vecPushPorts = mapSourcePushPort_[iSourceId]; for (int iPort = 0; iPort < vecPushPorts.size(); iPort++) { if (iPort == vecPushPorts.size() - 1) { //iRet = outputQueMap_[vecPushPorts[iPort]]->push(std::static_pointer_cast(pProcessData), true); PushData(vecPushPorts[iPort], pProcessData); continue; } std::shared_ptr pNewProcessData = std::make_shared(); *pNewProcessData = *pProcessData; //iRet = outputQueMap_[vecPushPorts[iPort]]->push(std::static_pointer_cast(pNewProcessData), true); PushData(vecPushPorts[iPort], pNewProcessData); } } iDataNO++; //每组处理数据需间隔一定时间 (运行状态且有第一步结果需休眠,否则直接处理后面的数据) if (iStatus == TRAINSTATUS_RUN && iTagTotalCnt != 0) { usleep(iIntervalTime_); } while (g_bNoDealStepTwoFlag) { usleep(iIntervalTime_); } } } APP_ERROR DataDealTwoEngine::Process() { int iRet = APP_ERR_OK; while (!isStop_) { //获取主摄像头车厢划分结果 std::shared_ptr pVoidData0 = nullptr; iRet = inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); // 1ms continue; } std::shared_ptr pTrainRange = std::static_pointer_cast(pVoidData0); LogInfo << "step2 start traindate:" << pTrainRange->strTrainDate << " trainname:" << pTrainRange->strTrainName << " trainindex:" << pTrainRange->iTrainIndex << " startframeid:" << pTrainRange->iStartFrameId << " endframeid:" << pTrainRange->iEndFrameId << " isEnd:" << pTrainRange->bIsEnd; if (iDirection_ == DIRECTION_UNKNOWN) { /*获取该车辆行驶方向 特殊场景:车头行驶画面一半后停止,再次反方向驶出画面。再次行驶得场景不会有方向.(因没有大框无法计算方向) */ std::string strFilePath = strResultPath_ + pTrainRange->strTrainDate + "/" + pTrainRange->strTrainName + "/" + "direction.txt"; int iCnt = 0; while (!isStop_ && iCnt < 10) { Json::Value jvDirectionInfo; if (MyUtils::getins()->ReadJsonInfo(jvDirectionInfo, strFilePath)) { iDirection_ = jvDirectionInfo["direction"].asInt(); //按行驶方向获取车号在前还是属性在前 if (iDirectionAndFirst_ == DO_NOT_KNOW_DIRECTION && iDirection_ != DIRECTION_UNKNOWN) { iDirectionAndFirst_ = iDirection_ == DIRECTION_LEFT ? dataSourceConfig_.iLeftFirst : dataSourceConfig_.iRightFirst; } break; } usleep(500 * 1000); // 500ms iCnt++; } } /*重置开始帧,结束帧 开始帧向上取跳帧的倍数,结束帧向下取跳帧的倍数 例: 车厢开始帧结束帧[50, 125],则推理的开始帧结束帧为[52, 124] */ int iSkipInterval = dataSourceConfig_.iSkipInterval; pTrainRange->iStartFrameId = (pTrainRange->iStartFrameId + iSkipInterval - 1) / iSkipInterval * iSkipInterval; pTrainRange->iEndFrameId = pTrainRange->iEndFrameId / iSkipInterval * iSkipInterval; if (pTrainRange->iStartFrameId > pTrainRange->iEndFrameId) { pTrainRange->iStartFrameId = pTrainRange->iEndFrameId; } //判断第一步是否处理完毕 char szCameraNo[5] = {0}; sprintf(szCameraNo, "%03d/", engineId_ + 1); std::string strFilePath = strResultPath_ + pTrainRange->strTrainDate + "/" + pTrainRange->strTrainName + "/" + szCameraNo + std::to_string(pTrainRange->iEndFrameId) + ".txt"; int iReadCnt = 0; bool bRet = false; while (!isStop_ && iReadCnt < 30) { Json::Value jvFrameInfo; bRet = MyUtils::getins()->ReadJsonInfo(jvFrameInfo, strFilePath); if (jvFrameInfo["step1Finish"].asBool()) { break; } usleep(500 * 1000); // 500ms iReadCnt++; } //处理当车厢的每帧信息 MakeProcessData(pTrainRange); // push结果汇总 iRet = outputQueMap_[engineName_ + "_" + std::to_string(engineId_) + "_9"]->push(std::static_pointer_cast(pTrainRange)); iTrainIndex_++; if (pTrainRange->bIsEnd) { InitParam(); } } return APP_ERR_OK; }