#include "TrainAnaEngine.h" #define SHOW_RECTANGLE using namespace ai_matrix; unsigned int num=0; TrainAnaEngine::TrainAnaEngine() {} TrainAnaEngine::~TrainAnaEngine() {} APP_ERROR TrainAnaEngine::Init() { LogInfo << "TrainAnaEngine Init start"; // 初始化相机帧率 nFrameRate = FRAME_RATE; nRecIndex = 0; nPicAreaChangeing = 0x00; strPort0_ = engineName_ + "_" + std::to_string(engineId_) + "_0"; strPort1_ = engineName_ + "_" + std::to_string(engineId_) + "_1"; dataSourceConfig_ = MyYaml::GetIns()->GetDataSourceConfigById(engineId_); strResultPath_ = MyYaml::GetIns()->GetPathValue("gc_result_path"); strResultPath_for_test = MyYaml::GetIns()->GetPathValue("gc_result_path_for_test"); // 获取算法参数的文件路径 std::string strsettingpath = MyYaml::GetIns()->GetStringValue("method_setting"); // 读取算法参数的内容 getsetting(strsettingpath); // 获取动态检测参数的数量 int nMethodCount = lstAction.size(); // LogInfo << "TrainAnaEngine Init method list count:" << nMethodCount; if (nMethodCount > 2) { //计算变化值 nRightComeFlagR3 = 0x00000001 << (lstAction.size() - 3); nRightComeFlagR2 = 0x00000001 << (lstAction.size() - 2) + nRightComeFlagR3; nRightComeFlagR1 = 0x00000001 << (lstAction.size() - 1) + nRightComeFlagR2; // LogInfo << "TrainAnaEngine Init nRightComeFlagR3:" << nRightComeFlagR3; // LogInfo << "TrainAnaEngine Init nRightComeFlagR2:" << nRightComeFlagR2; // LogInfo << "TrainAnaEngine Init nRightComeFlagR1:" << nRightComeFlagR1; } // 获取尾部车钩的偏移量 nTailPixOffset = getTailPixOffset(); // LogInfo << "TrainAnaEngine Init nTailPixOffset:" << nTailPixOffset; //初始化来车检测状态 nStatus=TRAIN_INIT_STATUS; // 初始化引擎相关的参数 vResetPartion(); LogInfo << "TrainAnaEngine Init ok"; return APP_ERR_OK; } APP_ERROR TrainAnaEngine::DeInit() { LogInfo << "TrainAnaEngine DeInit ok"; return APP_ERR_OK; } /** * 参数初始化(列车结束时需调用) * inParam : N/A * outParam: N/A * return : N/A */ void TrainAnaEngine::InitParam() { LogInfo << "TrainAnaEngine InitParam start"; strTrainData_ = ""; strTrainName_ = ""; LogInfo << "TrainAnaEngine InitParam end"; } /** * 初始化车厢分割信息 * inParam : N/A * outParam: N/A * return : N/A */ void TrainAnaEngine::vResetPartion() { LogInfo << "TrainAnaEngine vResetPartion start"; InitParam(); // //行车状态为初始化 // nStatus = TRAIN_INIT_STATUS; // nPreStatus = TRAIN_INIT_STATUS; //设定检测动态区域均为未发生变化 nPicAreaChangeing = 0x00; nPrePicAreaChangeing = 0x00; //清空车厢划分列表 lstPartInfo.clear(); //初始化开始帧 nLatestFrame = 0; // 根据帧率计算检测到车钩以后忽略检测的帧数 // 1.默认车辆3.9秒通过 // 2.默认车体长度 14.5(TRAIN_WIDTH) // 3.单位:米/秒 fdefaultspeed = (TRAIN_WIDTH / 3.9); // 车体的三分之一作为忽略标准 // 车体三分之一的通过时间 float fpasstime = (TRAIN_WIDTH / 3.0) / fdefaultspeed; // 忽略帧数:时间*帧率 nSamePartionIgnoreCount = fpasstime * nFrameRate; nPartionPassFrameCount = 0; LogInfo << "TrainAnaEngine vResetPartion start"; } /** * 格式化算分配置文件内容 * inParam : 单个算法配置分割后的字符信息 * outParam: 结构化的算法配置信息 * return : N/A */ void TrainAnaEngine::vformatStructAnalyseInfo(std::vector elems, AnalyseInfo &info) { LogInfo << "TrainAnaEngine vformatStructAnalyseInfo start"; //以下内容为文件读取的结果 //算法类型 1动态检测 2车厢划分 info.nType = -1; //检测敏感区域开始位置的X值 info.nAreaX1 = -1; //检测敏感区域开始位置的Y值 info.nAreaY1 = -1; //检测敏感区域结束位置的X值 info.nAreaX2 = -1; //检测敏感区域结束位置的Y值 info.nAreaY2 = -1; //算法结果等级相同做AND处理,不同做OR处理 info.bOrLevel = -1; //是否以不同作为判断结果 info.bDiff = false; //算法是否有效 1有效 0无效 info.bOn = false; //判断相同的阈值 info.dSameThresholdVal = 0.0; //判断不同的阈值 info.dDiffThresholdVal = 0.0; //判断停车的累计帧数阈值 info.nPauseMaxCoumt = 0; //图像增强的算法(位运算) //0x01 灰度化 //0x02 直方图均衡化 //0x04 自定义 info.npicimprovetype = -1; //OPENCV模板对比算法 info.templemethod = -1; //直方图对比算法 info.histmethod = -1; //自定义算法 info.specmethod = -1; //图像比对的方法(位运算) //0x01 OPENCV模板对比 //0x02 直方图对比 //0x04 自定义 info.compmethod = -1; //对比的基准图的路径 info.baseImagePath = ""; //以下内容为初始化结果 //图像对比数值 info.dComparePoint = 0.0; //上一帧对比数值 info.dPreComparePoint = 0.0; //图像与基础状态是否发生变化 info.bChanged = 0.0; //上一帧图像与基础状态是否发生变化 info.bPreChanged = 0.0; //图像变化后(保持在一个平衡状态即值不变的状态)累计值 info.nSameCount = 0; char *chrevptr; if (elems.size() == IMAGEANALYSE_NUM) { info.nType = atoi(elems[0].c_str()); info.nAreaX1 = atoi(elems[1].c_str()); info.nAreaY1 = atoi(elems[2].c_str()); info.nAreaX2 = atoi(elems[3].c_str()); info.nAreaY2 = atoi(elems[4].c_str()); info.bOrLevel = atoi(elems[5].c_str()); info.bDiff = (atoi(elems[6].c_str()) == 1) ? true : false; info.bOn = (atoi(elems[7].c_str()) == 1) ? true : false; info.dSameThresholdVal = strtod(elems[8].c_str(), &chrevptr); info.dDiffThresholdVal = strtod(elems[9].c_str(), &chrevptr); info.nPauseMaxCoumt = atoi(elems[10].c_str()); info.npicimprovetype = atoi(elems[11].c_str()); info.templemethod = atoi(elems[12].c_str()); info.histmethod = atoi(elems[13].c_str()); info.specmethod = atoi(elems[14].c_str()); info.compmethod = atoi(elems[15].c_str()); info.baseImagePath = elems[16]; } LogInfo << "TrainAnaEngine vformatStructAnalyseInfo end"; } /** * 获取图像比对的结果值 * inParam : 算法配置信息 * inParam : 当前图像的Mat值 * inParam : 比对基础图像的Mat值 * outParam: N/A * return : 比对值的数组 */ std::vector TrainAnaEngine::getCompPoint(AnalyseInfo info, cv::Mat baseimg, cv::Mat tarpic) { LogInfo << "TrainAnaEngine getCompPoint start"; std::vector dRetVal; cv::Point cvOutPoint; LogInfo << "TrainAnaEngine getCompPoint info.compmethod:" << info.compmethod; if ((info.compmethod & IMAGE_COMP_BY_SPEC) == IMAGE_COMP_BY_SPEC) { double dHistPoint = anapicbySpec(baseimg); dRetVal.push_back(dHistPoint); } //OPENCV模型比对方法 if ((info.compmethod & IMAGE_COMP_BY_TEMPLE) == IMAGE_COMP_BY_TEMPLE) { double dtemplePoint = anapicbyTemple(baseimg, tarpic, info.templemethod, cvOutPoint); dRetVal.push_back(dtemplePoint); } //直方图比对方法 if ((info.compmethod & IMAGE_COMP_BY_HIST) == IMAGE_COMP_BY_HIST) { double dHistPoint = anapicbyHist(baseimg, tarpic, info.histmethod); dRetVal.push_back(dHistPoint); } LogInfo << "TrainAnaEngine getCompPoint end:" << dRetVal[0]; return dRetVal; } /** * 获取算法配置文件的内容 * inParam : 算法配置文件路径 * outParam: N/A * return : N/A */ void TrainAnaEngine::getsetting(string strFilePath) { //LogInfo << "TrainAnaEngine getsetting start"; std::string strLineInfo; std::ifstream finfile(strFilePath); int nindex = 0; //按行读取 while (std::getline(finfile, strLineInfo)) { //LogInfo << "TrainAnaEngine getsetting nindex:" << nindex; //首行作为注释不读取 if (nindex == 0) { nindex++; continue; } nindex++; std::vector elems; //每行以逗号, 作为分隔符 elems = MyUtils::getins()->split(strLineInfo, ","); AnalyseInfo strTempInfo; //根据逗号分割的列表数据 初始化算法配置信息 vformatStructAnalyseInfo(elems, strTempInfo); //LogInfo << "TrainAnaEngine getsetting strTempInfo.nType :" << strTempInfo.nType ; //保存动态检测的算法到集合中 if (strTempInfo.nType == TRAIN_ACTION) { lstAction.push_back(strTempInfo); } //保存车厢划分的算法到集合中 else if(strTempInfo.nType == TRAIN_PARTION) { lstPartion.push_back(strTempInfo); } } //LogInfo << "TrainAnaEngine getsetting end"; } /** * 根据直方图做比对 * inParam : 当前图像的Mat值 * inParam : 比对基础图像的Mat值 * inParam : 比对算法 * outParam: N/A * return : 比对值 */ double TrainAnaEngine::anapicbySpec(cv::Mat baseimg) { LogInfo << "TrainAnaEngine anapicbySpec start"; double match = 0.0; int nmean = 0; Mat tmp_m, tmp_sd; cv::Mat mtTempImage = mtresizeImage(baseimg, (int)(baseimg.cols / 4), (int)(baseimg.rows / 4)); cv::Mat mtOutImage; cv::meanStdDev(mtTempImage, tmp_m, tmp_sd); nmean = (int)tmp_m.at(0,0); int nwidth = mtTempImage.cols; int nHeight = mtTempImage.rows; std::vector elems; int nmax = 0; int nmin = 0; for(int i = 0;i < nHeight;i++) { int ncheckval = 0; for(int j = 0; j < nwidth;j++) { ncheckval = ncheckval + mtTempImage.at(i,j); } ncheckval = (int)(ncheckval / nwidth) - nmean; if(ncheckval > nmax){ nmax = ncheckval; } if(ncheckval < nmin){ nmin = ncheckval; } elems.push_back(ncheckval); } int nstartindex = 6; int nendindex = 24; int nblackcount = 0; for(int i = nstartindex + 1;i < nendindex;i++) { if(elems[i] < 0 && elems[i - 1] < 0){ nblackcount++; } else { //nblackcount = 0; } } LogInfo << "TrainAnaEngine anapicbySpec nblackcount:" << nblackcount; if (nblackcount > ((nendindex - nstartindex) / 2)) { for(int i = 0;i < nHeight;i++) { elems[i] = 0 - elems[i]; } } int nfirstpot = -1; int nsecondpot = -1; int nthirdpot = -1; int nfirstpotsum = 0; int nsecondpotsum = 0; int nthirdpotsum = 0; int npremax = 0; int npremin = 0; int nfirstmax = 0; int nfirstmin = 0; int nsecondmax = 0; int nsecondmin = 0; for(int i = 2; i < nHeight; i++) { LogInfo << "TrainAnaEngine elems[i] :" << elems[i]; if (elems[i -2] < elems[i - 1] && elems[i - 1] < elems[i] && nfirstpot == -1 && elems[i] > 0) { nfirstpot = i; } if (nfirstpot == -1) { if(npremax < elems[i]){ npremax = elems[i]; } if(npremin > elems[i]){ npremin = elems[i]; } continue; } if (elems[i -2] > elems[i - 1] && elems[i - 1] > elems[i] && nsecondpot == -1 && elems[i] < 0) { nsecondpot = i; } if (nsecondpot == -1 && elems[i] > 0) { nfirstpotsum++; if(nfirstmax < elems[i]){ nfirstmax = elems[i]; } if(nfirstmin > elems[i]){ nfirstmin = elems[i]; } } if (nsecondpot == -1) { continue; } if (nthirdpot == -1 && elems[i] < 0) { nsecondpotsum++; if(nsecondmax < elems[i]){ nsecondmax = elems[i]; } if(nsecondmin > elems[i]){ nsecondmin = elems[i]; } } if (elems[i -2] < elems[i - 1] && elems[i - 1] < elems[i] && nthirdpot == -1 && elems[i] > 0) { nthirdpot = i; } if (nthirdpot != -1) { nthirdpotsum++; } } LogInfo << "TrainAnaEngine nHeight :" << nHeight; LogInfo << "TrainAnaEngine nfirstpot :" << nfirstpot; LogInfo << "TrainAnaEngine nsecondpot :" << nsecondpot; LogInfo << "TrainAnaEngine nthirdpot :" << nthirdpot; LogInfo << "TrainAnaEngine nmax :" << nmax; LogInfo << "TrainAnaEngine nmin :" << nmin; LogInfo << "TrainAnaEngine npremin :" << npremin; LogInfo << "TrainAnaEngine npremax :" << npremax; LogInfo << "TrainAnaEngine nfirstmax :" << nfirstmax; LogInfo << "TrainAnaEngine nfirstmin :" << nfirstmin; LogInfo << "TrainAnaEngine nsecondmax :" << nsecondmax; LogInfo << "TrainAnaEngine nsecondmin :" << nsecondmin; if ( (nfirstpot < (int)(nHeight / 3)) && (nsecondpot > (int)(nHeight / 2)) && (nsecondpot < (int)(nHeight *2 / 3)) && (nthirdpot > (int)(nHeight * 3/ 4)) && (npremin < 0) && (nfirstmax > 0) && (nsecondmin < 0) //&& (nfirstpotsum > (nsecondpot - nfirstpot - 2)) //&& (nsecondpotsum > (nthirdpot - nsecondpot - 2)) //&& (nthirdpotsum >= (nHeight - nthirdpot - 1)) //&& (nmax- nfirstmax > nmax/2) //&& (nsecondmin < nmin/2) ){ match = 1.0; double firstsinoffset = 180.0/nfirstpot; double secondsinoffset = 180.0/(nsecondpot - nfirstpot); double thirdsinoffset = 180.0/(nthirdpot - nsecondpot); double dbaseoffset = 1.0 / (nHeight * 1.0); double dmaxoffset = (nmax-nmin) * 1.0 ; LogInfo << "TrainAnaEngine firstsinoffset :" << firstsinoffset; LogInfo << "TrainAnaEngine secondsinoffset :" << secondsinoffset; LogInfo << "TrainAnaEngine thirdsinoffset :" << thirdsinoffset; LogInfo << "TrainAnaEngine dbaseoffset :" << dbaseoffset; LogInfo << "TrainAnaEngine dmaxoffset :" << dmaxoffset; double dtmp = 0.0; for (int i = 0; i < nHeight; i++) { if (i < nfirstpot){ dtmp = dbaseoffset * abs(elems[i] - sin((i)*firstsinoffset)*(npremin* 1.0))/ dmaxoffset; } else if(i>= nfirstpot && i < nsecondpot){ dtmp = dbaseoffset * abs(elems[i] - sin((i - nfirstpot)*secondsinoffset)*(nfirstmax * 1.0)) / dmaxoffset; } else if(i>= nsecondpot && i < nthirdpotsum){ dtmp = dbaseoffset * abs(elems[i] - sin((i - nsecondpot)*thirdsinoffset)*(nsecondmin * 1.0)) / dmaxoffset; } else if(i >= nthirdpotsum){ dtmp = 0.0; } LogInfo << "TrainAnaEngine befor match :" << match; LogInfo << "TrainAnaEngine dtmp :" << dtmp; match = match - dtmp; LogInfo << "TrainAnaEngine after match :" << match; } //match = 1.0; } if (strResultPath_for_test != "") { std::ostringstream ossfloat,ossint; ossfloat<<(int)(match * 1000); ossint< imagedata; imagefile >> std::noskipws; std::copy(std::istream_iterator(imagefile), std::istream_iterator(), std::back_inserter(imagedata)); cv::Mat jpegimage = cv::imdecode(Mat(imagedata), cv::IMREAD_COLOR); imagefile.close(); LogInfo << "TrainAnaEngine mtdecodeImageDatabyFile end"; return jpegimage; } /** * 将图像二进制数据转化为Mat值 * inParam : 二进制数据指针 * inParam : 二进制数据长度 * outParam: N/A * return : 图像Mat值 */ cv::Mat TrainAnaEngine::mtdecodeImageDatabyBin(LPVOID lpimgdata, int imglen) { LogInfo << "TrainAnaEngine mtdecodeImageDatabyBin start"; //LogInfo << "TrainAnaEngine mtdecodeImageDatabyBin imglen:" << imglen; const char *buffer = static_cast(lpimgdata); vector::size_type size = imglen; std::vector imagedata(buffer, buffer + size); cv::Mat jpegimage = imdecode(imagedata, cv::IMREAD_COLOR); LogInfo << "TrainAnaEngine mtdecodeImageDatabyBin end"; return jpegimage; } /** * 图像增强 * inParam : 原始图片的Mat值 * inParam : 算法配置信息 * outParam: N/A * return : 图像Mat值 */ cv::Mat TrainAnaEngine::mtImproveImage(cv::Mat inImage, AnalyseInfo info, bool bcvread) { LogInfo << "TrainAnaEngine mtImproveImage start"; cv::Mat mtOutImage = inImage; //cv::Mat mtOutImage; int x1 = info.nAreaX1; int y1 = info.nAreaY1; int width = info.nAreaX2 - info.nAreaX1; int height = info.nAreaY2 - info.nAreaY1; int type = info.nType; int mode = (bcvread == false) ? cv::COLOR_YUV2GRAY_420 : cv::COLOR_RGB2GRAY; //LogInfo << "TrainAnaEngine mtImproveImage x1:"<(i, j) = 6*pow((double)inImage.at(i, j), fgamma); } } cv::normalize(mtTempImage, mtTempImage, 0, 255, NORM_MINMAX); cv::convertScaleAbs(mtTempImage, mtOutImage); LogInfo << "TrainAnaEngine mtGammaImage end"; return mtOutImage; } /** * 图像进行自定义处理 * inParam : 原始图片的Mat值 * outParam: N/A * return : 图像Mat值 */ cv::Mat TrainAnaEngine::mtspecImage(cv::Mat inImage) { LogInfo << "TrainAnaEngine mtspecImage start"; cv::Mat mtTempImage = inImage; cv::Mat mtOutImage; //中值滤波,降采样 cv::medianBlur(inImage,mtTempImage,3); cv::resize(mtTempImage, mtOutImage, Size((int)(mtTempImage.rows*0.5),(int)(mtTempImage.cols*0.5) ), INTER_LINEAR); LogInfo << "TrainAnaEngine mtspecImage end"; return mtOutImage; } /* * 获取最近100帧的dComparePoint的最大值与最小值之差 * inParam : 第i个方框的dComparePoint值 * inParam : 第i个框的索引 * outParam: N/A * return : N/A */ float TrainAnaEngine::GetPointMaxReduceMin(float dComparePoint,int index){ static float array[20] ={0.0}; switch (index) { case 0: static int num_count1=0; static float array1[20] ={0.0}; array1[num_count1]=dComparePoint; num_count1++; if (num_count1>19){ num_count1=0; } for(int i=0;i<=19;i++){ array[i]=array1[i]; } break; case 1: static int num_count2=0; static float array2[20] ={0.0}; array2[num_count2]=dComparePoint; num_count2++; if (num_count2>19){ num_count2=0; } for(int i=0;i<=19;i++){ array[i]=array2[i]; } break; case 2: static int num_count3=0; static float array3[20] ={0.0}; array3[num_count3]=dComparePoint; num_count3++; if (num_count3>19){ num_count3=0; } for(int i=0;i<=19;i++){ array[i]=array3[i]; } break; } sort(array,array+20); return (array[19]-array[0]); } /** * 来车动态检测 * inParam : 原始图片的Mat值 * inParam : 原始图片的时间戳 * outParam: N/A * return : N/A */ void TrainAnaEngine::checkAction(cv::Mat baseimg, uint64_t i64TimeStamp) { #ifdef SHOW_RECTANGLE cv::Mat img=baseimg.clone(); cv::Scalar sca(0,0,255); #endif //count[5]记录选择区域的状态为来车所保持的帧数,当帧数大于5时,改变选择区域的状态为来车 static int count[5]={0}; LogInfo << "TrainAnaEngine checkAction start"; // 记录上一帧的行车状态 nPreStatus = nStatus; // 记录上一帧的动态变化情况 nPrePicAreaChangeing = nPicAreaChangeing; // 初始化当前帧的动态变化情况 nPicAreaChangeing = 0x00; // 检测区域数量 int nlistlen = lstAction.size(); //LogInfo << "TrainAnaEngine checkAction nlistlen:" << nlistlen; //LogInfo << "TrainAnaEngine checkAction i64TimeStamp:" << i64TimeStamp; for (int i = 0; i < nlistlen; i++) { // 根据检测区域切分当前帧 cv::Mat cvImg1 = mtareaImage(baseimg, lstAction[i].nAreaX1, lstAction[i].nAreaY1, lstAction[i].nAreaX2, lstAction[i].nAreaY2); cvImg1 = mtImproveImage(cvImg1, lstAction[i], false); // 根据检测区域切分基础帧 cv::Mat cvImg2 = mtareaImage(cvFirstImg, lstAction[i].nAreaX1+5, lstAction[i].nAreaY1+5, lstAction[i].nAreaX2-5, lstAction[i].nAreaY2-5); cvImg2 = mtImproveImage(cvImg2, lstAction[i], false); // 获取比对数值 std::vector lstRet = getCompPoint(lstAction[i], cvImg1, cvImg2); // 记录上一帧比对数值 lstAction[i].dPreComparePoint = lstAction[i].dComparePoint; // 记录当前帧比对数值 lstAction[i].dComparePoint = lstRet[0]; //LogInfo << "TrainAnaEngine checkAction i:" << i; //LogInfo << "TrainAnaEngine checkAction nlistlen:" << nlistlen; //LogInfo << "TrainAnaEngine checkAction nStatus:" << nStatus; //LogInfo << "TrainAnaEngine checkAction lstAction[i].dComparePoint:" << lstAction[i].dComparePoint; //LogInfo << "TrainAnaEngine checkAction lstAction[i].dSameThresholdVal:" << lstAction[i].dSameThresholdVal; #ifdef SHOW_RECTANGLE //方框的位置 cv::Rect rect(lstAction[i].nAreaX1,lstAction[i].nAreaY1,(lstAction[i].nAreaX2-lstAction[i].nAreaX1),(lstAction[i].nAreaY2-lstAction[i].nAreaY1)); //point1当前的方框状态显示的位置 cv::Point point(lstAction[i].nAreaX1,lstAction[i].nAreaY1-90); //point2时当前的方框相似度的值显示的位置 cv::Point point2(lstAction[i].nAreaX1,lstAction[i].nAreaY1-60); //point2时当前的方框累加的值显示的位置 cv::Point point3(lstAction[i].nAreaX1,lstAction[i].nAreaY1-30); cv::rectangle(img,rect,sca,3); #endif // 比对数值小于设定的阈值则判断检测区域发生变化 if (lstAction[i].dComparePoint < lstAction[i].dSameThresholdVal){ //LogInfo << "TrainAnaEngine checkAction start nPicAreaChangeing:" << nPicAreaChangeing; // 设定状态 当前区域存在变化 count[i]++; if(count[i]>=5){ // nPicAreaChangeing += 0x00000001 << i; lstAction[i].bChanged = true; if(count[i]>10) count[i]=10; } //LogInfo << "TrainAnaEngine checkAction end nPicAreaChangeing:" << nPicAreaChangeing; }else{ count[i]--; if(count[i]<=0){ count[i]=0; //nPicAreaChangeing =(nPicAreaChangeing&(~(0x00000001< 检测有车 if (nStatus == TRAIN_INIT_STATUS){ //LogInfo << "TrainAnaEngine checkAction TRAIN_INIT_STATUS start"; // 动态检测区域状态是否发生变化 true 发生 false 未发生 bool bStatuschanged = false; //根据方框的编号以及对应的状态判断当前来车的方向以及有无来车 //0对应左侧方框一,1对应中间方框 if((lstAction[0].bChanged&&lstAction[1].bChanged&&(!lstAction[2].bChanged))||(lstAction[0].bChanged&(!lstAction[1].bChanged)&lstAction[2].bChanged)){ nStatus = TRAIN_RIGHT_RUN; bStatuschanged = true; }else if(lstAction[1].bChanged&&lstAction[2].bChanged&&(!lstAction[0].bChanged)){ nStatus = TRAIN_LEFT_RUN; bStatuschanged = true; } // }else if(lstAction[0].bChanged&&lstAction[1].bChanged&&lstAction[2].bChanged){ // nStatus = TRAIN_RIGHT_RUN; // bStatuschanged = true; // } // 状态发生变化 if (bStatuschanged == true) { // 开始记录车厢划分信息/添加一节车厢划分信息 PartionInfo stTempInfo; stTempInfo.nindex = 1; stTempInfo.startframe = 1; stTempInfo.i64StartTimeStamp = i64TimeStamp; lstPartInfo.push_back(stTempInfo); } //基础帧替换的第一种情况。 //用于计算高校相似度保持的帧数,当帧数保持10帧以上则进行帧替换 static int count_num=0; bool bEmpty1=true; for (int i = 0; i < nlistlen; i++) { bEmpty1=bEmpty1&&(lstAction[i].dPreComparePoint>=0.95); } if (bEmpty1){ count_num++; if(count_num>=10) { // 没有发生变化,则将该帧作为基础帧 cvFirstImg = baseimg; count_num=0; } }else{ count_num=0; } //基础帧替换的第二种情况,过车后引起的相似度下降,需要最近100帧相似度波动小于0.03 bool bEmpty2=true; static int count_num2=0; for (int i = 0; i < nlistlen; i++) { bEmpty2=bEmpty2&&(!lstAction[i].bChanged); bEmpty2=bEmpty2&&(lstAction[i].fluctuationFlag); } if(bEmpty2){ count_num2++; if(count_num2>100){ cvFirstImg = baseimg; count_num2=0; } }else{ count_num2=0; } #ifdef SHOW_RECTANGLE LogInfo<<"current img id "<=2 )&& noFluctuationFlag); bpassed=(bpassed && noFluctuationFlag); //计算累计帧数 static unsigned short int count1=0; static unsigned short int count2=0; // 状态 有车 -> 停车 if (bpaused == true) { count1++; if(count1>50){ nStatus = TRAIN_PAUSE; count1=0; count2=0; } }else{ count1=0; } // 状态 有车 -> 完全通过 if (bpassed == true) { count2++; if(count2>50){ nStatus = TRAIN_PASSED; count1=0; count2=0; } }else{ count2=0; } #ifdef SHOW_RECTANGLE LogInfo<<"current img id "<=2 )&& noFluctuationFlag); bpassed=(bpassed && noFluctuationFlag); //计算累计帧数 static unsigned short int count1=0; static unsigned short int count2=0; // 状态 有车 -> 停车 if (bpaused == true) { count1++; if(count1>50){ nStatus = TRAIN_PAUSE; count1=0; count2=0; } }else{ count1=0; } // 状态 有车 -> 完全通过 if (bpassed == true) { count2++; if(count2>50){ nStatus = TRAIN_PASSED; count1=0; count2=0; } }else{ count2=0; } #ifdef SHOW_RECTANGLE LogInfo<<"current img id "<=2 )&& noFluctuationFlag); bpassed=(bpassed && noFluctuationFlag); //计算累计帧数 static unsigned short int count1=0; static unsigned short int count2=0; // 状态 有车 -> 停车 if (bpaused == true) { count1++; if(count1>50){ nStatus = TRAIN_PAUSE; count1=0; count2=0; } }else{ count1=0; } // 状态 有车 -> 完全通过 if (bpassed == true) { count2++; if(count2>50){ nStatus = TRAIN_PASSED; count1=0; count2=0; } }else{ count2=0; } #ifdef SHOW_RECTANGLE LogInfo<<"current img id "<20){ nStatus=TRAIN_RESTART; count=0; } count++; } #ifdef SHOW_RECTANGLE LogInfo<<"current img id "< lstRet = getCompPoint(lstPartion[i], cvImg1, cvImg2); lstPartion[i].dComparePoint = lstRet[0]; //LogInfo << "TrainAnaEngine checkPartion lstPartion[i].dComparePoint:" << lstPartion[i].dComparePoint; // 获取是相同还是不同作为判断标准 bool bCurrentRet = (lstPartion[i].bDiff == true) ? lstPartion[i].dComparePoint < lstPartion[i].dDiffThresholdVal : lstPartion[i].dComparePoint > lstPartion[i].dSameThresholdVal; // 对比等级不同 进行判断结果OR处理 if (lstPartion[i].bOrLevel != nPreOrLevel) { //LogInfo << "TrainAnaEngine checkPartion lstPartion[i].bOrLevel != nPreOrLevel"; bPartion = bPartion || bCurrentRet; } // 比对等级相同 进行判断结果AND处理 else { //LogInfo << "TrainAnaEngine checkPartion lstPartion[i].bOrLevel == nPreOrLevel"; bPartion = bPartion && bCurrentRet; } // 判断结果存在false的情况 直接停止判断确定没有车厢划分信息 if (bPartion == false) { //LogInfo << "TrainAnaEngine checkPartion bPartion == false"; break; } } // 存在车厢划分信息 if (bPartion == true) { //LogInfo << "TrainAnaEngine checkPartion bPartion == true for end"; // nPartionPassFrameCount = 0; // 获取最新的车厢节数 int nPrePartionIndex = lstPartInfo.size() - 1; // 获取时间戳 lstPartInfo[nPrePartionIndex].i64EndTimeStamp = i64TimeStamp; // 根据开始帧时间戳和结束帧时间错 计算当节车厢的行车速度 //LogInfo << "TrainAnaEngine checkPartion bPartion == true lstPartInfo[nPrePartionIndex].ftime:" << abs(lstPartInfo[nPrePartionIndex].i64EndTimeStamp - lstPartInfo[nPrePartionIndex].i64StartTimeStamp); // 根据时间戳计算时间差 float nTimePassed = (abs(lstPartInfo[nPrePartionIndex].i64EndTimeStamp - lstPartInfo[nPrePartionIndex].i64StartTimeStamp)) * 1.0; lstPartInfo[nPrePartionIndex].fspeed = (TRAIN_WIDTH * 1000.0) /nTimePassed; // //nSamePartionIgnoreCount = (nTimePassed / (3 * 5000)) * nFrameRate; // 结束帧为当前帧再往后 (除以2的原因:中间为车钩,车钩后的车体宽度为整个镜头的宽度除以2) lstPartInfo[nPrePartionIndex].endframe = nLatestFrame + getOffsetFrame(lstPartInfo[nPrePartionIndex].fspeed, (TRAIN_IN_CAMERA_WIDTH / 2), nFrameRate); //LogInfo << "TrainAnaEngine checkPartion bPartion == true lstPartInfo[nPrePartionIndex].endframe" << lstPartInfo[nPrePartionIndex].endframe; lstPartInfo[nPrePartionIndex].bfuncconfirmed = true; //LogInfo << "TrainAnaEngine checkPartion bPartion == true lstPartInfo[nPrePartionIndex].i64EndTimeStamp:" << lstPartInfo[nPrePartionIndex].i64EndTimeStamp; //LogInfo << "TrainAnaEngine checkPartion bPartion == true lstPartInfo[nPrePartionIndex].i64StartTimeStamp:" << lstPartInfo[nPrePartionIndex].i64StartTimeStamp; // 如果时间戳相同则不是划分信息 if (lstPartInfo[nPrePartionIndex].i64EndTimeStamp == lstPartInfo[nPrePartionIndex].i64StartTimeStamp) { bPartion = false; return bPartion; } //LogInfo << "TrainAnaEngine checkPartion nPrePartionIndex" << nPrePartionIndex; //LogInfo << "TrainAnaEngine checkPartion lstPartInfo[nPrePartionIndex].i64EndTimeStamp" << lstPartInfo[nPrePartionIndex].i64EndTimeStamp; //LogInfo << "TrainAnaEngine checkPartion lstPartInfo[nPrePartionIndex].nLatestFrame" << nLatestFrame; //LogInfo << "TrainAnaEngine checkPartion lstPartInfo[nPrePartionIndex].fspeed:" << lstPartInfo[nPrePartionIndex].fspeed; //LogInfo << "TrainAnaEngine checkPartion lstPartInfo[nPrePartionIndex].endframe" << lstPartInfo[nPrePartionIndex].endframe; //LogInfo << "TrainAnaEngine checkPartion bPartion == true lstPartInfo[nPrePartionIndex].fspeed:" << lstPartInfo[nPrePartionIndex].fspeed; } LogInfo << "TrainAnaEngine checkPartion end"; return bPartion; } /** * 计算车钩从中间到边缘的间隔帧 * inParam : 行车速度(单位:米/秒) * inParam : 宽度 * inParam : 相机帧率(单位:帧/秒) * outParam: N/A * return : 间隔帧 */ int TrainAnaEngine::getOffsetFrame(float fspeed, int width, int nFrameRate) { LogInfo << "TrainAnaEngine getOffsetFrame start"; //LogInfo << "TrainAnaEngine getOffsetFrame fspeed:" << fspeed; //LogInfo << "TrainAnaEngine getOffsetFrame width:" << width; //LogInfo << "TrainAnaEngine getOffsetFrame nFrameRate:" << nFrameRate; //LogInfo << "TrainAnaEngine getOffsetFrame nLatestFrame:" << nLatestFrame; //偏移值 = (中间到边缘的宽度(米) / 速度(米/秒)->时间(秒))* 帧率(帧/秒) float ftmp = width * (float) nFrameRate; //LogInfo << "TrainAnaEngine getOffsetFrame start end:" << ftmp; ftmp = ftmp / fspeed; //LogInfo << "TrainAnaEngine getOffsetFrame start end:" << ftmp; int nRet = (int) ftmp; LogInfo << "TrainAnaEngine getOffsetFrame start end:" << nRet; return nRet; } /** * 计算车钩移动的像素值 * inParam : 行车速度(单位:米/秒) * inParam : 宽度 * inParam : 相机帧率(单位:帧/秒) * outParam: N/A * return : 间隔帧 */ int TrainAnaEngine::getCouplerOffsetPosition(float fspeed, int nframeindex) { LogInfo << "TrainAnaEngine getCouplerOffsetPosition start"; //LogInfo << "TrainAnaEngine getCouplerOffsetPosition fspeed:" << fspeed; //LogInfo << "TrainAnaEngine getCouplerOffsetPosition start:" << nframeindex; //单位换算 // 米/秒 -> 米/帧 // 米/帧 = 米/秒 * 秒/帧(即:1/帧率) float fmeter_frame = fspeed / nFrameRate; //LogInfo << "TrainAnaEngine getCouplerOffsetPosition fmeter_frame:" << fmeter_frame; // 米/帧 -> 像素/帧 // 像素/帧 = 米/帧 * 像素/米 float fpix_frame = fmeter_frame * (METHOD_BASE_WIDTH / TRAIN_IN_CAMERA_WIDTH); //LogInfo << "TrainAnaEngine getCouplerOffsetPosition fpix_frame:" << fpix_frame; int nretPixOffet = (int)fpix_frame; nretPixOffet = nretPixOffet * nframeindex; //LogInfo << "TrainAnaEngine getCouplerOffsetPosition nretPixOffet:" << nretPixOffet; LogInfo << "TrainAnaEngine getCouplerOffsetPosition end"; return nretPixOffet; } int TrainAnaEngine::getTailPixOffset() { LogInfo << "TrainAnaEngine getTailPixOffset start"; // 单位计算 // 帧宽像素/米 float fframewidth_meter = ((METHOD_BASE_WIDTH * 1.0) / (TRAIN_IN_CAMERA_WIDTH)); //LogInfo << "TrainAnaEngine getTailPixOffset fframewidth_meter:" << fframewidth_meter; // 车尾车钩像素位置 float fOffsetPosistion = TRAIN_WIDTH * fframewidth_meter; //LogInfo << "TrainAnaEngine getTailPixOffset fOffsetPosistion:" << fOffsetPosistion; int nretOffset = (int)fOffsetPosistion; //LogInfo << "TrainAnaEngine getTailPixOffset nretOffset:" << nretOffset; //LogInfo << "TrainAnaEngine getTailPixOffset end"; return nretOffset; } APP_ERROR TrainAnaEngine::Process() { int iRet = APP_ERR_OK; //程序启动标志位 bool bInited = false; while (!isStop_) { std::shared_ptr pVoidData0 = nullptr; inputQueMap_[strPort0_]->pop(pVoidData0); if (nullptr == pVoidData0) { usleep(1000); //1ms continue; } LogInfo << "TrainAnaEngine Process start"; std::shared_ptr pDecodeData = std::static_pointer_cast(pVoidData0); std::shared_ptr pHostData = nullptr; //获取图像数据 cv::Mat matYUV(pDecodeData->iHeight * 3 / 2, pDecodeData->iWidth, CV_8UC1); int iCopySize = pDecodeData->iWidth * pDecodeData->iHeight * 3 / 2; memcpy(matYUV.data, pHostData.get(), iCopySize); // 将YUV格式灰度化之后修改图像尺寸 cv::Mat cvtemp; cv::cvtColor(matYUV, cvtemp, cv::COLOR_YUV2GRAY_420); //cv::imwrite("/home/HwHiAiUser/1.jpg",cvtemp); matYUV = mtresizeImage(cvtemp, METHOD_BASE_WIDTH, METHOD_BASE_HEIGHT); //来车 //cv::Mat baseimg = mtdecodeImageDatabyBin(lpimgdata, imglen); //cv::Mat baseimg = matYUV.data; //程序启动第一帧跳过 保存为基础图像 if (bInited == false) { cvFirstImg = matYUV; bInited = true; nFrameRate = pDecodeData->iRate; continue; } LogInfo << "TrainAnaEngine Process pDecodeData.i64TimeStamp:" << pDecodeData->i64TimeStamp; ncurtime = pDecodeData->i64TimeStamp; //来车状态检测 checkAction(matYUV, pDecodeData->i64TimeStamp); //判断是否有来车 pDecodeData->iStatus = (nStatus == TRAIN_LEFT_RUN || nStatus == TRAIN_RIGHT_RUN || nStatus == TRAIN_UNKOWN_RUN || nStatus == TRAIN_RESTART) ? 1 : ( nStatus == TRAIN_PAUSE)? 2 : 0; //判断来车方向 0 方向未知/无车 1右侧来车(向左行驶:模型识别用) 2左侧来车(向右行驶:模型识别用) pDecodeData->iDirection = ((nStatus == TRAIN_LEFT_RUN) ? 1 : ((nStatus == TRAIN_RIGHT_RUN) ? 2 : 0)); //列车是否通过 pDecodeData->bIsEnd = (nStatus == TRAIN_PASSED || nStatus == TRAIN_RESTART ) ? true : false; LogInfo << "TrainAnaEngine Process pDecodeData->iStatus:" << pDecodeData->iStatus; //LogInfo << "TrainAnaEngine Process pDecodeData->iDirection:" << pDecodeData->iDirection; //新过车创建文件夹 if ((nStatus != TRAIN_INIT_STATUS && nPreStatus == TRAIN_INIT_STATUS) || ( nPreStatus == TRAIN_RESTART && nStatus == TRAIN_UNKOWN_RUN)) { strTrainData_ = MyUtils::getins()->GetDate(); strTrainName_ = MyUtils::getins()->GetTime(); std::string strTrainPath = strResultPath_ + strTrainData_ + "/" + strTrainName_ + "/"; MyUtils::getins()->CreateDirPath(strTrainPath); } //过车日期 pDecodeData->strTrainDate = strTrainData_; //过车时间 pDecodeData->strTrainName = strTrainName_; // iRet = outputQueMap_[strPort0_]->push(std::static_pointer_cast(pDecodeData)); //当前帧是否有划分信息 bool bPartionExist = false; //有车的状态进行车厢划分检测 if (nStatus != TRAIN_INIT_STATUS){ //LogInfo << "TrainAnaEngine Process nPartionPassFrameCount:" << nPartionPassFrameCount; //LogInfo << "TrainAnaEngine Process nSamePartionIgnoreCount:" << nSamePartionIgnoreCount; //检测到划分状态的情况下 进行跳帧处理 //跳帧值为计算的车体通过三分之一之后的帧 if (nPartionPassFrameCount < nSamePartionIgnoreCount) { nPartionPassFrameCount++; } else { //超过跳帧进行车厢划分检测 bPartionExist = checkPartion(matYUV, pDecodeData->i64TimeStamp); //如果检测到车厢划分信息则检测跳帧的值 if (bPartionExist == true) { nPartionPassFrameCount = 0; } } } /// write json info to file //先读取文本内容,追加新的信息后再写入 //划分信息 JSON格式 Json::Value jvPartionInfo; //JSON保存路径 std::string strFilePath; //当然车厢通过的数量 int nPartionIndex = lstPartInfo.size() - 1; LogInfo << "TrainAnaEngine Process nPartionIndex:" << nPartionIndex; LogInfo << "TrainAnaEngine Process bPartionExist:" << bPartionExist; //检测到车厢划分信息 if ((bPartionExist == true)) { strFilePath = strResultPath_ + pDecodeData->strTrainDate + "/" + pDecodeData->strTrainName + "/" + std::to_string(nPartionIndex + 1) + ".txt"; // 记录过车日期 jvPartionInfo["trainDate"] = pDecodeData->strTrainDate; // 记录过车时间 jvPartionInfo["trainName"] = pDecodeData->strTrainName; // 记录车厢节数 (索引从0开始 所以这里+1) jvPartionInfo["trainNo"] = nPartionIndex + 1; // 记录行车开始帧 jvPartionInfo["startFrameId"] = lstPartInfo[nPartionIndex].startframe; // 记录行车结束帧 jvPartionInfo["endFrameId"] = lstPartInfo[nPartionIndex].endframe; // 记录车厢是否完全通过 jvPartionInfo["isEnd"] = pDecodeData->bIsEnd; // 首部车钩的偏移位置 (单位帧) int headpos = 0; // 尾部车钩的偏移位置 (单位帧) int tailpos = (0 - nTailPixOffset); if (nPartionIndex == 0) { headpos = METHOD_BASE_WIDTH / 2; tailpos = tailpos + headpos; } // 是否位右侧来车 bool brightcome = false; if (nStatus == TRAIN_RIGHT_RUN) { brightcome = true; // 右侧来车 首部车钩从画面最右侧开始 headpos = METHOD_BASE_WIDTH; // 右侧来车 尾部车钩从画面最右侧+车厢宽的像素值 tailpos = METHOD_BASE_WIDTH + nTailPixOffset; if (nPartionIndex == 0) { headpos = METHOD_BASE_WIDTH / 2; tailpos = tailpos - headpos; } } //LogInfo << "TrainAnaEngine Process lstPartInfo[nPartionIndex].startframe:" << lstPartInfo[nPartionIndex].startframe ; //LogInfo << "TrainAnaEngine Process lstPartInfo[nPartionIndex].endframe:" << lstPartInfo[nPartionIndex].endframe; //从当节车厢的开始帧到结束帧计算首部车钩和尾部车钩的偏移值 for (int nplayframe = lstPartInfo[nPartionIndex].startframe; nplayframe <= lstPartInfo[nPartionIndex].endframe; nplayframe++) { Json::Value jvposInfo; // 当前车厢的第几几帧 int noffsetindex = (nplayframe - lstPartInfo[nPartionIndex].startframe); // 根据车速计算车钩位置量(单位 像素) int noffsetpos = getCouplerOffsetPosition(lstPartInfo[nPartionIndex].fspeed, noffsetindex); // 初始化首部车钩偏移量(单位 像素) jvposInfo["headpos"] = -1; // 初始化尾部车钩偏移量(单位 像素) jvposInfo["tailpos"] = -1; if (brightcome == false) { // 左侧来车 // 首部车钩和尾部车钩 每帧加 车钩偏移值 jvposInfo["headpos"] = (headpos + noffsetpos); jvposInfo["tailpos"] = (tailpos + noffsetpos); } else { // 右侧来车 // 首部车钩和尾部车钩 每帧减 车钩偏移值 jvposInfo["headpos"] = (headpos - noffsetpos); jvposInfo["tailpos"] = (tailpos - noffsetpos); } //LogInfo << "TrainAnaEngine Process jvposInfo[headpos]" << jvposInfo["headpos"]; // LogInfo << "TrainAnaEngine Process jvposInfo[tailpos]:" << jvposInfo["tailpos"]; //LogInfo << "TrainAnaEngine Process jvPartionListInfo.append"; jvPartionInfo[std::to_string(nplayframe)] = jvposInfo; } PartionInfo stTempInfo; // 开始记录新的一节车厢信息(从索引变成序号+1 ,新增一节车厢信息+1) stTempInfo.nindex = nPartionIndex + 2; // 上一节车厢的结束帧 - (偏移帧 = (镜头内的车体宽度/ (速度) -> 通过时间) * 帧/秒 ) 作为下一节车厢的开始帧 int ntempOffsetFrame = lstPartInfo[nPartionIndex].endframe - (int)(((TRAIN_IN_CAMERA_WIDTH) / lstPartInfo[nPartionIndex].fspeed) * nFrameRate); //LogInfo << "TrainAnaEngine Process ntempOffsetFrame:" << ntempOffsetFrame; stTempInfo.startframe = (ntempOffsetFrame > nSamePartionIgnoreCount) ? ntempOffsetFrame : nSamePartionIgnoreCount; stTempInfo.i64StartTimeStamp = pDecodeData->i64TimeStamp; // 初始化下一节的结束帧 //stTempInfo.endframe = 0; lstPartInfo.push_back(stTempInfo); // 记录当前车厢的信息到JSON文件 //MyUtils::getins()->WriteJsonInfo(jvPartionInfo, strFilePath); std::shared_ptr pTrainRange = std::make_shared(); pTrainRange->strTrainDate = jvPartionInfo["trainDate"].asString(); pTrainRange->strTrainName = jvPartionInfo["trainName"].asString(); pTrainRange->iTrainIndex = jvPartionInfo["trainNo"].asInt(); pTrainRange->iStartFrameId = jvPartionInfo["startFrameId"].asInt(); pTrainRange->iEndFrameId = jvPartionInfo["endFrameId"].asInt(); pTrainRange->bIsEnd = jvPartionInfo["isEnd"].asBool(); //iRet = outputQueMap_[strPort1_]->push(std::static_pointer_cast(pTrainRange)); } // 有车的情况下。记录帧数:累加1 if (nStatus != TRAIN_INIT_STATUS) { nLatestFrame = nLatestFrame + 1; } //停车或无车(初始化相关参数) /* if ((nStatus == TRAIN_INIT_STATUS && (nStatus != TRAIN_INIT_STATUS)) || pDecodeData->bIsEnd) { vResetPartion(); } */ // 车厢通过初始化状态 if (pDecodeData->bIsEnd) { vResetPartion(); } LogError<<"current img id "<