#include "ValveDetector.h" #include #include "patterndetector.h" using namespace luffy_base; ValveDetector::ValveDetector() { luffy_triangle::createNewTrigValue(3600); } ValveDetector::~ValveDetector() { } enum detectMode { shootWheelExist = 0, shootTargetMatch = 1 }; void remove(Mat &img, int fValveWidth) { int nStep = 20; int nOffset = 30; float fThres = 0.8; Mat imgDst; cv::threshold(img, imgDst, 1, 255.0, THRESH_OTSU); Mat imgHalf; Rect ret = Rect(0, imgDst.rows / 2 + nOffset, imgDst.cols, imgDst.rows / 2 - nOffset); if (ret.y > imgDst.rows || (imgDst.rows / 2 + nOffset + imgDst.rows / 2 - nOffset) > imgDst.rows) return; imgDst(ret).copyTo(imgHalf); Mat imgProj; luffy_projection::project2axis(imgHalf, imgProj, luffy_projection::emProjX, cv::NORM_MINMAX); Mat imgBlob(1, imgProj.cols, CV_8UC1); imgBlob.setTo(0); float *pProj = imgProj.ptr(0); uchar *pBlob = imgBlob.ptr(0); for (int i = 0; i < imgProj.cols; i++) { if (pProj[i] >= fThres) { pBlob[i] = 255; int offset = 120; int nIndex = 0; bool bLineMode = false; for (int j = 0; j < offset; j++) { int nX = i + offset - j; nX = nX % imgProj.cols; if (bLineMode) { pBlob[nX] = 255; } else { if (pProj[nX] >= fThres) { bLineMode = true; nIndex = i + offset - j; } } } if (bLineMode) { if (nIndex >= imgProj.cols) { break; } else { i = nIndex; } } } } for (int i = 0; i < imgProj.cols; i++){ if (pBlob[i] != 0) { img.col(i).setTo(0); } } } Point getNextMinMax(Mat *img, Point maxLoc, double minVal, InputParam InputParameter) { int templateH = InputParameter.barTemplate.rows; int templateW = InputParameter.barTemplate.cols; int startX = maxLoc.x - templateW / 2; int startY = 0; int endX = maxLoc.x + templateW / 2; int endY = img->rows - 1; if (startX < 0 || startY < 0) { startX = 0; startY = 0; } if (endX > img->cols - 1 || endY >img->rows - 1) { endX = img->cols - 1; endY = img->rows - 1; } for (int y = startY; y < endY + 1; y++) { float* fPtr = (float*)img->row(y).data; for (int x = startX; x <= endX; x++) { fPtr[x] = minVal; } } double minValue, maxValue; Point iminLoc, imaxLoc; minMaxLoc(*img, &minValue, &maxValue, &iminLoc, &imaxLoc); return imaxLoc; } void findCandidateValsInMat(const Mat &_img, vector &canPoints, InputParam InputParameter) { Mat result = _img.clone(); double minVal, maxVal; Point minLoc, maxLoc; minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); canPoints.push_back(maxLoc); int barNum = InputParameter.barNum; if (barNum <=0) { qWarning() << "burNum cannot be negatIve or ZERO"; return; } int maxLength = InputParameter.nMaxAngle; int interval = maxLength / barNum; for (int i = 1; i < barNum; i++) { int nextLoc = maxLoc.x + (i*interval); if (nextLoc >= maxLength) { nextLoc = nextLoc % maxLength; } canPoints.push_back(Point(nextLoc, 0)); } /*Point next_maxPoint; next_maxPoint = getNextMinMax(&result, maxLoc, minVal, InputParameter); canPoints.push_back(next_maxPoint); next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter); canPoints.push_back(next_maxPoint); next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter); canPoints.push_back(next_maxPoint); next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter); canPoints.push_back(next_maxPoint);*/ /*next_maxPoint = getNextMinMax(&result, next_maxPoint, minVal, InputParameter); canPoints.push_back(next_maxPoint);*/ } void findOffsets(InputParam in, const vector & canVec, vector & detectOffset) { int barNum = in.barNum; if (barNum <=0) { qWarning() << "barNum cannot be negative or ZERO"; return; } int maxLength = in.nMaxAngle; int withinOffset = in.withinOffset; int width = in.barTemplate.cols; for (int i = 0; i < barNum; i++) { float barX = canVec[i].x + width / 2.0; float holeX = barX + withinOffset; if (holeX > maxLength) { //holeX = holeX % maxLength; holeX = fmod(holeX, (double)maxLength); } detectOffset.push_back(holeX); } } void creatMask(const Mat &img2Rect, const vector &offsetVec, InputParam paramIn, Mat &iMask) { int smallMove = 20; for (int i = 0; i < offsetVec.size(); i++) { int holeX = offsetVec[i]; int width = paramIn.imgTemplate.cols + 2*smallMove; int startX = holeX - paramIn.imgTemplate.cols / 2 - smallMove; if (startX < 0) { int offset = abs(startX); startX = paramIn.nMaxAngle - offset; //iMask(Rect(startX, 0, offset, img2Rect.rows)).setTo(255); } if (startX + paramIn.imgTemplate.cols + 2*smallMove> paramIn.nMaxAngle) { width = paramIn.nMaxAngle - startX; int offset = startX + paramIn.imgTemplate.cols + 2*smallMove- paramIn.nMaxAngle; iMask(Rect(0, 0, offset, img2Rect.rows)).setTo(255); } Rect candidateRoi(startX, 0, width, img2Rect.rows); iMask(candidateRoi).setTo(255); } } void genSobelImage1(Mat& img, Mat* pSobelx /*= NULL*/, Mat* pSobely /*= NULL*/) { Mat sobelx, sobely; Sobel(img, sobelx, CV_32FC1, 1, 0); Sobel(img, sobely, CV_32FC1, 0, 1); img = sobelx.mul(sobelx) + sobely.mul(sobely); Mat tempImg; img.convertTo(tempImg, CV_32FC1); Mat tempImg0; sqrt(tempImg, tempImg0); img = tempImg0; if (pSobelx) { *pSobelx = sobelx; } if (pSobely) { *pSobely = sobely; } } cv::Mat getSobelDir(const Mat& sobelX, const Mat& sobelY) { Mat img(sobelX.rows, sobelX.cols, CV_16UC1); for (int i = 0; i < img.rows; ++i) { Mat row = img.row(i); float* pDataX = (float*)sobelX.row(i).data; float* pDataY = (float*)sobelY.row(i).data; ushort* pData = (ushort*)row.data; for (int j = 0; j < img.cols; ++j) { float dx = pDataX[j]; float dy = pDataY[j]; float angle = 0; if (dx == 0 && dy == 0) { angle = 0; } else { angle = atan2f(dy, dx); if (angle < 0) { angle += 2.0 * M_PI; } } pData[j] = floorf((angle / M_PI) * 180); } } return img; } void genSobelDir1(Mat& img) { Mat srcImg = img.clone(); Mat sobelX, sobelY; genSobelImage1(srcImg, &sobelX, &sobelY); img = getSobelDir(sobelX, sobelY); } void histMeanStddev(const Mat& hist, double* pMean, double* pStddev) { float * pData = (float*)hist.data; double sum = 0; int count = 0; for (int i = 0; i < hist.cols; ++i) { if (!pData[i]) { continue; } count += pData[i]; sum += pData[i] * i; } if (count == 1) { if (pMean) { *pMean = sum; } if (pStddev) { *pStddev = 0; } return; } *pMean = sum / (double)count; sum = 0; for (int i = 0; i < hist.cols; ++i) { if (!pData[i]) { continue; } double d = i - *pMean; sum += d*d*pData[i]; } *pStddev = sqrt(sum / (double)(count - 1)); } double tempScoreShoot(Mat &_img, Mat &template_img, detectMode mode) { //qDebug() << "tempScoreShoot"; double dis = 0.0; Mat templateDir = template_img.clone(); Mat temporaryDir = _img.clone(); //temporaryDir = temporaryDir(Rect(0, 30, temporaryDir.cols, temporaryDir.rows - 30)); Mat normTemplateDir, normTemporaryDir; Mat blurredTempl, blurredTempo; cv::GaussianBlur(templateDir, blurredTempl, Size(3, 3), 5.0); cv::GaussianBlur(temporaryDir, blurredTempo, Size(3, 3), 5.0); luffy_imageProc::meanvarnorm(blurredTempl, normTemplateDir, 120, 50); luffy_imageProc::meanvarnorm(blurredTempo, normTemporaryDir, 120, 50); // normTemplateDir.convertTo(normTemplateDir, CV_16UC1); // normTemporaryDir.convertTo(normTemporaryDir, CV_16UC1); normTemplateDir.convertTo(normTemplateDir, CV_32F); normTemporaryDir.convertTo(normTemporaryDir, CV_32F); genSobelDir1(normTemplateDir); genSobelDir1(normTemporaryDir); Mat templateHist, temporaryHist, magHist; float range[] = { 0, 360 }; const float * histRange = { range }; int histSize = 36; calcHist(&normTemplateDir, 1, 0, Mat(), templateHist, 1, &histSize, &histRange, true, false); calcHist(&normTemporaryDir, 1, 0, Mat(), temporaryHist, 1, &histSize, &histRange, true, false); #ifdef VEIW_HISTGRAM Mat dstImage = Mat::zeros(512, 800, CV_8UC3); //normalize(templateHist, templateHist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); //normalize(temporaryHist, temporaryHist, 0, histImage.rows, NORM_MINMAX, -1, Mat()); double max = 0; double max1 = 0; minMaxLoc(templateHist, NULL, &max, 0, 0); minMaxLoc(temporaryHist, NULL, &max1, 0, 0); max = MAX(max, max1); double bin_w = (double)dstImage.cols / histSize; // the interval of every bin double bin_u = (double)dstImage.rows / max; //// the maximal height // draw histGram for (int i = 0; i < histSize; i++) { Point p0 = Point(i*bin_w, dstImage.rows); int val = templateHist.at(i); int val1 = temporaryHist.at(i); Point p1 = Point((i + 1)*bin_w, dstImage.rows - val*bin_u); Point p2 = Point((i + 1)*bin_w, dstImage.rows - val1*bin_u); rectangle(dstImage, p0, p1, Scalar(0, 255), 1, 8, 0); rectangle(dstImage, p0, p2, Scalar(0, 0, 255), 1, 8, 0); //imshow("image", dstImage); } char string[12]; int yAxis = 0; for (int i = 1; yAxis < max; i++) { yAxis = i*max / 10; itoa(yAxis, string, 10); cv::putText(dstImage, string, Point(0, dstImage.rows - yAxis*bin_u), 1, 1, Scalar(0, 255, 255)); } int xAxis = 0; for (int i = 1; xAxis < 360; i++) { xAxis = i * 20; itoa(xAxis, string, 10); cv::putText(dstImage, string, Point(xAxis*(dstImage.cols / 360), dstImage.rows), 1, 1, Scalar(0, 255, 255)); } #endif // VEIW_HISTGRAM switch (mode) { case shootWheelExist: { /* double templMean, templStddev, tempoMean, tempoStddev; transpose(templateHist, templateHist); transpose(temporaryHist, temporaryHist); histMeanStddev(templateHist, &templMean, &templStddev); histMeanStddev(temporaryHist, &tempoMean, &tempoStddev); double meanDiff = abs(templMean - tempoMean); double stddevDiff = abs(templStddev - tempoStddev); if (meanDiff > 1.5 || stddevDiff > 1.5) { qDebug() << "there is no wheel exist"; return 0; } else { qDebug() << "wheel exists"; return 1; }*/ } case shootTargetMatch: { qDebug() << "start get matchScore:" ; double templCount = cv::sum(templateHist.rowRange(12, 25)).val[0]; double temporCount = cv::sum(temporaryHist.rowRange(12, 25)).val[0]; dis = temporCount / templCount; if (dis > 0.60) { if (dis > 1) { dis = 1; qDebug() << "matchScore:" << dis; return dis; } else { qDebug() << "matchScore:" << dis; return dis; } } qDebug() << "fail to find the targetMatch"; return 0; } } qDebug() << "end tempScoreShoot"; return 0; } cv::Mat LoopRoi(Mat &src, int x, int nWidth) { Mat dst; if (x + nWidth > src.cols) { if (src.type() == CV_8UC1) { dst.create(Size(nWidth, src.rows), CV_8UC1); } else { dst.create(Size(nWidth, src.rows), CV_32FC1); } src(Rect(x, 0, src.cols - x, src.rows)).copyTo(dst(Rect(0, 0, src.cols - x, src.rows))); src(Rect(0, 0, nWidth - src.cols + x, src.rows)).copyTo(dst(Rect(src.cols - x, 0, nWidth - src.cols + x, src.rows))); } else { Rect roi(x, 0, nWidth, src.rows); src(roi).copyTo(dst); } return dst; } cv::Point2f ValveDetector::getCenterPoints(Mat &_Img, const Mat ¢erTempl, InputParam paramIn, Point2f pt, Mat & rstMat) {//中心定位功能 0关闭 1开启 if (0 == paramIn.nCenterAlg) { return pt; } if (paramIn.wheelType == 1) { if (paramIn.backGround.empty()) { return pt; } else { Record_List roiRecord = paramIn.roi.records; int nRoiCount = roiRecord.size(); if (nRoiCount > 0) { Item_List itemRoi = roiRecord.front(); int width = abs(itemRoi.front().second.at(2)); int height = abs(itemRoi.front().second.at(3)); int corr_x = itemRoi.front().second.at(0) - width / 2.0; int corr_y = itemRoi.front().second.at(1) - height / 2.0; Rect rect = Rect(corr_x, corr_y, width, height); Mat roiMat = _Img(rect); Mat backCandidateMat = paramIn.backGround(rect); //Mat forMat = abs(roiMat - backCandidateMat); luffy_base::luffyCircle pCircle; findCircleObject(roiMat, backCandidateMat, paramIn.backgroundThresh, &pCircle); rstMat = findCircleObject(_Img, paramIn.backGround, paramIn.backgroundThresh, NULL); float axis_x = corr_x + pCircle.ptCenter.x; float axis_y = corr_y + pCircle.ptCenter.y; return Point2f(axis_x, axis_y); } } luffy_base::luffyCircle pCircle; rstMat = findCircleObject(_Img, paramIn.backGround, paramIn.backgroundThresh, &pCircle); qDebug() << "get image"; return pCircle.ptCenter; } else { Mat centerMatch; int nOffset = 80; //need int templW = centerTempl.cols; int templH = centerTempl.rows; int nStartX = pt.x - templW / 2 - nOffset; int nStartY = pt.y - templH / 2 - nOffset; if (nStartX<0||nStartY<0) return Point2f(0, 0); if ((2 * nOffset + templH)>_Img.rows) return Point2f(0, 0); if ((2 * nOffset + templW)>_Img.cols) return Point2f(0, 0); if ((2 * nOffset + templH+nStartY) > _Img.rows) return Point2f(0, 0); if ((2 * nOffset + templW+nStartX) > _Img.cols) return Point2f(0, 0); Mat imgRoi; _Img(Rect(pt.x - templW / 2 - nOffset, pt.y - templH / 2 - nOffset, 2 * nOffset + templW, 2 * nOffset + templH)).copyTo(imgRoi); matchTemplate(imgRoi, centerTempl, centerMatch, CV_TM_CCOEFF_NORMED); Point p; double v = luffy_math::getMinMaxData(centerMatch, luffy_math::emDataMax, &p); int localCenterX = p.x + templW / 2; int localCenterY = p.y + templH / 2; int newCenterX = pt.x - templW / 2 - nOffset + localCenterX; int newCenterY = pt.y - templH / 2 - nOffset + localCenterY; /*Mat img1 = _Img.clone(); Mat img2 = _Img.clone(); Mat img3 = _Img.clone(); vector imgs; imgs.push_back(img1); imgs.push_back(img2); imgs.push_back(img3); Mat rst; merge(imgs, rst); cv::circle(rst, Point(newCenterX, newCenterY), 3, Scalar(255), -1);*/ return Point2f(newCenterX, newCenterY); } } cv::Mat ValveDetector::getForeImage(const Mat & src, const Mat &backgroundImg) { Mat resizedBackgroundImg = backgroundImg; if (backgroundImg.size() != src.size()) { resize(backgroundImg, resizedBackgroundImg, src.size()); } qDebug() << src.cols << "" << src.rows << "" << resizedBackgroundImg.cols << "" << resizedBackgroundImg.rows; qDebug() << src.channels() << "" << resizedBackgroundImg.channels(); Mat h = src - resizedBackgroundImg; qDebug() << "h pass"; return (src - resizedBackgroundImg); } cv::Mat ValveDetector::findCircleObject(const Mat &src, const Mat& backgroundImg, int nThres, luffy_base::luffyCircle *pCircle) { if (src.empty() || backgroundImg.empty() || src.rows < 500) { return Mat(); } assert(backgroundImg.type() == CV_8UC1); Mat imgTmp, imgBinary; const cv::Size cSize = cv::Size(ALG_RESIZE_IMAGE_WIDTH, floorf(ALG_RESIZE_IMAGE_WIDTH / (float)src.cols*(float)src.rows)); cv::resize(src, imgTmp, cSize); Mat foregroundImg = getForeImage(imgTmp, backgroundImg);// 0421 using namespace luffy_base; luffy_threshold::Threshold(foregroundImg, imgBinary, nThres);//0421 //luffy_threshold::Threshold(imgTmp, imgBinary, nThres); Mat dilatedImgBin; dilate(imgBinary, dilatedImgBin, Mat::ones(7, 7, CV_32FC1)); erode(dilatedImgBin, imgBinary, Mat::ones(7, 7, CV_32FC1)); erode(imgBinary, imgBinary, Mat::ones(1, 13, CV_32FC1)); dilate(imgBinary, imgBinary, Mat::ones(1, 13, CV_32FC1)); vector> conts; cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE); imgBinary.setTo(0); for (int i = 0; i < conts.size(); i++) { const vector &pt = conts.at(i); if (pt.size() < 20) { continue; } Rect rt = boundingRect(pt); if (rt.width < 5 || rt.height < 5) { continue; } drawContours(imgBinary, conts, i, Scalar::all(255), -1); } Mat hit; vector pts; luffy_hit::firstHit4Circle(imgBinary, hit, pts, Point(cSize.width / 2, cSize.height / 2), 0, cSize.width / 2, 360, luffy_hit::emHitOut2In); qDebug() << "image8"; //luffy_imageProc::RansacParam rs(0.02, 2.5, 70, 100, 220); luffy_imageProc::RansacParam rs(0.01, 3, 200, 150, 240);//0421 vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); #ifdef _DEBUG Mat imgColor; cv::cvtColor(imgTmp, imgColor, CV_GRAY2BGR); for (int i = 0; i < pts.size(); i++) { imgColor.at(pts.at(i))[0] = 255;//B imgColor.at< cv::Vec3b >(pts.at(i))[1] = 0;//G imgColor.at< cv::Vec3b >(pts.at(i))[2] = 0;//R } for (int i = 0; i < pts2.size(); i++) { imgColor.at(pts2.at(i))[0] = 0;//B imgColor.at< cv::Vec3b >(pts2.at(i))[1] = 0;//G imgColor.at< cv::Vec3b >(pts2.at(i))[2] = 255;//R } #endif float fRadius; Point2f ptCenter; bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); qDebug() << "image9"; if (!bFind) { return Mat(); } Mat dst; const int nOffset = 1; fRadius += nOffset; Rect rt(ptCenter.x - fRadius + nOffset, ptCenter.y - fRadius + nOffset, 2 * fRadius, 2 * fRadius); rt &= Rect(0, 0, imgTmp.cols, imgTmp.rows); imgTmp(rt).copyTo(dst); static int nCount = cv::getTickCount(); if (pCircle) { float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH; Mat matBig = src - backgroundImg;//0421 //Mat matBig = src; pCircle->fRadius = fRadius * fScale; pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale); Mat matBinary; luffy_threshold::Threshold(matBig, matBinary, nThres); Mat hit; vector pts; luffy_hit::firstHit4Circle(matBinary, hit, pts, pCircle->ptCenter, 0, pCircle->fRadius + 10, 360, luffy_hit::emHitOut2In); luffy_imageProc::RansacParam rs(0.01, 2.5, 200, 150, 220); vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); float fRadius2; Point2f ptCenter2; bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius2, ptCenter2); if (bFind) { pCircle->fRadius = fRadius2; pCircle->ptCenter = ptCenter2; Rect rt(ptCenter2.x - fRadius2 + nOffset, ptCenter2.y - fRadius2 + nOffset, 2 * fRadius2, 2 * fRadius2); if (rt.x < 0 || rt.y < 0 || rt.x + rt.width > matBinary.cols || rt.y + rt.height > matBinary.rows) { return Mat(); } rt &= Rect(0, 0, matBinary.cols, matBinary.rows); src(rt).copyTo(dst); int nWidth = ((int)((double)dst.cols / fScale / 4)) * 4; cv::resize(dst, dst, cv::Size(nWidth, nWidth)); } } return dst; } bool isRequiredModel(Mat &_img, InputParam ¶mIn) { int notSatisified = 0; Mat imgRect = _img.clone(); Mat rstImage; luffy_match::LoopMatMatch(imgRect, imgRect, luffy_match::emLoopMatX, rstImage); int interval = floor(paramIn.nMaxAngle / paramIn.barNum); double minVal, maxVal; Point minLoc, maxLoc; cv::minMaxLoc(rstImage, &minVal, &maxVal, &minLoc, &maxLoc); vector loc; loc.push_back(maxLoc.x); Point getMaxLoc; for (int i = 1; i < paramIn.barNum + 1; i++) { getMaxLoc = getNextMinMax(&rstImage, maxLoc, 0, paramIn); maxLoc = getMaxLoc; loc.push_back(getMaxLoc.x); } std::sort(loc.begin(), loc.end()); for (int j = 0; j < loc.size(); j++) { if (j + 1 >= 7) { break; } int diff = loc[j + 1] - loc[j]; int interDiff = abs(diff - interval); if (interDiff > 10) { notSatisified++; } } if (notSatisified > 2) { return false; } else { return true; } } void getTargetPosAndVal(const Mat &img, InputParam &in, double &val, int &nPos) { vector diffVec; vector vec; vec.resize(in.barNum); diffVec.resize(in.barNum); Mat result = img.clone(); double minVal, maxVal; Point minLoc, maxLoc; minMaxLoc(result, &minVal, &maxVal, &minLoc, &maxLoc); int maxLength = in.nMaxAngle; int interval = in.nMaxAngle / in.barNum; int barX = maxLoc.x + in.barTemplate.cols / 2; barX = barX % maxLength; int valveOffset = in.nValveOffset; diffVec[0] = abs(barX - valveOffset); vec[0] = barX; for (int i = 1; i < diffVec.size(); i++) { int vOffset = barX + interval*i; if (vOffset >=in.nMaxAngle) { vOffset = vOffset % maxLength; } diffVec[i] = abs(vOffset - valveOffset); vec[i] = vOffset; } size_t valIndex = std::min_element(diffVec.begin(), diffVec.end()) - diffVec.begin(); nPos = vec[valIndex]; val = maxVal; //nPos = barX; } int roiCandidateMatch(const vector &vec, Mat templ) { vector candidateVal; candidateVal.resize(vec.size()); for (int i = 0; i < vec.size(); ++i) { Mat roi = vec[i]; Mat roiMatch; luffy_match::LoopMatMatch(roi, templ, luffy_match::emLoopMatX, roiMatch); Point pt3; double v3 = luffy_math::getMinMaxData(roiMatch, luffy_math::emDataMax, &pt3); candidateVal[i] = v3; } auto val = std::max_element(candidateVal.begin(), candidateVal.end()); int index = std::distance(candidateVal.begin(), val); return index; } bool imageRotateMatch(Mat & imgSrc, InputParam ¶mIn, OutputParam ¶mOut, vector candidatePoints) { float templateAngle = paramIn.nValveOffset / paramIn.nMaxAngle * 360; Mat imgTemplate = paramIn.imgTemplate; vector templates; templates.resize(360); int rotateOffset = 15; int x = imgTemplate.cols / 2 - rotateOffset; int y = imgTemplate.rows / 2 - rotateOffset; int width = imgTemplate.cols - 2 * x; int height = imgTemplate.rows - 2 * y; Rect rect = Rect(x, y, width, height); for (int i = templateAngle, j = 0; i < 360 + templateAngle, j < 360; ++i, ++j) { i = i % 360; Mat transMat = getRotationMatrix2D(Point2f(imgTemplate.cols / 2.0, imgTemplate.rows / 2.0), j, 1.0); Mat dst; warpAffine(imgTemplate, dst, transMat, imgTemplate.size()); Mat dstRoi = dst(rect); templates[i] = dstRoi; } vector> candiateAngleRange; candiateAngleRange.resize(candidatePoints.size()); int nOffSet = 0; for (int x = 0; x < candidatePoints.size(); ++x) { float startIndex = candidatePoints[x] - templates[0].cols / 2.0 - nOffSet; startIndex = luffy_math::mod(startIndex, paramIn.nMaxAngle); float holeStartAngle = startIndex / paramIn.nMaxAngle * 360; float endIndex = candidatePoints[x] + templates[0].cols + nOffSet; float holeEndAngle = 0.0; if (endIndex > paramIn.nMaxAngle) { holeEndAngle = fmod(endIndex, paramIn.nMaxAngle) / paramIn.nMaxAngle * 360; } else { holeEndAngle = endIndex / paramIn.nMaxAngle * 360; } candiateAngleRange[x].push_back(holeStartAngle); candiateAngleRange[x].push_back(holeEndAngle); } float fvalveWidth = paramIn.fValveWidth; float fvalveDis = paramIn.fValveDis; Point wheelCenter = paramIn.ptCenter; int offset = 30; Mat srcImg = imgSrc.clone(); int outterRadius = fvalveDis + offset; int innerRadius = fvalveDis - offset; Mat wheelRoi = srcImg(Rect(wheelCenter.x - outterRadius, wheelCenter.y - outterRadius, outterRadius * 2, outterRadius * 2)); Mat wheelRoiMask(wheelRoi.size(), wheelRoi.type(), Scalar::all(0)); cv::circle(wheelRoiMask, Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), outterRadius, Scalar::all(255), -1); cv::circle(wheelRoiMask, Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), innerRadius, Scalar::all(0), -1); Mat selectRoi = (wheelRoiMask / 255).mul(wheelRoi); /*vector imgs; Mat img1 = selectRoi.clone(); Mat img2 = selectRoi.clone(); imgs.push_back(selectRoi); imgs.push_back(img2); imgs.push_back(img1); Mat showImage; showImage.setTo(0); merge(imgs, showImage);*/ /*std::map valToLoc;*/ ////qDebug() << "start"; //float sumVal = 0; Point p = Point(0, 0); float maxVal = _I32_MIN; float m_Index = 0.0; Mat roi; roi.setTo(0); for (int k = 0; k < selectRoi.rows; ++k) { //uchar *ptr = selectRoi.row(k).data; for (int m = 0; m < selectRoi.cols; ++m) { //qDebug() << "k:" << k << "m :" << m ; float dis = luffy_math::disofPoints(Point2f(m, k), Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0)); if (dis > outterRadius || dis < innerRadius) { continue; } float nIndex = luffy_math::caculAngle(Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0), Point2f(m, k)); int flag = false; for (int y = 0; y < candiateAngleRange.size(); ++y) { if (candiateAngleRange[y][0] > candiateAngleRange[y][1]) { if ((nIndex >= candiateAngleRange[y][0] && nIndex < 360) || (nIndex >=0 && nIndex <=candiateAngleRange[y][1])) { const Mat& templ = templates[nIndex]; int nwidth = templ.cols; int nheight = templ.rows; if ((m + nwidth >= outterRadius * 2) || (k + nheight > outterRadius * 2)) { continue; } Mat matchRoi = selectRoi(Rect(m, k, nwidth, nheight)); Mat val; cv::matchTemplate(matchRoi, templ, val, CV_TM_CCOEFF_NORMED); //float val = norm(matchRoi, templ, NORM_L2); if (val.at(0, 0) > maxVal) { maxVal = val.at(0, 0); p = Point(m, k); m_Index = nIndex; roi = matchRoi; } } } if (nIndex >= candiateAngleRange[y][0] && nIndex <= candiateAngleRange[y][1]) { //selectRoi.at(k, m) = 0; const Mat& templ = templates[nIndex]; int nwidth = templ.cols; int nheight = templ.rows; if ((m + nwidth >= outterRadius * 2) || (k + nheight > outterRadius * 2)) { continue; } Mat matchRoi = selectRoi(Rect(m, k, nwidth, nheight)); Mat val; cv::matchTemplate(matchRoi, templ, val, CV_TM_CCOEFF_NORMED); //float val = norm(matchRoi, templ, NORM_L2); if (val.at(0, 0) > maxVal) { maxVal = val.at(0, 0); p = Point(m, k); m_Index = nIndex; roi = matchRoi; } } } } } Point2f pLoc = Point2f(p.x + templates.front().cols / 2.0, p.y + templates.front().rows / 2.0); paramOut.rstPoint = paramIn.ptCenter + pLoc - Point2f(wheelRoi.cols / 2.0, wheelRoi.rows / 2.0); paramOut.dAngleRes = m_Index; paramOut.dScore = maxVal; paramIn.fValveWidth = templates.front().cols / 2.0; //cv::rectangle(showImage, p, Point(p.x + templates[0].cols, p.y + templates[0].rows), Scalar(0, 0, 255), 2, 8, 0); double disVal = tempScoreShoot(roi, templates[55], detectMode::shootTargetMatch); return true; } bool ValveDetector::detect(Mat & imgSrc, InputParam ¶mIn, OutputParam ¶mOut, Mat &imgDst /*= Mat()*/) { int rtWidth = 100; if (paramIn.ptCenter.x - rtWidth < 0 || paramIn.ptCenter.y - rtWidth < 0) return false; if (paramIn.ptCenter.x + 2 * rtWidth > imgSrc.cols) return false; if (paramIn.ptCenter.y + 2 * rtWidth>imgSrc.rows) return false; if (paramIn.barNum <= 0) return false; cv::Mat imgCenter = imgSrc(Rect(paramIn.ptCenter.x - rtWidth, paramIn.ptCenter.y - rtWidth, 2 * rtWidth, 2 * rtWidth)); Scalar scMean = cv::mean(imgCenter); if (scMean[0] < 20) { paramOut.dAngle = 3610; paramOut.dScore = 0; } else { float fValveWidth = paramIn.fValveWidth; float fValveDis = paramIn.fValveDis; int offset = 10; int nImgHeight = fValveWidth * 2 + 2 * offset; Mat img2Rect; paramIn.ptCenter = Point(paramIn.ptCenter.x , paramIn.ptCenter.y); luffy_math::polar2rect(imgSrc, img2Rect, paramIn.ptCenter, fValveDis - nImgHeight / 2, fValveDis + nImgHeight / 2, paramIn.nMaxAngle); Mat imgMatch, barCompare; if (paramIn.flagCircle == 1 ) { luffy_match::LoopMatMatch(img2Rect, paramIn.barTemplate, luffy_match::emLoopMatX, barCompare); double score = 0; int tarPos; getTargetPosAndVal(barCompare, paramIn, score, tarPos);//计算角度和分数 paramOut.dAngle = tarPos; paramOut.dScore = score; } else { luffy_match::LoopMatMatch(img2Rect, paramIn.barTemplate, luffy_match::emLoopMatX, barCompare); vector candidatePoints; findCandidateValsInMat(barCompare, candidatePoints, paramIn); int bIsNotStatisfy = 0; Mat imgRect = img2Rect.clone(); for (int i = 0; i < candidatePoints.size(); i++) { int rectW = paramIn.barTemplate.cols; int rectH = img2Rect.rows; if ((candidatePoints[i].x + rectW) > img2Rect.cols) { rectW = img2Rect.cols - candidatePoints[i].x; int leftOffset = candidatePoints[i].x + paramIn.barTemplate.cols - img2Rect.cols; img2Rect(Rect(0, 0, leftOffset, rectH)).setTo(0); } Rect rToBeErease(candidatePoints[i].x, 0, rectW, rectH); img2Rect(rToBeErease).setTo(0); Mat barRoi = LoopRoi(barCompare, candidatePoints[i].x, paramIn.barTemplate.cols); double dx = luffy_math::getMinMaxData(barRoi, luffy_math::emDataMax); if (dx < paramIn.nBarScore / 100.0) { bIsNotStatisfy++; } } if (bIsNotStatisfy < 2) { vector detectedOffset; findOffsets(paramIn, candidatePoints, detectedOffset); //Mat iMask(img2Rect.size(), img2Rect.type(), Scalar::all(0)); //creatMask(img2Rect, detectedOffset, paramIn, iMask); vector vecImg; int nOffset = 10; for (int i = 0; i < detectedOffset.size(); i++) { int nStart = detectedOffset.at(i) - paramIn.imgTemplate.cols / 2.0 - nOffset; nStart = luffy_math::mod(nStart, paramIn.nMaxAngle); Mat roi = LoopRoi(imgRect, nStart, paramIn.imgTemplate.cols + 2 * nOffset); Mat roi2 = roi(Rect(0, 0, roi.cols, roi.rows *3.0 / 5)); // Mat roi3; // float m = 128; float d = 70.0; // luffy_imageProc::meanvarnorm(roi2, roi3, m, d); if (paramIn.wheelType == 0) { vecImg.push_back(roi2); } else { vecImg.push_back(roi); } } // FOR MOTORCIRCLE PROGRAM START Mat ret(vecImg.size(), vecImg.size(), CV_32FC1, Scalar(0)); for (int i = 0; i < vecImg.size(); i++) { for (int j = 0; j < vecImg.size(); j++) { Mat imgMatch2; Point pt; Mat templ; luffy_match::LoopMatMatch(vecImg.at(i), vecImg.at(j), luffy_match::emLoopMatY, imgMatch2); double v = luffy_math::getMinMaxData(imgMatch2, luffy_math::emDataMax, &pt); ret.at(i, j) = v; } } float fMin = 1000; int nIndex = 0; std::map scoreMapIndex; for (int i = 0; i < ret.cols; i++) { float fSum = sum(ret.col(i))[0]; scoreMapIndex[fSum] = i; if (fSum < fMin) { fMin = fSum; nIndex = i; } } std::map::iterator it = scoreMapIndex.begin(); int candidateIndex = 0; int ni = 0; for (; it != scoreMapIndex.end(); ++it, ++ni) { if (ni == 1) { candidateIndex = it->second; } } //FOR MOTORCIRCLE END double mcutOffset = 1.0; float ss = 0.0; if (paramIn.wheelType == 0) { mcutOffset = 2.0; // FOR MOTORCIRCLE PROGRAM START Mat imgTemplate = paramIn.imgTemplate(Rect(0, 0, paramIn.imgTemplate.cols, paramIn.imgTemplate.rows / mcutOffset)); Mat ret0; matchTemplate(vecImg[nIndex], imgTemplate, ret0, CV_TM_CCORR_NORMED); Point p0; double v0 = luffy_math::getMinMaxData(ret0, luffy_math::emDataMax, &p0); Mat ret1; matchTemplate(vecImg[candidateIndex], imgTemplate, ret1, CV_TM_CCORR_NORMED); Point p1; double v1 = luffy_math::getMinMaxData(ret1, luffy_math::emDataMax, &p1); nIndex = v1 > v0 ? candidateIndex : nIndex; Mat identicalImg = vecImg[nIndex](Rect(10, 0, imgTemplate.cols, imgTemplate.rows)); double disVal = tempScoreShoot(identicalImg, imgTemplate, detectMode::shootTargetMatch); std::vector vecMat; auto imgCrop = [&](Mat srcMat, std::vector& vecMat){ int rightTopX = srcMat.cols - imgTemplate.cols; int leftDownY = srcMat.rows - imgTemplate.rows; Mat rightTopMat = srcMat(Rect(rightTopX, 0, imgTemplate.cols, imgTemplate.rows)); Mat leftDownMat = srcMat(Rect(0, leftDownY, imgTemplate.cols, imgTemplate.rows)); Mat rightDownMat = srcMat(Rect(rightTopX, leftDownY, imgTemplate.cols, imgTemplate.rows)); vecMat.push_back(rightTopMat); vecMat.push_back(leftDownMat); vecMat.push_back(rightDownMat); }; imgCrop(vecImg[nIndex], vecMat); for each (Mat vMat in vecMat) { double s = tempScoreShoot(vMat, imgTemplate, detectMode::shootTargetMatch); if (s > disVal) { disVal = s; } } int targetIndex = nIndex; float maxVal = disVal; if (disVal < 0.85) { float vMax = FLT_MIN; for (int k = 0; k < vecImg.size(); k++) { if (k == nIndex) { continue; } else { Mat imgRet; matchTemplate(vecImg[k], imgTemplate, imgRet, CV_TM_CCORR_NORMED); Point pnt; double v3 = luffy_math::getMinMaxData(imgRet, luffy_math::emDataMax, &pnt); if (v3 > vMax) { targetIndex = k; vMax = v3; } } } } nIndex = targetIndex; Mat imgMatchRet; matchTemplate(vecImg[nIndex], imgTemplate, imgMatchRet, CV_TM_CCORR_NORMED); Point pt3; double v3 = luffy_math::getMinMaxData(imgMatchRet, luffy_math::emDataMax, &pt3); float nPos = pt3.x + detectedOffset.at(nIndex) - nOffset; paramOut.dAngle = fmod(nPos, (double)paramIn.nMaxAngle); paramOut.dScore = v3; } else { Rect ret = Rect(0, 0, paramIn.imgTemplate.cols, paramIn.imgTemplate.rows / mcutOffset); if (paramIn.imgTemplate.cols <= 0 || paramIn.imgTemplate.rows / mcutOffset <= 0 || paramIn.imgTemplate.rows / mcutOffset > paramIn.imgTemplate.rows) return false; Mat imgTemplate = paramIn.imgTemplate(ret); PatternDetector m_detect; m_detect.train(imgTemplate); Vec4f t_vec; int m_posIndex = 0; float maxVal = 0; int m_index = 0; for (int k = 0; k < vecImg.size(); k++) { Mat roiMat = vecImg[k]; float score = m_detect.detectBest(roiMat, t_vec); if (score > maxVal) { maxVal = score; m_posIndex = t_vec[0]; m_index = k; } } float nPos = m_posIndex + detectedOffset.at(m_index) - nOffset - imgTemplate.cols / 2.0; paramOut.dAngle = fmod(nPos, (double)paramIn.nMaxAngle); paramOut.dScore = maxVal / 100.0; } } else { qDebug() << "bar check is failed"; paramOut.dAngle = 3610; paramOut.dScore = 0; } } } if (paramOut.dScore < paramIn.dScoreThres / 100.0 ) { paramOut.nErrorType += 8; } paramOut.bIsFind = true; return true; } void ValveDetector::drawResult(Mat &img, InputParam ¶mIn, OutputParam ¶mOut) { if (img.empty()) { return; } QString strObj = paramIn.strObj; QString str = "type: " + (strObj.isEmpty() ? "no type" : strObj); putText(img, str.toLatin1().data(), Point(10, 100), 3, 2, LP_COLOR_RED, 3); QString strAngle; if (!paramOut.bIsFind) { strAngle = "result: can not find valve"; } else { strAngle = "result: " + QString::number(paramOut.dAngleRes, 'f', 2) + QString(" center:(%1,%2)").arg(paramIn.ptCenter.x).arg(paramIn.ptCenter.y); } putText(img, strAngle.toLatin1().data(), Point(10, 200), 3, 2, LP_COLOR_RED, 3); QString strScore; QString strComp = ">"; if ((paramOut.nErrorType & 0x08) || (paramOut.nErrorType & 0x16)) { strComp = "<"; } strScore = "score=" + QString::number((paramOut.dScore)*100.0, 'f', 2) + "%" + strComp + QString::number(paramIn.dScoreThres, 'f', 2) + "%"; putText(img, strScore.toLatin1().data(), Point(10, 400), 3, 2, LP_COLOR_RED, 3); str = "time: " + QString::number((int)paramOut.dTime) + "ms"; putText(img, str.toLatin1().data(), Point(10, 300), 3, 2, LP_COLOR_RED, 3); str = "errorType: " + QString::number(paramOut.nErrorType); putText(img, str.toLatin1().data(), Point(10, 500), 3, 2, LP_COLOR_RED, 3); if (paramOut.flag == 1) { str = "Attention: center need to be ccalibrated"; putText(img, str.toLatin1().data(), Point(10, 600), 3, 2, LP_COLOR_RED, 3); } if (paramOut.nErrorType & 0x16) { strComp = ">"; } else { strComp = "<"; } if (paramOut.showMatchScore >= 0) { str = "model judge score = " + QString::number(paramOut.showMatchScore, 'f', 4) + strComp + QString::number(paramIn.cMatchScore, 'f', 4); putText(img, str.toLatin1().data(), Point(10, 700), 3, 2, LP_COLOR_RED, 3); } if (paramOut.bIsFind) { //= paramIn.nMaxAngle ? 0 : paramOut.dAngle; int tmpX = paramIn.ptCenter.x + paramIn.fValveDis * luffy_base::luffy_triangle::getCos(paramIn.nMaxAngle, angle); int tmpY = paramIn.ptCenter.y - paramIn.fValveDis * luffy_base::luffy_triangle::getSin(paramIn.nMaxAngle, angle); Point ptValve(tmpX, tmpY); cv::line(img, paramIn.ptCenter, ptValve, LP_COLOR_RED, 2); cv::circle(img, ptValve, paramIn.fValveWidth, LP_COLOR_RED, 2); cv::circle(img, ptValve, 3, LP_COLOR_BLUE, 3); double startAlg = paramIn.nStartOffset*1.0 / 10; double endAlg = angle * 1.0 / 10; if (startAlg < endAlg) { cv::ellipse(img, paramIn.ptCenter, Size(150, 150), 0, 360-startAlg, 360-endAlg,Scalar(255,0,255),2); } else { cv::ellipse(img, paramIn.ptCenter, Size(150, 150), 0, 0, -endAlg, Scalar(255, 0, 255), 2); cv::ellipse(img, paramIn.ptCenter, Size(150, 150), 0, 0, 360-startAlg, Scalar(255, 0, 255), 2); } } cv::circle(img, paramIn.ptCenter, 3, LP_COLOR_BLUE, 2); if (paramIn.nCenterAlg == 1) { cv::circle(img, paramIn.originalPoint, 3, LP_COLOR_GREEN, 2); } } double ValveDetector::ruleData(double dAngle, int nType) { if (0 != nType) { dAngle = 361; } if (dAngle < 0) { dAngle += 360.0; } //加入随机数 int r = rand() % 100; double dr = r / 4000.0; dAngle += dr; if (dAngle >= 359.99 && dAngle < 360.0) { dAngle += 0.01; } if (dAngle < 361.0 && dAngle >= 360.0) { dAngle -= 360; } return dAngle; } QString ValveDetector::genResultTip(QString str, int nType) { if (nType & 0x0001) { // no image str += "no image; "; } if (nType & 0x0002) { // no obj str += "no obj; "; } if (nType & 0x0004) { // lost calibrate info str += "no cali info; "; } if (nType & 0x0008) { // less than score th str += "less than scoreTh; "; } if (nType &0x0010) { str += "model is not matched; "; } return str; } cv::Point2f ValveDetector::getCenter(Mat & imgSrc, Point2f pt, InputParam ¶mIn) { if (0 == paramIn.nCenterAlg) { return pt; } Mat imgBinary; int nOffset = 80; //need Mat imgRoi; imgSrc(Rect(pt.x - nOffset, pt.y - nOffset, 2 * nOffset, 2 * nOffset)).copyTo(imgRoi); cv::threshold(imgRoi, imgBinary, 40, 255.0, THRESH_BINARY_INV); vector> con; Rect rect = Rect(0, 0, imgBinary.cols, imgBinary.rows); if (rect.width > imgBinary.cols || rect.height > imgBinary.rows) return pt; cv::rectangle(imgBinary, rect, Scalar(255), 1); cv::findContours(imgBinary.clone(), con, RETR_EXTERNAL, CHAIN_APPROX_NONE); bool bFind = false; Point2f ptNew; for (int i = 0; i < con.size(); i++) { const vector& c = con.at(i); if (c.size() < 20) { continue; } Rect rt = boundingRect(c); if (abs(rt.width - rt.height) > 5) { continue; } int nArea = luffy_blob::getArea(imgBinary.size(), c); double r = (rt.width + rt.height) / 4.0; double d = nArea / r /r; if (d < 2.5) { continue; } bFind = true; ptNew.x = rt.x + rt.width / 2.0 + pt.x - nOffset; ptNew.y = rt.y + rt.height / 2.0 + pt.y - nOffset; } if (bFind) { return ptNew; } return pt; } /* void ValveDetector::drawToImage(Mat &img, InputParam ¶mIn, OutputParam ¶mOut) { if (img.empty()) { return; } QString strObj = paramIn.strObj; QString str = "type: " + (strObj.isEmpty() ? "no type" : strObj); putText(img, str.toLatin1().data(), Point(10, 100), 3, 3, LP_COLOR_RED, 3); QString strAngle; if (!paramOut.bIsFind) { strAngle = "result: can not find valve"; } else { strAngle = "result: " + QString::number(paramOut.dAngleRes, 'f', 2); } putText(img, strAngle.toLatin1().data(), Point(10, 200), 3, 3, LP_COLOR_RED, 3); QString strScore; QString strComp = ">"; if (paramOut.nErrorType & 0x08) { strComp = "<"; } strScore = "score=" + QString::number((paramOut.dScore)*100.0, 'f', 2) + "%" + strComp + QString::number(paramIn.dScoreThres, 'f', 2) + "%"; putText(img, strScore.toLatin1().data(), Point(10, 400), 3, 3, LP_COLOR_RED, 3); str = "time: " + QString::number((int)paramOut.dTime) + "ms"; putText(img, str.toLatin1().data(), Point(10, 300), 3, 3, LP_COLOR_RED, 3); str = "errorType: " + QString::number(paramOut.nErrorType); putText(img, str.toLatin1().data(), Point(10, 500), 3, 3, LP_COLOR_RED, 3); if (paramOut.bIsFind) { //