#include "AlgorithmFluorescence.h" #include "ImageProcess.h" #include #include #include #include #include "CVUtils.h" #include "qtcvutils.h" #include "Result2Ui.h" #include "ICompareModel.h" #include "IWheelModel.h" #pragma execution_character_set("utf-8") #define MAX_CIRCLE_RADII 110 #define MIN_INSIDE_RATIO 0.038 #define MAX_INSIDE_RATIO 0.072 #define INSIDE_NUM_DIS_THRE 1.5 using namespace cv; using namespace lp; class CLocalWheel{ public: CLocalWheel() { useHeight = true; useDiameter = true; } cv::Mat img; int height; int diameter; bool useHeight; bool useDiameter; QStringList defectList; double dRatioVal{0}; int ratioType{ 0 }; }; CAlgorithmFluorescence::CAlgorithmFluorescence(void) { } CAlgorithmFluorescence::~CAlgorithmFluorescence(void) { } //检测算法入口函数 由corctl框架回调 int CAlgorithmFluorescence::IImageAnalysis(class IImageObject* pImgObj, TP_ALGORITHM_OPTION* pOpt, class IDetectorEngine* pDE) { try { qDebug() << "start alg"; QMutexLocker locker(&mutex); CircleParam cParam; double dStart = cv::getTickCount(); Mat matSrc = getImage(pImgObj).clone();//获取相机原始图像 QVariantMap vMap = pImgObj->IVarFromUI().toMap();//获取由UI传递过来的算法参数 //解析出模板库指针 这里获取的是整个模块库 long long modelMapPtr = vMap.value("modelMap").toLongLong(); QMap *ptr = (QMap*)modelMapPtr; //获取需要检测的列表 型号名 long long defectListPtr = vMap.value("defectList").toLongLong(); QStringList* strModelListptr = (QStringList*)defectListPtr; QStringList strModelList; if(strModelListptr) strModelList = *(strModelListptr); int IsCutedImg = vMap.value("IsCutImg", 0).toInt();//裁剪后的轮毂图 检测模式 小图 int th = vMap.value("thickness", -1).toInt();//轮毂厚度 轮毂高度数据 bool useThickness = vMap.value("useThickness", 0).toBool();//是否使用厚度检测判断 匹配时过滤不符合范围的模板 bool useDiameter = vMap.value("useDiameter", 0).toBool();//是否使用直径参数检测判断 double dD2H = vMap.value("d2h", -1).toDouble(); int nthreshold = vMap.value("Threshold", 15).toInt();//图像阈值参数 使用背景图抠图算法时使用 bool bUseBackground = vMap.value("useBackground",false).toBool();//true 使用背景图抠图 false 不使用背景 int ratioType = vMap.value("RatioType").toInt();//偏距检测模式 启用方式 double ratioVal = vMap.value("Ratio").toDouble();//偏距系数 bool bEqual = vMap.value("bEqual").toBool();//使用使用图像增强 int filterSize = vMap.value("filterSize").toInt();//过滤圆大小 cParam.CirclePolarity = vMap.value("Circle_Polarity",0).toInt(); cParam.CircleACThres = vMap.value("Circle_ACThres",3).toInt(); cParam.CircleEdgeWidth = vMap.value("Circle_EdgeWidth",3).toInt(); cParam.filterSize = filterSize; if (nthreshold <= 0) nthreshold = 15; QVariantMap rltMap;//算法检测结果值 输出到UI用 rltMap.insert("ratioVal", ratioVal); luffy_base::luffyCircle lCircle; static bool bReload = false;//背景图加载判断 Mat matBack = getBackGroundImage(pImgObj, bReload);//获取背景图 Mat matMatch;//抠图后的图像 目标图像 if (IsCutedImg == 0) //使用的是原始图像 需要执行圆查找算法找出 轮毂 { //原始图像的size和背景图size不匹配, 直接返回错误提示 if (bUseBackground == true && (matSrc.size().height != matBack.size().height || matSrc.size().width != matBack.size().width)) { rltMap.insert("error", 0); pImgObj->IVariantMapToUI(rltMap); bReload = true; return 0; } else{ bReload = false; } if (bUseBackground == true)//使用背景图 做减法找圆 { Point2f centerPoint; double radius = 0; matMatch = ImageProcess::findCircleByBackground(matSrc, matBack, centerPoint, radius, bEqual, filterSize, cParam); lCircle.ptCenter = centerPoint; lCircle.fRadius = radius; } else { //不需要 背景图找圆算法 Point2f centerPoint; double radius = 0; matMatch = ImageProcess::findCircle(matSrc, centerPoint, radius, bEqual,filterSize,cParam); lCircle.ptCenter = centerPoint; lCircle.fRadius = radius; } if (matMatch.cols >= 900 || matMatch.rows >= 900)//控制检测图像大小不能超过这个范围 { cv::resize(matMatch, matMatch, cv::Size(matMatch.cols / 2, matMatch.rows / 2)); lCircle.fRadius = lCircle.fRadius / 2; } } else{ matMatch = matSrc; } Result2Ui *pResult = new Result2Ui; pResult->m_pixSrc = QtCVUtils::cvMatToQPixmap(matSrc);//!>原图像发送值UI 用于保存备份和调试 if (matMatch.empty())//抠图为空,表示抠图失败,直接返回错误 { rltMap.insert("noCircle", 0); long long varRlt = (long long)pResult; rltMap.insert("result", varRlt); pImgObj->IVariantMapToUI(rltMap); return 0; } double dDiameter = dD2H * lCircle.fRadius * 2;//计算轮毂直径 //打包相关数据 CLocalWheel wheelLocal; wheelLocal.defectList = strModelList; wheelLocal.img = matMatch.clone(); wheelLocal.height = th; wheelLocal.diameter = dDiameter; wheelLocal.useHeight = useThickness; wheelLocal.useDiameter = useDiameter; wheelLocal.ratioType = ratioType; wheelLocal.dRatioVal = ratioVal; //开始匹配 if (!matMatch.empty() && ptr && ptr->size() > 0) { vector minDisVec(ptr->size());//初始化模板匹配分数值 QString str = bestMatch(ptr, &wheelLocal, &(minDisVec[0]), minDisVec.size()); pResult->m_strModel = str; pResult->m_dMinDis = minDisVec[0]; if (ptr->contains(str) && ptr->value(str)->getImageComModel()) { ICompareModel *pModel = ptr->value(str)->getImageComModel(); double d = pModel->getDisThre(); double dValue = (d - minDisVec[0]) / d * 0.4 + 0.6; pResult->m_dScore = dValue; } } qDebug() << "pull result"; QImage img = QtCVUtils::cvMatToQImage(matMatch); pResult->m_pixResult = QtCVUtils::cvMatToQPixmap(matMatch);// .scaled(125, 125); pResult->m_dDiameter = dDiameter; pResult->m_dThickness = th; //!>传递检测结果到UI //pImgObj->IDrawImage(img.scaled(300, 300));//!>显示结果图片到UI的第二个窗口上 double dTime = (cv::getTickCount() - dStart) / cv::getTickFrequency(); pResult->m_dRunTime = dTime; long long varRlt = (long long)pResult; rltMap.insert("result", varRlt); pImgObj->IVariantMapToUI(rltMap); qDebug() << "finish alg"; return 1; } catch (...) { qDebug() << "algo run Error " << __FUNCTION__; return 1; } } //模板匹配流程 QString CAlgorithmFluorescence::bestMatch(const QMap* modelMap, CLocalWheel* pLocal, double* pMinDis /*= NULL*/, int minDisNum /*= -1*/) const { double minDis = DBL_MAX; QString bestName; vector disVec(modelMap->size()); int nIndex = 0; if (!modelMap) return bestName; QStringList strDetectModels = pLocal->defectList; int similarNum = 0; const QString hubName1("DH151079"); const QString hubName2("DK151050"); QMap simularModelMap; while (strDetectModels.size()) { QString strModelName = strDetectModels.takeFirst(); if (!modelMap->contains(strModelName)) continue; QMap::const_iterator itsModel = modelMap->find(strModelName); disVec[nIndex] = DBL_MAX; IWheelModel *pWheel = itsModel.value(); if (!pWheel) break; if (pLocal->useDiameter) { if (abs(pLocal->diameter - pWheel->getDiameter()) >= 15) { nIndex++; continue; } } if (pLocal->useHeight) { if (abs(pLocal->height - pWheel->getThickness()) >= 15) { nIndex++; continue; } } if (pLocal->ratioType == 1) {//开启使用偏距过滤检测模板的功能 //必须三个数值不为0才进行 否则可能导致不明问题 double curRatioVal = pLocal->dRatioVal; double minRatio = pWheel->getMinRotia(); double maxRatio = pWheel->getMaxRotia(); if (curRatioVal > 0 && minRatio > 0 && maxRatio > 0) { if (curRatioVal < minRatio || curRatioVal > maxRatio) { nIndex++; continue; } } } QString name = strModelName; ICompareModel* pModel = pWheel->getImageComModel(); if (pModel->getBaseImg().data == NULL) { nIndex++; continue; } pModel->setIsEnableCache(false); double dis = pModel->compare(pLocal->img, NULL, true, 1); double disThre = pModel->getDisThre(); double innerCircleNum = pModel->getInnerCircleNum(); if (dis < disThre) { similarNum++; simularModelMap[name] = innerCircleNum; } disVec[nIndex] = dis; if (dis < minDis && dis != -1) { minDis = dis; bestName = name; } nIndex++; } if (pMinDis) { *pMinDis = minDis; } if (minDisNum > 1) { sort(disVec.begin(), disVec.end()); std::copy_n(disVec.begin(), minDisNum, pMinDis); } if (similarNum < 1) { return bestName; } const cv::Mat originalMat = pLocal->img; float startX = originalMat.cols / 2.0 - MAX_CIRCLE_RADII;//找最大圆外径,固定直径 float startY = originalMat.rows / 2.0 - MAX_CIRCLE_RADII; Rect rect(startX, startY, MAX_CIRCLE_RADII * 2, MAX_CIRCLE_RADII * 2); cv::Mat centerMat = originalMat(rect).clone(); EDCircles edCircles(centerMat); std::vector circles = edCircles.getCircles(); const int nSize = circles.size(); float rMax = 0; for (int i = 0; i < nSize; ++i) { float radius = circles[i].r; if (radius > rMax) { rMax = radius; } } double innerCircleNumSum = 0; double rMaxUp = rMax * MAX_INSIDE_RATIO; double rMaxLow = rMax * MIN_INSIDE_RATIO; for (int i = 0; i < nSize; ++i) { double radius = circles[i].r; if (radius < rMaxUp && radius > rMaxLow * MIN_INSIDE_RATIO) { innerCircleNumSum++; } } if (bestName.toUpper() == hubName1) { if (innerCircleNumSum > 1) { QStringList modelList = pLocal->defectList; bool bFind = false; while (modelList.size()) { QString modelName = modelList.takeFirst(); if (modelName == hubName2) { bestName = hubName2; bFind = true; break; } } if (!bFind) { // bestName = QString(); } } } else if (bestName.toUpper() == hubName2) { if (innerCircleNumSum < 2) { QStringList modelList = pLocal->defectList; bool bFind = false; while (modelList.size()) { QString modelName = modelList.takeFirst(); if (modelName == hubName1) { bestName = hubName1; bFind = true; break; } } if (!bFind) { // bestName = QString(); } } } return bestName; } cv::Mat CAlgorithmFluorescence::getImage(class IImageObject *pImgObj) { emTpColorFormat colorFormat = pImgObj->IColorFormat(); int nImageW; int nImageH; int nBitsPerPixel; int nBytesPerLine; BYTE* pImageData = pImgObj->IImageData(nImageW, nImageH, nBitsPerPixel, nBytesPerLine); Mat matSrc; if (TP_COLOR_Y800 != colorFormat) { Mat colorMat = Mat(nImageH, nImageW, CV_8UC4, pImageData, nBytesPerLine); matSrc = getFirstChannel(colorMat); } else { matSrc = Mat(nImageH, nImageW, CV_8UC1, pImageData, nBytesPerLine); } return matSrc; } cv::Mat CAlgorithmFluorescence::getBackGroundImage(class IImageObject *pObj, bool bReLoad) { static Mat matback; if (matback.empty()) { QString filepath = ".\\user\\background.png"; matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0); if (matback.empty()) { QString filepath = getPath(pObj) + "\\user\\background_r.png"; matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0); cv::flip(matback, matback, 1); } } else { if (bReLoad) { QString filepath = getPath(pObj) + "\\user\\background.png"; matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0); if (matback.empty()) { QString filepath = getPath(pObj) + "\\user\\background_r.png"; matback = cv::imread(string((const char *)filepath.toLocal8Bit()), 0); cv::flip(matback, matback, 1); } } } return matback; } QString CAlgorithmFluorescence::getPath(class IImageObject *pObj) { IAlgorithmShared* pShare = pObj->IGetShared(); if (!pShare) return QString(); QStringList mlist = pObj->IGetShared()->IGetStringList("filepath"); if (mlist.empty()) { return QString(); } return mlist.first(); }