Train_Identify_arm/nvidia_ascend_engine/common_engine/TrainAnaEngine/TrainAnaEngine.cpp

1685 lines
62 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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<std::string> 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<double> TrainAnaEngine::getCompPoint(AnalyseInfo info, cv::Mat baseimg, cv::Mat tarpic)
{
LogInfo << "TrainAnaEngine getCompPoint start";
std::vector<double> 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<std::string> 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<double>(0,0);
int nwidth = mtTempImage.cols;
int nHeight = mtTempImage.rows;
std::vector<int> 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<uchar>(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<<ncurtime;
std::string strscore(ossfloat.str());
std::string strindex(ossint.str());
std::string strtestpath = strResultPath_for_test + strindex + "_______" + strscore + ".jpg";
LogInfo << "TrainAnaEngine anapicbySpec image to" << strtestpath;
cv::imwrite(strtestpath, mtTempImage);
}
LogInfo << "TrainAnaEngine anapicbySpec end:" << match;
return match;
}
/**
* 根据直方图做比对
* inParam : 当前图像的Mat值
* inParam : 比对基础图像的Mat值
* inParam : 比对算法
* outParam: N/A
* return : 比对值
*/
double TrainAnaEngine::anapicbyHist(cv::Mat baseimg, cv::Mat tarpic, int method)
{
LogInfo << "TrainAnaEngine anapicbyHist start";
float hranges[] = {0, 180};
float sranges[] = {0, 255};
const float *ranges[] = {hranges, sranges};
int hbins = 60, sbins = 64;
int histSize[] = {hbins, sbins};
int channels[] = {0};
cv::Mat hist1, hist2;
//获取直方图信息
cv::calcHist(&baseimg, 1, channels, Mat(), hist1, 2, histSize, ranges);
cv::calcHist(&tarpic, 1, channels, Mat(), hist2, 2, histSize, ranges);
double match = cv::compareHist(hist1, hist2, method);
LogInfo << "TrainAnaEngine anapicbyHist end:" << match;
return match;
}
/**
* 根据模板做比对
* inParam : 当前图像的Mat值
* inParam : 比对基础图像的Mat值
* inParam : 比对算法
* outParam: 目标的坐标
* return : 比对值
*/
double TrainAnaEngine::anapicbyTemple(cv::Mat baseimg, cv::Mat tarpic, int method, cv::Point &pPos)
{
LogInfo << "TrainAnaEngine anapicbyTemple start";
double dRetVal = 0.0;
cv::Mat img_match;
//LogInfo << "TrainAnaEngine anapicbyTemple baseimg.cols:" << baseimg.cols;
//LogInfo << "TrainAnaEngine anapicbyTemple baseimg.rows:" << baseimg.rows;
//LogInfo << "TrainAnaEngine anapicbyTemple tarpic.cols:" << tarpic.cols;
//LogInfo << "TrainAnaEngine anapicbyTemple tarpic.rows:" << tarpic.rows;
cv::matchTemplate(baseimg, tarpic, img_match, method);
double minval, maxval;
cv::Point minloc, maxloc;
cv::minMaxLoc(img_match, &minval, &maxval, &minloc, &maxloc);
//LogInfo << "TrainAnaEngine anapicbyTemple method:" << method;
//TM_SQDIFF算法和TM_SQDIFF_NORMED算法最小值为最匹配的数值
if (
method == cv::TM_SQDIFF || method == cv::TM_SQDIFF_NORMED)
{
dRetVal = minval;
pPos = minloc;
}
//TM_CCORR TM_CCORR_NORMED TM_CCOEFF TM_CCOEFF_NORMED算法最大值为最匹配的数值
else if (
method == cv::TM_CCORR || method == cv::TM_CCORR_NORMED || method == cv::TM_CCOEFF || method == cv::TM_CCOEFF_NORMED)
{
dRetVal = maxval;
pPos = maxloc;
}
//LogInfo << "TrainAnaEngine anapicbyTemple end" << dRetVal;
//if (strResultPath_for_test != "" && nLatestFrame != 0)
if(false)
{
cv::Mat cvdes = Mat(baseimg.rows, baseimg.cols + tarpic.cols, baseimg.type());
cv::Mat cvleft = cvdes(cv::Rect(0, 0, baseimg.cols, baseimg.rows));
baseimg.copyTo(cvleft);
cv::Mat cvright = cvdes(cv::Rect(baseimg.cols, 0, tarpic.cols, tarpic.rows));
tarpic.copyTo(cvright);
std::ostringstream ossfloat,ossint;
ossfloat<<(int)(dRetVal*1000);
ossint<<nLatestFrame;
std::string strscore(ossfloat.str());
std::string strindex(ossint.str());
std::string strtestpath = strResultPath_for_test + strindex + "_" + strscore + ".jpg";
//LogInfo << "TrainAnaEngine anapicbyTemple image to" << strtestpath;
cv::imwrite(strtestpath, cvdes);
}
return dRetVal;
}
/**
* 读取图像文件并转化为Mat值
* inParam : 读取文件的路径
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtdecodeImageDatabyFile(string path)
{
LogInfo << "TrainAnaEngine mtdecodeImageDatabyFile start";
//LogInfo << "TrainAnaEngine mtdecodeImageDatabyFile path:" << path;
std::ifstream imagefile(path, std::ios::binary);
std::vector<char> imagedata;
imagefile >> std::noskipws;
std::copy(std::istream_iterator<char>(imagefile), std::istream_iterator<char>(), 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<char *>(lpimgdata);
vector<uchar>::size_type size = imglen;
std::vector<unsigned char> 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:"<<x1;
//LogInfo << "TrainAnaEngine mtImproveImage y1:"<<y1;
//LogInfo << "TrainAnaEngine mtImproveImage width:"<<width;
//LogInfo << "TrainAnaEngine mtImproveImage height:"<<height;
//LogInfo << "TrainAnaEngine mtImproveImage type:"<<type;
//图像灰度处理
if (((info.npicimprovetype & IMAGE_GRAY) == IMAGE_GRAY) && (mode != -1))
{
mtOutImage = mtgrayImage(mtOutImage, mode);
}
//图像直方图均衡化处理
if ((info.npicimprovetype & IMAGE_EQUALIZE) == IMAGE_EQUALIZE)
{
mtOutImage = mtequalizeImage(mtOutImage);
}
//图像进行gamma变换
if ((info.npicimprovetype & IMAGE_GAMMA) == IMAGE_GAMMA)
{
mtOutImage = mtGammaImage(mtOutImage, 1.0);
}
//自定义处理
if ((info.npicimprovetype & IMAGE_SPEC) == IMAGE_SPEC)
{
mtOutImage = mtspecImage(mtOutImage);
}
LogInfo << "TrainAnaEngine mtImproveImage end";
return mtOutImage;
}
/**
* 修改图像尺寸
* inParam : 原始图片的Mat值
* inParam : 目标宽度
* inParam : 目标高度
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtresizeImage(cv::Mat inImage, int width, int height)
{
LogInfo << "TrainAnaEngine mtresizeImage start";
//LogInfo << "TrainAnaEngine mtresizeImage width:"<<width;
//LogInfo << "TrainAnaEngine mtresizeImage height:"<<height;
cv::Mat mtTempImage = inImage;
cv::Mat mtOutImage;
cv::resize(mtTempImage, mtOutImage, cv::Size(width, height));
LogInfo << "TrainAnaEngine mtresizeImage end";
return mtOutImage;
}
/**
* 裁剪图像
* inParam : 原始图片的Mat值
* inParam : 开始位置的X值
* inParam : 开始位置的Y值
* inParam : 结束位置的X值
* inParam : 结束位置的Y值
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtareaImage(cv::Mat inImage, int x1, int y1, int x2, int y2)
{
LogInfo << "TrainAnaEngine mtareaImage start";
//LogInfo << "TrainAnaEngine mtareaImage x1:"<<x1;
//LogInfo << "TrainAnaEngine mtareaImage y1:"<<y1;
//LogInfo << "TrainAnaEngine mtareaImage x2:"<<x2;
//LogInfo << "TrainAnaEngine mtareaImage y2:"<<y2;
cv::Mat mtTempImage = inImage;
cv::Rect recArea = cv::Rect(x1, y1, abs(x2 - x1), abs(y2 - y1));
cv::Mat mtOutImage = mtTempImage(recArea);
//LogInfo << "TrainAnaEngine mtareaImage out cols:"<< mtOutImage.cols;
//LogInfo << "TrainAnaEngine mtareaImage out rows:"<< mtOutImage.rows;
LogInfo << "TrainAnaEngine mtareaImage end";
return mtOutImage;
}
/**
* 图像灰度化
* inParam : 原始图片的Mat值
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtgrayImage(cv::Mat inImage, int mode)
{
LogInfo << "TrainAnaEngine mtgrayImage start";
cv::Mat mtTempImage = inImage;
cv::Mat mtOutImage;
cv::cvtColor(mtTempImage, mtOutImage, mode);
LogInfo << "TrainAnaEngine mtgrayImage end";
return mtOutImage;
}
/**
* 图像直方图均衡化
* inParam : 原始图片的Mat值
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtequalizeImage(cv::Mat inImage)
{
LogInfo << "TrainAnaEngine mtequalizeImage start";
cv::Mat mtTempImage = inImage;
cv::Mat mtOutImage;
cv::equalizeHist(mtTempImage, mtOutImage);
LogInfo << "TrainAnaEngine mtequalizeImage end";
return mtOutImage;
}
/**
* 图像进行gamma变换
* inParam : 原始图片的Mat值
* inParam : gamma值
* outParam: N/A
* return : 图像Mat值
*/
cv::Mat TrainAnaEngine::mtGammaImage(cv::Mat inImage, float fgamma = 1.0)
{
LogInfo << "TrainAnaEngine mtGammaImage start";
//LogInfo << "TrainAnaEngine mtGammaImage fgamma:"<<fgamma;
cv::Mat mtTempImage = inImage;
cv::Mat mtOutImage;
for (int i = 0; i < mtTempImage.rows; i++){
for (int j = 0; j < mtTempImage.cols; j++) {
mtTempImage.at<uchar>(i, j) = 6*pow((double)inImage.at<unsigned char>(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<double> 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<<i)));
lstAction[i].bChanged = false;
}
}
#ifdef SHOW_RECTANGLE
if( lstAction[i].bChanged){
cv::putText(img,"yes",point,5,1.5,sca,3);
LogInfo<<"current img id "<<num << " yes";
}else{
cv::putText(img,"no",point,5,1.5,sca,3);
LogInfo<<"current img id "<<num << " no";
}
cv::putText(img,"similarity: "+to_string((int)((lstAction[i].dComparePoint)*1000)),point2,5,1.5,sca,3);
LogInfo<<"current img id "<<num << " similarity: "<<(int)((lstAction[i].dComparePoint)*1000);
#endif
// 如果最近100帧的最大值与最小值小于0.03视为无变化
if (GetPointMaxReduceMin(lstAction[i].dComparePoint,i)< 0.03){
lstAction[i].fluctuationFlag=true;
}else{
lstAction[i].fluctuationFlag=false;
}
#ifdef SHOW_RECTANGLE
if(lstAction[i].fluctuationFlag){
cv::putText(img,"fluctuation Low",point3,5,1.5,sca,3);
LogInfo<<"current img id "<<num << " fluctuation Low";
}else{
cv::putText(img,"fluctuation High",point3,5,1.5,sca,3);
LogInfo<<"current img id "<<num << " fluctuation High";
}
#endif
lstAction[i].bPreChanged = lstAction[i].bChanged;
}
//LogInfo << "TrainAnaEngine checkAction nStatus:" << nStatus;
//LogInfo << "TrainAnaEngine checkAction nPicAreaChangeing:" << nPicAreaChangeing;
//LogInfo << "TrainAnaEngine checkAction nPrePicAreaChangeing:" << nPrePicAreaChangeing;
/************************************************状态切换****************************************************************/
// 状态无车(并进行基础帧替换) -> 检测有车
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 "<<num << " train no";
cv::putText(img,"train no",cv::Point(150,200),5,4,sca,3);
#endif
}else if(nStatus == TRAIN_LEFT_RUN){
bool bpaused = false;
bool bpassed = false;
bool noFluctuationFlag = true;
unsigned short int bpaused_count = 0;
//0,1,2全部无改变相似度较高视为车辆已经过去
//0改变12无变化仍视为车辆已经过去
if(
(!lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(!lstAction[2].bChanged)||
(lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(!lstAction[2].bChanged)){
bpassed=true;
}
for (int i = 0; i < nlistlen; i++)
{
//任意两个及以上改变视为停车
if(lstAction[i].bChanged){
bpaused_count++;
}
noFluctuationFlag = (noFluctuationFlag && lstAction[i].fluctuationFlag);
}
bpaused=((bpaused_count>=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 "<<num << " director left ";
cv::putText(img,"director left",cv::Point(150,200),5,4,sca,3);
#endif
}else if (nStatus == TRAIN_RIGHT_RUN){
bool bpaused = false;
bool bpassed = false;
bool noFluctuationFlag = true;
unsigned short int bpaused_count = 0;
//0,1,2全部无改变相似度较高视为车辆已经过去
//2改变0,1无变化仍视为车辆已经过去
if(
(!lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(!lstAction[2].bChanged)||
(!lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(lstAction[2].bChanged)){
bpassed=true;
}
for (int i = 0; i < nlistlen; i++)
{
//任意两个及以上改变视为停车
if(lstAction[i].bChanged){
bpaused_count++;
}
noFluctuationFlag = (noFluctuationFlag && lstAction[i].fluctuationFlag);
}
bpaused=((bpaused_count>=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 "<<num << " director right ";
cv::putText(img,"director right",cv::Point(150,200),5,4,sca,3);
#endif
}else if (nStatus == TRAIN_UNKOWN_RUN){
bool bpaused = false;
bool bpassed = false;
bool noFluctuationFlag = true;
unsigned short int bpaused_count = 0;
//0,1,2全部无改变相似度较高视为车辆已经过去
//2改变0,1无变化仍视为车辆已经过去,或者0给改变12无变化
if(
(!lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(!lstAction[2].bChanged)||
(!lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(lstAction[2].bChanged)||
(lstAction[0].bChanged)&&(!lstAction[1].bChanged)&&(!lstAction[2].bChanged)
){
bpassed=true;
}
for (int i = 0; i < nlistlen; i++)
{
//任意两个及以上改变视为停车
if(lstAction[i].bChanged){
bpaused_count++;
}
noFluctuationFlag = (noFluctuationFlag && lstAction[i].fluctuationFlag);
}
bpaused=((bpaused_count>=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 "<<num << " director unkonw ";
cv::putText(img,"director unkonw",cv::Point(150,200),5,4,sca,3);
#endif
}else if(nStatus == TRAIN_PAUSE){
static short int count=0;
//停车状态只检测波动三块全部波动保持20帧即重启
if(!lstAction[0].fluctuationFlag&&!lstAction[1].fluctuationFlag&&!lstAction[2].fluctuationFlag){
if(count>20){
nStatus=TRAIN_RESTART;
count=0;
}
count++;
}
#ifdef SHOW_RECTANGLE
LogInfo<<"current img id "<<num << " train stop ";
cv::putText(img,"train stop",cv::Point(150,200),5,4,sca,3);
#endif
}else if(nStatus == TRAIN_RESTART){
//切换到TRAIN_UNKOWN_RUN
nStatus=TRAIN_UNKOWN_RUN;
#ifdef SHOW_RECTANGLE
LogInfo<<"current img id "<<num << " train restort ";
cv::putText(img,"train restort",cv::Point(150,200),5,4,sca,3);
#endif
}else if(nStatus == TRAIN_PASSED){
//切换回TRAIN_INIT_STATUS状态
nStatus = TRAIN_INIT_STATUS;
#ifdef SHOW_RECTANGLE
LogInfo<<"current img id "<<num << " train passed ";
cv::putText(img,"train passed",cv::Point(150,200),5,4,sca,3);
#endif
}
if(nStatus!=TRAIN_INIT_STATUS){
#ifdef SHOW_RECTANGLE
if(num%4==0){
LogInfo<<"current img id "<<num << " state: "<<nStatus;
cv::putText(img,"state: "+to_string(nStatus),cv::Point(150,400),5,4,sca,5);
imwrite(to_string(num)+".jpg",img);
}
#endif
}
LogInfo << "TrainAnaEngine checkAction end";
}
/**
* 车厢划分检测
* inParam : 原始图片的Mat值
* inParam : 原始图片的时间戳
* outParam: N/A
* return : N/A
*/
bool TrainAnaEngine::checkPartion(cv::Mat baseimg, uint64_t i64TimeStamp)
{
LogInfo << "TrainAnaEngine checkPartion start";
// 初始化是否有划分信息
bool bPartion = false;
// 记录上一帧的判断等级(相同作and处理 不同作or处理)
int nPreOrLevel = 1;
// LogInfo << "TrainAnaEngine checkPartion nStatus:" << nStatus;
// 停车状态不进行划分信息检测
//if(false){
if ((nStatus == TRAIN_PAUSE)
|| (nStatus == TRAIN_INIT_STATUS)
|| (nStatus == TRAIN_PASSED)){
return bPartion;
}
//LogInfo << "TrainAnaEngine checkPartion lstPartion.size():" << lstPartion.size();
// 根据判断算法的数量进行循环比对
bPartion = true;
for (int i = 0; i < lstPartion.size(); i++)
{
//LogInfo << "TrainAnaEngine checkPartion i:" << i;
// 算法不开启则跳过
if (lstPartion[i].bOn == false)
{
//LogInfo << "TrainAnaEngine checkPartion lstPartion[i].bOn i:" << i;
continue;
}
// 对当前帧图片进行切割
cv::Mat baseimgin = mtareaImage(baseimg, lstPartion[i].nAreaX1, lstPartion[i].nAreaY1, lstPartion[i].nAreaX2, lstPartion[i].nAreaY2);
// 对当前帧图片进行画面增强
//LogInfo << "TrainAnaEngine checkPartion cvImg1 cols:" << baseimgin.cols;
//LogInfo << "TrainAnaEngine checkPartion cvImg1 rows:" << baseimgin.rows;
cv::Mat cvImg1 = mtImproveImage(baseimgin, lstPartion[i], false);
//LogInfo << "TrainAnaEngine checkPartion cvImg1 cols:" << cvImg1.cols;
//LogInfo << "TrainAnaEngine checkPartion cvImg1 rows:" << cvImg1.rows;
cv::Mat cvImg2;
//LogInfo << "TrainAnaEngine checkPartion lstPartion[i].baseImagePath:" << lstPartion[i].baseImagePath;
if (lstPartion[i].baseImagePath == "None")
{
cv::Mat cvFirstImgin = mtareaImage(cvFirstImg, lstPartion[i].nAreaX1 - 10, lstPartion[i].nAreaY1 -10, lstPartion[i].nAreaX2 -10, lstPartion[i].nAreaY2 -10);
// 设定为None 用基础图像进行比对
cvImg2 = mtImproveImage(cvFirstImgin, lstPartion[i], false);
}
else
{
// 设定有路径则读取路径的文件进行比对
cvImg2 = cv::imread(lstPartion[i].baseImagePath, cv::IMREAD_GRAYSCALE);
// cvImg2 = mtdecodeImageDatabyFile(lstPartion[i].baseImagePath);
// 图像增强
cvImg2 = mtImproveImage(cvImg2, lstPartion[i], true);
}
// 获取比对值
//LogInfo << "TrainAnaEngine checkPartion cvImg1 cols:" << cvImg1.cols;
//LogInfo << "TrainAnaEngine checkPartion cvImg1 rows:" << cvImg2.rows;
std::vector<double> 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<void> pVoidData0 = nullptr;
inputQueMap_[strPort0_]->pop(pVoidData0);
if (nullptr == pVoidData0)
{
usleep(1000); //1ms
continue;
}
LogInfo << "TrainAnaEngine Process start";
std::shared_ptr<DecodedData> pDecodeData = std::static_pointer_cast<DecodedData>(pVoidData0);
std::shared_ptr<void> 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<void>(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<TrainRange> pTrainRange = std::make_shared<TrainRange>();
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<void>(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 "<<num;
num++;
LogInfo << "TrainAnaEngine Process end";
}
return APP_ERR_OK;
}