You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
smokeboxidentification/src/CategoryMatcher.cpp

377 lines
11 KiB
C++

#pragma execution_character_set("utf-8")
#include "CategoryMatcher.h"
CategoryMatcher::CategoryMatcher(QObject *parent)
: QObject(parent)
{
m_ilmatchPtr = ILMatchPtr(__uuidof(LMatch));
initILMatchParam(QCoreApplication::applicationDirPath() + MATCHER_CONFIG);
setILMatch(m_matchParam);
qDebug() << "init CategoryMatcher successed";
}
CategoryMatcher::~CategoryMatcher()
{
}
void CategoryMatcher::initILMatchParam(const QString& path)
{
QString fileMyself = path;
QFile file(fileMyself);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qWarning() << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD>";
return;
}
QByteArray arr = file.readAll();
file.close();
if (arr.isEmpty())
{
qWarning() << "<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>";
return;
}
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(arr, &err);
if (doc.isEmpty())
{
qWarning() << err.errorString(); //<2F><>ӡʧ<D3A1><CAA7><EFBFBD><EFBFBD>Ϣ
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.GrayValueWeight = MatchParamObj.value("GrayValueWeight").toInt();
m_matchParam.StrictScore = MatchParamObj.value("StrictScore").toBool();
m_bUseTotalThresh = MatchParamObj.value("UseTotalThresh").toBool();
}
}
void CategoryMatcher::setILMatch(const MatchParam& matchParam)
{
m_ilmatchPtr->MaxCount = m_matchParam.MaxCount;
m_ilmatchPtr->ScaleTolerance = m_matchParam.ScaleTolerance;
m_ilmatchPtr->AngleTolerance = m_matchParam.AngleTolerance;
m_ilmatchPtr->GrayValueWeight = m_matchParam.GrayValueWeight;
m_ilmatchPtr->StrictScore = m_matchParam.StrictScore;
if (m_bUseTotalThresh)
{
m_ilmatchPtr->AcceptScore = m_matchParam.AcceptScore;
}
}
bool CategoryMatcher::smokeMatch(const QString& typeNo, const cv::Mat& inputMat, cv::Mat& rltMat)
{
if (inputMat.empty())
{
qWarning() << "inputMat is empty";
return false;
}
ILImagePtr ilImgGray(__uuidof(LImage));
cv::Mat imgMatGray;
ensureGrayImg(inputMat, imgMatGray);
qDebug() << "ensureGrayImg OK!";
ilImgGray->SetImageData(imgMatGray.cols, imgMatGray.rows, (void*)imgMatGray.data, imgMatGray.step, 0);
qDebug() << "LPV SetImageData OK!";
std::pair<int, QVector<ILMatchResultPtr>> templateLevelAndvecMatchRltPtr;
bool bRlt = smokeMatch(typeNo, ilImgGray, templateLevelAndvecMatchRltPtr);
drawImage(imgMatGray, rltMat, templateLevelAndvecMatchRltPtr);
return bRlt;
}
bool CategoryMatcher::smokeMatch(const QString& typeNo, const ILImagePtr ilImgPtr,
std::pair<int, QVector<ILMatchResultPtr>>& templateLevelAndvecMatchRltPtr)
{
QVector<ILMatchResultPtr> vecMatchRltPtrMax;
TemplateObject templateObj;
QString templateImgFolderPath = TYPE_TEMPLATE_PATH;
QString folderPath = QString("%1\\%2").arg(templateImgFolderPath).arg(typeNo);
if (getTemplateImgFileInfo(folderPath, templateObj))
{
qDebug() << "Get TemplateImg OK!";
QVector<double> vecMatchSroreMax;
ILMatchResultsPtr matchResultsPtr;
QList<int> keys = templateObj.uniqueKeys();
int templateLevel = keys.length();
qDebug() << "templateLevel = "<< templateLevel;
templateLevelAndvecMatchRltPtr.first = templateLevel;
for each (int level in keys)
{
QVector<double> vecMatchSrore;
QVector<ILMatchResultPtr> vecMatchRltPtr;
QMap<QString, int> strScoreMap = templateObj.value(level);
for (QMap<QString, int>::iterator it = strScoreMap.begin(); it != strScoreMap.end(); ++it)
{
QString templateImgPath = it.key();
int scoreThresh;
if (!m_bUseTotalThresh)
{
scoreThresh = it.value();
m_ilmatchPtr->AcceptScore = scoreThresh;
}
else
{
scoreThresh = m_matchParam.AcceptScore;
}
ILImagePtr ilTemplatePtr(__uuidof(LImage));
ilTemplatePtr->Load(templateImgPath.toStdString().c_str());
if (ilTemplatePtr->Void())
{
QString outStr = templateImgPath + " is empty!";
qDebug() << outStr;
continue;
}
m_ilmatchPtr->DetailLevel = 0.5;
m_ilmatchPtr->Learn(ilTemplatePtr, nullptr);
// <20><><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ر<EFBFBD><D8B1>࣬ƥ<E0A3AC><C6A5>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0B5B1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD>ϸ<EFBFBD><CFB8>
ILPointsPtr featurePoints = m_ilmatchPtr->GetPatFeature();
if (featurePoints->Count()>3000)
{
m_ilmatchPtr->DetailLevel = 0.05;
m_ilmatchPtr->Learn(ilTemplatePtr, nullptr);
}
LPVErrorCode err = m_ilmatchPtr->Match(ilImgPtr, nullptr, &matchResultsPtr);
if (err != LPVErrorCode::LPVNoError) {
continue; // match failed
}
int objCount = matchResultsPtr->Count();
if (objCount > 0)
{
double maxScore = -1;
ILMatchResultPtr matchRltPtr;
int indexMaxScore = 0;
for (int i = 0; i < objCount; i++)
{
matchRltPtr = matchResultsPtr->Item(i);
double score = matchRltPtr->GetScore();
if (score < scoreThresh)
{
continue;
}
if (maxScore < score)
{
maxScore = score;
indexMaxScore = i;
}
}
if (maxScore < 0)
continue;
vecMatchSrore.push_back(maxScore);
vecMatchRltPtr.push_back(matchResultsPtr->Item(indexMaxScore));
}
}
if (vecMatchSrore.isEmpty())
{
break;
}
else
{
auto maxMatchScorePos = std::max_element(vecMatchSrore.begin(), vecMatchSrore.end());
auto maxIndex = maxMatchScorePos - vecMatchSrore.begin();
vecMatchSroreMax.push_back(*maxMatchScorePos);
vecMatchRltPtrMax.push_back(vecMatchRltPtr.at(maxIndex));
}
}
if (vecMatchSroreMax.isEmpty() || (vecMatchSroreMax.length() != templateLevel))
{
QString outStr = QString("Level: %1 match failed!")
.arg(vecMatchSroreMax.length() + 1);
qDebug() << outStr;
templateLevelAndvecMatchRltPtr.second = vecMatchRltPtrMax;
return false;
}
else
{
templateLevelAndvecMatchRltPtr.second = vecMatchRltPtrMax;
}
}
else
{
QString outStr = QString("%1 find templateImage failed!").arg(folderPath);
qDebug() << outStr;
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("_");
if (strList.first() == "template" && strList.length() == 3)
{
int scoreThresh = strList.last().toInt();
QString templateImgPath = imgFileInfo.filePath(); //<2F><><EFBFBD><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>·<EFBFBD><C2B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ȡʧ<C8A1><CAA7>
std::pair<QString, int> 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(const cv::Mat& imgMatSrc, cv::Mat& rltCvImg,
std::pair<int, QVector<ILMatchResultPtr>> templateLevelAndvecMatchRltPtr)
{
if (imgMatSrc.empty()) {
return;
}
ensureColorBGRImg(imgMatSrc, rltCvImg);
int level = 1;
int templateLevel = templateLevelAndvecMatchRltPtr.first;
QVector<ILMatchResultPtr> 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;
}
}