#pragma execution_character_set("utf-8") #include "CategoryMatcher.h" CategoryMatcher::CategoryMatcher(QObject *parent) : QObject(parent) { m_ilmatch = ILMatchPtr(__uuidof(LMatch)); m_ilmatchF = ILMatchPtr(__uuidof(LMatch)); m_display = ILDisplayPtr(__uuidof(LDisplay)); m_text = ILTextPtr(__uuidof(LText)); m_textSys= ILSystemPtr(__uuidof(LSystem)); initILMatchParam(QCoreApplication::applicationDirPath() + MATCHER_CONFIG); setILMatch(m_matchParam); qDebug() << "init CategoryMatcher successed"; m_text->Alignment = LPVAlignment::LPVAlignLeft; // 设置文本绘制时的对齐方式 m_textSys->SetFontColor(m_text, m_textSys->GetColorRef(0, 255, 0)); // 设置文本的颜色 m_textSys->SetFontHeight(m_text, 80); // 设置字体高度 m_textSys->SetFontFamily(m_text, "Microsoft YaHei"); // 设置字体类型 m_text->PosX = 100; m_text->PosY = 100; // 设置文本绘制时的位置 } CategoryMatcher::~CategoryMatcher() { } void CategoryMatcher::initILMatchParam(const QString& path) { QString fileMyself = path; QFile file(fileMyself); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "打开文件失败!"; return; } QByteArray arr = file.readAll(); file.close(); if (arr.isEmpty()) { qWarning() << "内容为空"; return; } QJsonParseError err; QJsonDocument doc = QJsonDocument::fromJson(arr, &err); if (doc.isEmpty()) { qWarning() << err.errorString(); //打印失败信息 return; } QJsonObject jsMyself = doc.object(); QJsonObject MatchParamObj = jsMyself.value("MatchParam").toObject(); if (!MatchParamObj.isEmpty()) { m_matchParam.MaxCount = MatchParamObj.value("MaxCount").toInt(); m_matchParam.ScaleTolerance = MatchParamObj.value("ScaleTolerance").toInt(); m_matchParam.AngleTolerance = MatchParamObj.value("AngleTolerance").toInt(); m_matchParam.AcceptScore = MatchParamObj.value("ScoreThresh").toInt(); m_matchParam.StrictScore = MatchParamObj.value("StrictScore").toBool(); m_matchParam.UseCache = MatchParamObj.value("UseCache").toBool(); } } void CategoryMatcher::setILMatch(const MatchParam& matchParam) { m_ilmatch->MaxCount = m_matchParam.MaxCount; m_ilmatch->ScaleTolerance = m_matchParam.ScaleTolerance; m_ilmatch->AngleTolerance = m_matchParam.AngleTolerance; m_ilmatch->StrictScore = m_matchParam.StrictScore; m_ilmatch->UseCache = m_matchParam.UseCache; m_ilmatch->AcceptScore = m_matchParam.AcceptScore; m_ilmatchF->MaxCount = m_matchParam.MaxCount; m_ilmatchF->ScaleTolerance = m_matchParam.ScaleTolerance; m_ilmatchF->AngleTolerance = m_matchParam.AngleTolerance; m_ilmatchF->StrictScore = m_matchParam.StrictScore; m_ilmatchF->UseCache = m_matchParam.UseCache; m_ilmatchF->AcceptScore = m_matchParam.AcceptScore; } bool CategoryMatcher::smokeMatch(const QString& typeNo, ILImagePtr image, int id) { QMap resultsPair; bool bRlt = smokeMatch(typeNo, image, resultsPair,id); drawImage(image, resultsPair); return bRlt; } bool CategoryMatcher::smokeMatch(const QString& typeNo, const ILImagePtr ilImgPtr, QMap& resultsMap, int id) { TemplateObject templateObj; QString templateImgFolderPath = TYPE_TEMPLATE_PATH; //可能存在问题:之前的模板设计。后缀带了别的数据。需验证 // 模板文件格式:烟箱编码/烟箱编码-模板编码 // 模板编码:模板类型+模板编号 // 模板类型:1为大模板(模板和匹配图均放缩50%),2为小模板 // 例如:1类模板的第1个模板:11 // 中华硬310102的2类模板的第1个模板:310102-21 QString folderPath = QString("%1\\%2").arg(templateImgFolderPath).arg(typeNo); QString str; if (getTemplateImgFileInfo(folderPath, templateObj)) { str = QString("[%1]:Get TemplateImg OK!").arg(id); qDebug() < vecMatchSroreMax; QVector vecMatchRltsMax; QList keys = templateObj.uniqueKeys(); int templateLevelCount = keys.length(); str = QString("[%1]:templateLevelCount =%2").arg(id).arg(templateLevelCount); qDebug() << str; // 遍历不同模板级别 for each (int level in keys) { QVector vecMatchSrore; QVector vecMatchRlts; resultsMap.insert(level, nullptr); QMap strScoreMap = templateObj.value(level); for (QMap::iterator it = strScoreMap.begin(); it != strScoreMap.end(); ++it) { QString templateImgPath = it.key(); ILImagePtr ilTemplatePtr(__uuidof(LImage)); ilTemplatePtr->Load(templateImgPath.toStdString().c_str()); if (ilTemplatePtr->Void()) { QString outStr = templateImgPath + " is empty!"; qDebug() << outStr; continue; } m_ilmatch->Learn(ilTemplatePtr, nullptr); ILImagePtr img(__uuidof(LImage)); ILImagePtr tempImage(__uuidof(LImage)); //由于如果角度开到±180,部分匹配时间过长,故而用两次模板匹配,分别匹配模板和模板旋转180度情况 ILImageArithmPtr imgArithmF(__uuidof(LImageArithm)); imgArithmF->Flip(ilTemplatePtr, LPVFlipType::LPVFlipH, tempImage); imgArithmF->Flip(tempImage, LPVFlipType::LPVFlipV, tempImage); m_ilmatchF->Learn(tempImage, nullptr); ILMatchResultsPtr matchResults, matchResultsF; ILRotRectRegionPtr rectRoi(__uuidof(LRotRectRegion)); if (level == 1) // 大模板 { ILImageArithmPtr imgArithm(__uuidof(LImageArithm)); imgArithm->Resize(ilImgPtr, 0.5, 0.5, LPVInterNearest, img); rectRoi->SetPlacement(800, 500, 500, 1250, 600); } else { rectRoi->SetPlacement(1600, 1000, 2500, 1200, 0); } qInfo() << "setrectRoi end"; LPVErrorCode err = m_ilmatch->Match((level == 1 ? img : ilImgPtr), rectRoi, &matchResults); LPVErrorCode errF = m_ilmatchF->Match((level == 1 ? img : ilImgPtr), rectRoi, &matchResultsF); if (err < LPVErrorCode::LPVNoError || errF < LPVErrorCode::LPVNoError) { str = QString("[%1]:Match Failed;templateImgPath = %2").arg(id).arg(templateImgPath); qDebug() << str; continue; // match failed } int objCount = matchResults->Count() + matchResultsF->Count(); if (objCount > 0) { double valueMaxScore = -1; ILMatchResultPtr matchRltPtr; int indexMaxScore = 0; QVector matchSrore; // 模板方向的匹配结果——旋转180度匹配结果,组成一个完整的匹配结果值 for (int i = 0; i < matchResults->Count(); i++) { matchSrore.push_back(matchResults->Item(i)->Score); } for (int i = 0; i < matchResultsF->Count(); i++) { matchSrore.push_back(matchResultsF->Item(i)->Score); } //选择评分最高的匹配结果 auto maxPos = std::max_element(matchSrore.begin(), matchSrore.end()); valueMaxScore = *maxPos; indexMaxScore = maxPos - matchSrore.begin(); vecMatchSrore.push_back(valueMaxScore); if (indexMaxScore < matchResults->Count()) { vecMatchRlts.push_back(matchResults->Item(indexMaxScore)); } else { vecMatchRlts.push_back(matchResultsF->Item(indexMaxScore - matchResults->Count())); } } } if (vecMatchSrore.isEmpty()) { str = QString("[%1]:Level: %1 match failed!").arg(id).arg(level); qDebug() << str; return false; } else { // 选择该模板等级下评分最高的匹配结果 auto maxMatchScorePos = std::max_element(vecMatchSrore.begin(), vecMatchSrore.end()); auto maxIndex = maxMatchScorePos - vecMatchSrore.begin(); vecMatchSroreMax.push_back(*maxMatchScorePos); //vecMatchRltsMax.push_back(vecMatchRlts.at(maxIndex)); resultsMap[level]=vecMatchRlts.at(maxIndex); } } } else { str = QString("[%1]:Find templateImage failed! Folder = %2").arg(id).arg(folderPath); qDebug() << str; return false; } return true; } bool CategoryMatcher::getTemplateImgFileInfo(const QString& folderPath, TemplateObject& templateObject) { templateObject.clear(); QDir fileDir(folderPath); if (!fileDir.exists()) { qWarning() << folderPath << " is not exist"; return false; } for each(QFileInfo imgFileInfo in fileDir.entryInfoList(QDir::Filter::Files | QDir::NoDotAndDotDot)) { QString fileName = imgFileInfo.fileName(); if (fileName.endsWith(".png") || fileName.endsWith(".PNG") || fileName.endsWith(".BMP") || fileName.endsWith(".bmp") || fileName.endsWith(".jpeg") || fileName.endsWith(".JPEG") || fileName.endsWith(".jpg") || fileName.endsWith(".JPG")) { QStringList strList = imgFileInfo.baseName().split("-"); QString templateImgPath = imgFileInfo.filePath(); //相对路径,避免路径存在中文时读取失败 int level = strList.last().mid(0, 1).toInt(); templateObject[level].insert(templateImgPath, 70); ////之前的模板格式,例如:templateImg/51520312/template_0101_65 //if (strList.first() == "template" && strList.length() == 3) //{ // int scoreThresh = strList.last().toInt(); // QString templateImgPath = imgFileInfo.filePath(); //相对路径,避免路径存在中文时读取失败 // std::pair imgScorePair(templateImgPath, scoreThresh); // QString serialNum = strList[1]; // if (serialNum.length() == 4) // { // int level = serialNum.mid(0, 2).toInt(); // templateObject[level].insert(templateImgPath, scoreThresh); // } //} } } if (templateObject.isEmpty()) { return false; } return true; } void CategoryMatcher::drawImage(ILImagePtr image, QMap resultsMap) { if (image->Void()) { return; } std::stringstream textStream(""); //在Display上绘制图像+结果 m_display->SetImage(image); m_display->RemoveAllObjects(); QString tittleStr,rltStr; bool bRlt = false; for (auto iter = resultsMap.begin(); iter != resultsMap.end(); iter++) { ILMatchResultPtr matchRlt = iter.value(); if (matchRlt == nullptr) { continue; } bRlt = true; double score = matchRlt->GetScore(); rltStr.append(QString("\n Level %1 score: %2").arg(iter.key()).arg(score)); if (iter.key() == 1) { ILRotRectRegionPtr m_rect(__uuidof(LRotRectRegion)); m_rect->SetPlacement(matchRlt->GetCenter()->X * 2, matchRlt->GetCenter()->Y * 2 , matchRlt->GetRect()->Width * 2, matchRlt->GetRect()->Height * 2, matchRlt->GetRect()->Angle); m_textSys->SetPenWidth(m_rect, 3); m_textSys->SetPenColor(m_rect, m_textSys->GetColorRef(0, 255, 0)); m_display->AddObject(m_rect, 0); } else { m_textSys->SetPenWidth(matchRlt, 3); m_textSys->SetPenColor(matchRlt, m_textSys->GetColorRef(0, 255, 0)); m_display->AddObject(matchRlt, LPVPatDrawFlags::LPVPatDrawBoundingRect); } } ILRotRectRegionPtr m_rect(__uuidof(LRotRectRegion)); m_rect->SetPlacement(1600, 1000, 2500, 1200, 0); m_textSys->SetPenWidth(m_rect, 3); m_textSys->SetPenColor(m_rect, m_textSys->GetColorRef(0, 255, 0)); m_display->AddObject(m_rect, 0); if (bRlt) { m_textSys->SetFontColor(m_text, m_textSys->GetColorRef(0, 255, 0)); tittleStr = QString("Match successful! Total level Count: %1").arg(resultsMap.keys().length()); } else { m_textSys->SetFontColor(m_text, m_textSys->GetColorRef(255, 0, 0)); tittleStr = QString("Match failed! Total level Count: %1").arg(resultsMap.keys().length()); } textStream << tittleStr.toStdString(); textStream << rltStr.toStdString(); m_text->Text = textStream.str().c_str(); m_display->AddObject(m_text,0); } void CategoryMatcher::saveResultsImage(const QString& filePath) { std::wstring str = filePath.toStdWString(); m_display->SaveSceneToFile(str.c_str(), 1, 1); } void CategoryMatcher::drawImage(const cv::Mat& imgMatSrc, cv::Mat& rltCvImg, std::pair> templateLevelAndvecMatchRltPtr) { if (imgMatSrc.empty()) { return; } ensureColorBGRImg(imgMatSrc, rltCvImg); int level = 1; int templateLevel = templateLevelAndvecMatchRltPtr.first; QVector vecMatchRltPtr = templateLevelAndvecMatchRltPtr.second; QString rltStr; cv::Scalar textColor(0, 255, 0); if (!vecMatchRltPtr.isEmpty() && (vecMatchRltPtr.length() == templateLevel)) { rltStr = QString("Match successful! Total level: %1").arg(templateLevel); } else { textColor = cv::Scalar(0, 0, 255); rltStr = QString("Match failed! Total level: %1").arg(templateLevel); } int fontFace = cv::FONT_HERSHEY_DUPLEX; double fontScale = 2.5; int textThickness = 2; int baseLine = 0; int startX = 50; int startY = 100; cv::Size textSize = cv::getTextSize(rltStr.toStdString(), fontFace, fontScale, textThickness, &baseLine); cv::putText(rltCvImg, rltStr.toStdString(), cv::Point(startX, startY), fontFace, fontScale, textColor, textThickness); rltStr.clear(); for each(ILMatchResultPtr matchRltPtr in vecMatchRltPtr) { double score = matchRltPtr->GetScore(); rltStr.append(QString(" Level %1 score: %2").arg(level++).arg(score)); ILRectPtr ilRectPtr = matchRltPtr->GetRect(); ILPointsPtr ilPointsPtr = ilRectPtr->GetPoints(); cv::Point2f vertices[4]; int count = ilPointsPtr->Count(); if (count != 4) { continue; } for (int i = 0; i < count; ++i) { ILPointPtr ilPointPtr = ilPointsPtr->Item(i); vertices[i] = cv::Point2f(ilPointPtr->GetX(), ilPointPtr->GetY()); } for (int i = 0; i < 4; ++i) { cv::line(rltCvImg, vertices[i], vertices[(i + 1) % 4], cv::Scalar(255, 0, 0), 8); } } if (!rltStr.isEmpty()) { cv::putText(rltCvImg, rltStr.toStdString(), cv::Point(startX, startY + textSize.height + 20), fontFace, fontScale, textColor, textThickness); } } bool ensureGrayImg(const cv::Mat& img, cv::Mat& gray) { if (img.channels() == 3) { if (img.depth() == CV_8U) { cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); } else { cv::Mat channels[3]; split(img, channels); gray = channels[2] * 0.299 + channels[1] * 0.587 + channels[0] * 0.114; } return true; } else if (img.channels() == 4) { if (img.depth() == CV_8U) { cvtColor(img, gray, cv::COLOR_BGRA2GRAY); } else { cv::Mat channels[4]; cv::split(img, channels); gray = channels[2] * 0.299 + channels[1] * 0.587 + channels[0] * 0.114; } return true; } else if (img.channels() == 1) { gray = img; return false; } else { _ASSERTE(false && "unsupported image conversion."); return false; } } bool ensureColorBGRImg(const cv::Mat& img, cv::Mat& color) { if (img.channels() == 3) { color = img; return false; } else if (img.channels() == 4) { if (img.depth() == CV_8U) { cvtColor(img, color, cv::COLOR_BGRA2BGR); } else { static int from4_to3[] = { 0,0,1,1,2,2 }; if (color.cols != img.cols || color.rows != img.rows || color.type() != CV_MAKE_TYPE(img.depth(), 3)) color = cv::Mat(img.rows, img.cols, CV_MAKE_TYPE(img.depth(), 3)); mixChannels(img, color, from4_to3, 3); } return true; } else if (img.channels() == 1) { if (img.depth() == CV_8U) { cvtColor(img, color, cv::COLOR_GRAY2BGR); } else { static int from1_to3[] = { 0,0,0,1,0,2 }; if (color.cols != img.cols || color.rows != img.rows || color.type() != CV_MAKE_TYPE(img.depth(), 3)) color = cv::Mat(img.rows, img.cols, CV_MAKE_TYPE(img.depth(), 3)); mixChannels(img, color, from1_to3, 3); } return true; } else { _ASSERTE(false && "unsupported image conversion."); return false; } }