#include "QAlgDetect.h" #include "ED.h" #include "EDLines.h" #include "EDCircles.h" #include #include #include "CircleDetector.h" #include "ICompareModel.h" #include "QFunctionTransfer.h" using namespace std; static QImage cvMat2QImage(const cv::Mat& mat) { if (mat.type() == CV_8UC1) { QImage image(mat.cols, mat.rows, QImage::Format_Indexed8); image.setColorCount(256); for (int i = 0; i < 256; i++) { image.setColor(i, qRgb(i, i, i)); } uchar *pSrc = mat.data; for (int row = 0; row < mat.rows; row++) { uchar *pDest = image.scanLine(row); memcpy(pDest, pSrc, mat.cols); pSrc += mat.step; } return image; } else if (mat.type() == CV_8UC3) { const uchar *pSrc = (const uchar*)mat.data; QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888); if (image.isNull()) return QImage(); return image.rgbSwapped(); } else if (mat.type() == CV_8UC4) { const uchar *pSrc = (const uchar*)mat.data; QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32); return image.copy(); } else { qDebug() << "ERROR: Mat could not be converted to QImage."; return QImage(); } } static cv::Mat QImageToMat(QImage image) { cv::Mat mat; QImage::Format f = image.format(); switch (image.format()) { case QImage::Format_ARGB32: case QImage::Format_RGB32: case QImage::Format_ARGB32_Premultiplied: mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine()); break; case QImage::Format_RGB888: mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine()); cv::cvtColor(mat, mat, CV_BGR2RGB); break; case QImage::Format_Indexed8: case QImage::Format_Grayscale8: mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine()); break; } return mat; } Mat _EnhanImg_sharpen(const Mat &img) { int mGainValue = 3; float amount = mGainValue * 0.5f; Mat blurred; int mSmoothValue = 3; GaussianBlur(img, blurred, Size(), mSmoothValue); Mat lowContrastMask = abs(img - blurred) < 5; Mat orResult = img * (1 + amount) + blurred * (-amount); img.copyTo(orResult, lowContrastMask); Mat openMat = orResult.clone(); return openMat; } Mat findEdge2(const Mat &Src) { Mat ret = Src.clone(); Mat kernel = (Mat_(5, 5) << -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 24, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); filter2D(Src, ret, CV_8UC1, kernel); return ret; } QAlgDetect::QAlgDetect(QObject *parent) : QObject(parent) { QFunctionTransfer::Instance(); m_pThreadPool = std::make_shared(3); m_pThreadPool->init(); } QAlgDetect::~QAlgDetect() { m_pThreadPool->stop(); m_pThreadPool->wait(); } #define REAIZE 2 cv::Mat QAlgDetect::findCircle(cv::Mat srcImg, QVariantMap param) { bool bEqual = param.value("equal").toBool(); //Mat srcImg = QImageToMat(img); if(srcImg.channels()!=1) cv::cvtColor(srcImg, srcImg, CV_RGB2GRAY); Mat detectImg; Mat src = srcImg; cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE)); int bBaseX = detectImg.cols; int bBaseY = detectImg.rows; if(bEqual == true) equalizeHist(detectImg, detectImg);//根据图像的实际情况使用 图像暗一点不需要,亮一点的需要 detectImg = _EnhanImg_sharpen(detectImg); EDCircles edcircles(detectImg); vector EDCircle = edcircles.getCircles(); double maxR = 0; int nIndex = -1; for (int i = 0; i < EDCircle.size(); i++) { int startX = EDCircle[i].center.x - EDCircle[i].r; int startY = EDCircle[i].center.y - EDCircle[i].r; if (startX < 0 || startY < 0) continue; if (EDCircle[i].center.x + EDCircle[i].r > bBaseX || EDCircle[i].center.y + EDCircle[i].r > bBaseY) continue; if(EDCircle[i].r< 50 ) continue; if (EDCircle[i].r > maxR) { maxR = EDCircle[i].r; nIndex = i; } } if (nIndex != -1) { int startX = EDCircle[nIndex].center.x * REAIZE - EDCircle[nIndex].r * REAIZE; int startY = EDCircle[nIndex].center.y * REAIZE - EDCircle[nIndex].r* REAIZE; double radius = EDCircle[nIndex].r; int hight = 2 * radius * REAIZE; QPointF centerP; centerP.setX(EDCircle[nIndex].center.x * REAIZE); centerP.setY(EDCircle[nIndex].center.y * REAIZE); double r = radius * REAIZE; Mat aa = DetectCircle(srcImg, centerP, r, bEqual); return aa; } else { QPointF centerP; centerP.setX(srcImg.cols/2); centerP.setY(srcImg.rows/2); double r = 0; Mat aa = DetectCircle(srcImg, centerP, r, bEqual); return aa; } } bool QAlgDetect::detect(QImage img, QVariantMap param, AlgResultCallBack func) { Mat srcImg = QImageToMat(img); if (srcImg.channels() != 1) cv::cvtColor(srcImg, srcImg, CV_RGB2GRAY); Task task = std::bind(&QAlgDetect::taskFunc, this, srcImg.clone(), param, func); m_pThreadPool->AddNewTask(task); return true; } Mat QAlgDetect::DetectCircle(Mat img, QPointF center, double radius,bool bEqual) { Mat detectImg; if(bEqual == true) equalizeHist(img, detectImg); else detectImg = img; CircleDetector cd; cd.setAlgoType(CircleDetector::PeakCircle); cd.setEdgeWidth(3); cd.setPolarity(Polarity::White2Black); cd.setFindBy(FindBy::Best); double difRadiusMin = radius - 100; double difRadiusMax = radius + 150; if (difRadiusMin < 0) { difRadiusMin = 0; if (radius > 0) { difRadiusMax = abs(center.y() - (img.cols / 2)) - 50; } else { int minV = (img.rows / 2) > (img.cols / 2) ? (img.cols / 2) : (img.rows / 2); difRadiusMax = minV - 50; center.setX(img.cols / 2); center.setY(img.rows / 2); } } cd.setRadii(difRadiusMin, difRadiusMax); cd.setACThres(3); vector allScores; Vec3f bestCircle; float bestScore = cd.detectBest(detectImg, Point2f(center.x(), center.y()), bestCircle, &allScores); if (abs(bestScore) <= FLT_EPSILON || bestCircle == Vec3f::zeros()) { return Mat(); } QPointF cen(bestCircle[0], bestCircle[1]); double r = bestCircle[2]; Rect rect; rect.x = cen.x() - r; rect.y = cen.y() - r; if (rect.x < 0) rect.x = 0; if (rect.y < 0) rect.y = 0; rect.width = 2 * r; rect.height = 2 * r; Mat s = img(rect); return s; } QString QAlgDetect::matchTemplate(const QMap* modelMap, cv::Mat detectImg, double* pMinDis /*= NULL*/, int minDisNum /*= -1*/) const { double minDis = DBL_MAX; QString bestName = "NG"; vector disVec(modelMap->size()); int nIndex = 0; if (!modelMap) return bestName; QStringList strDetectModels = modelMap->keys(); 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; QString name = strModelName; ICompareModel* pModel = pWheel->getImageComModel(); if (pModel->getBaseImg().data == NULL) { nIndex++; continue; } pModel->setIsEnableCache(false); double dis = pModel->compare(detectImg, NULL, true, 1); double disThre = pModel->getDisThre(); double innerCircleNum = pModel->getInnerCircleNum(); if (dis < disThre) { 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); } return bestName; } void QAlgDetect::taskFunc(cv::Mat srcImg, QVariantMap param, AlgResultCallBack func) { double dStart = cv::getTickCount(); QVariantMap rltMap; cv::Mat circleMat = findCircle(srcImg, param); long long modelMapPtr = param.value("modelMap").toLongLong(); QMap *ptr = (QMap*)modelMapPtr; if (!circleMat.empty()&&ptr&&ptr->size()>0) { vector minDisVec(ptr->size()); QString strName = matchTemplate(ptr, circleMat, &(minDisVec[0]), minDisVec.size()); rltMap.insert("modeName", strName); rltMap.insert("minDis", minDisVec[0]); if (ptr->contains(strName) && ptr->value(strName)->getImageComModel()) { ICompareModel *pModel = ptr->value(strName)->getImageComModel(); double d = pModel->getDisThre(); double dValue = (d - minDisVec[0]) / d * 0.4 + 0.6; rltMap.insert("score", dValue); } } QImage srcImage = cvMat2QImage(srcImg); QImage resultImage = cvMat2QImage(circleMat); rltMap.insert("SrcImage", srcImage); rltMap.insert("ResImage", resultImage); double dTime = (cv::getTickCount() - dStart) / cv::getTickFrequency(); rltMap.insert("runTime", dTime); if (func) { QFunctionTransfer::Instance()->execInMain([this, rltMap, func]() { if (func) func(rltMap); }); } }