老算法 准确率低 cv::Mat ImageProcess::findCircleObject(const Mat &src, const Mat& backgroundImg, bool useBackgroundFlag, int nThres /*= 20*/, luffy_base::luffyCircle *pCircle /*= NULL*/) { #ifdef MOTO_DETECT//摩轮型号识别抠图算法 if (!useBackgroundFlag) { Mat detectImg; cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE)); int bBaseX = detectImg.cols; int bBaseY = detectImg.rows; 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 > 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; if (startX > 0 && startY > 0 && hight > 0 \ && startX < src.cols &&startY < src.rows \ &&hight < src.cols&&hight < src.rows \ && startX + hight < src.cols && startY + hight < src.rows) { Mat cutMat = src(Rect(startX, startY, hight, hight)); if (cutMat.data != NULL) { //Mat dst; //double rate = src.cols*1.0 / ALG_RESIZE_IMAGE_WIDTH; //const cv::Size cSize = cv::Size(cutMat.cols*1.0 / rate, cutMat.rows*1.0 / rate); //cv::resize(cutMat, dst, cSize); if (hight < 50) return Mat(); cv::Point2d center; center.x = EDCircle[nIndex].center.x * REAIZE; center.y = EDCircle[nIndex].center.y * REAIZE; pCircle->ptCenter = center; //float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH; //pCircle->fRadius = hight*1.0 / fScale; pCircle->fRadius = radius * REAIZE; //2021-05-10 增加图像大小判断 对超过900像素的图像进行再一次压缩 if (cutMat.cols >= 900 || cutMat.rows >= 900) { Mat newCutImg; cv::resize(cutMat, newCutImg, cv::Size(cutMat.cols / REAIZE, cutMat.rows / REAIZE)); pCircle->fRadius = pCircle->fRadius / REAIZE; return newCutImg; } return cutMat; } } } return Mat(); } else { 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 cv::resize(foregroundImg, foregroundImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE)); using namespace luffy_base; luffy_threshold::Threshold(foregroundImg, imgBinary, nThres);//0421 Mat dilatedImgBin; dilate(imgBinary, dilatedImgBin, Mat::ones(21, 21, CV_32FC1)); erode(dilatedImgBin, imgBinary, Mat::ones(21, 21, CV_32FC1)); openOper(imgBinary, Mat::ones(1, 11, 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); int nMinFitNum = 100; luffy_imageProc::RansacParam rs(0.01, 3, 150, nMinFitNum, 240); vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); float fRadius; Point2f ptCenter; bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); 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; pCircle->fRadius = fRadius * fScale; pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale); Rect rt(pCircle->ptCenter.x - pCircle->fRadius + nOffset, pCircle->ptCenter.y - pCircle->fRadius + nOffset, 2 * pCircle->fRadius, 2 * pCircle->fRadius); rt &= Rect(0, 0, matBig.cols, matBig.rows); src(rt).copyTo(dst);*/ float fScale = src.cols / ALG_RESIZE_IMAGE_WIDTH; Mat matBig = src - backgroundImg; pCircle->fRadius = fRadius * fScale; pCircle->ptCenter = Point(ptCenter.x * fScale, ptCenter.y * fScale); Mat matBinary; luffy_threshold::Threshold(matBig, matBinary, nThres); // add openOper(matBinary, Mat::ones(3, 3, CV_32FC1)); Mat hit; vector pts; luffy_hit::firstHit4Circle(matBinary, hit, pts, pCircle->ptCenter, 0, pCircle->fRadius + 20, 360, luffy_hit::emHitOut2In);//luffy_hit::emHitOut2In std::map mp; std::for_each(pts.begin(), pts.end(), [&](Point p) { double dis = fabs(luffy_math::disofPoints(pCircle->ptCenter, p)); mp[dis] = p; }); const int bound = 200; //int startIndex = mp.size() - bound; std::map::iterator it = mp.begin(); //std::advance(it, startIndex); std::vector ppts; int i = 0; for (it; it != mp.end(); ++it, ++i) { if (i == bound) break; ppts.push_back(it->second); } luffy_imageProc::RansacParam rs(0.01, 5.0, 300, 70, 120); vector pts2 = luffy_imageProc::fitModelbyRansac(ppts, 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); } else { return Mat(); } } return dst; } #else//汽轮型号识别抠图算法 /* 2020-06-19 使用三种预防措施找圆 第一阶梯 使用EDCircle算法,图像经过2.5倍增亮找圆 如若在第一阶梯没有找到圆(找到的圆不符合条件),进入第二阶梯 第二阶梯 使用EDCircle算法,图像改为原图 如若在第二阶梯还没找到圆,进入第三阶梯使用传统找圆算法(结合监测背景图) 第三阶梯不管怎样都会找出一个最佳圆 */ if (src.empty() || backgroundImg.empty() || src.rows < 500) { return Mat(); } bool findFlag = false; /*第一阶梯找圆*/ assert(backgroundImg.type() == CV_8UC1); Mat detectImg; cv::resize(src, detectImg, cv::Size(src.cols / REAIZE, src.rows / REAIZE)); int bBaseX = detectImg.cols; int bBaseY = detectImg.rows; Mat upLight_Img = detectImg + 1.5 * detectImg;//20200423 修改 对图像进行叠加,增强目标亮度 blur(upLight_Img, upLight_Img, Size(3, 3)); EDCircles edcircles(upLight_Img); 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 > 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 centerX = EDCircle[nIndex].center.x * REAIZE; double centerY = EDCircle[nIndex].center.y * REAIZE; double radius = EDCircle[nIndex].r; if (radius < 50)//小于阈值 进行二次查找 radius一般大于100,小于50像素的基本是其他小圆 {/*第二阶梯找圆 2020 - 06 - 19 添加 原图查找圆*/ blur(detectImg, detectImg, Size(3,3)); EDCircles edcircles2(detectImg); vector EDCircle2 = edcircles2.getCircles(); double maxR = 0; int mIndex = -1; for (int i = 0; i < EDCircle2.size(); i++) { int startX = EDCircle2[i].center.x - EDCircle2[i].r; int startY = EDCircle2[i].center.y - EDCircle2[i].r; if (startX < 0 || startY < 0) continue; if (EDCircle2[i].center.x + EDCircle2[i].r > bBaseX || EDCircle2[i].center.y + EDCircle2[i].r > bBaseY) continue; if (EDCircle2[i].r > maxR) { maxR = EDCircle2[i].r; mIndex = i; } } if (mIndex == -1) return Mat(); startX = EDCircle2[nIndex].center.x * REAIZE - EDCircle2[nIndex].r * REAIZE; startY = EDCircle2[nIndex].center.y * REAIZE - EDCircle2[nIndex].r* REAIZE; centerX = EDCircle2[nIndex].center.x * REAIZE; centerY = EDCircle2[nIndex].center.y * REAIZE; radius = EDCircle2[nIndex].r; if (radius < 50)/*第三阶梯找圆*/ { 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; //nThres = 90; luffy_threshold::Threshold(foregroundImg, imgBinary, nThres);//0421 Mat dilatedImgBin; closeOper(imgBinary, 7); vector> conts; cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE); imgBinary.setTo(0); //筛选最大轮廓的作为圆拟合区域 int maxsize = 0; int nbestIndex = 0; for (int i = 0; i < conts.size(); i++) { if (conts.at(i).size()>maxsize) { maxsize = conts.at(i).size(); nbestIndex = i; } } if (conts.size() > 0) { drawContours(imgBinary, vector>(1, conts.at(nbestIndex)), -1, 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); int nMinFitNum = 150; if (pts.size() < nMinFitNum)//解决检测目标在图像边缘导致的抠图识别问题 { if (conts.size()>0) pts = conts.at(nbestIndex); } luffy_imageProc::RansacParam rs(0.01, 2, 150, nMinFitNum, 240); vector pts2 = luffy_imageProc::fitModelbyRansac(pts, luffy_imageProc::emModelCircle, &rs); float fRadius; Point2f ptCenter; bool bFind = luffy_imageProc::lsCircleFit(pts2, fRadius, ptCenter); 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; 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_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; } } int hight = 2 * radius * REAIZE; if (startX > 0 && startY > 0 && hight > 0 \ && startX < src.cols &&startY < src.rows \ &&hight < src.cols&&hight < src.rows \ && startX+hightptCenter = center; pCircle->fRadius = radius * REAIZE / rate; return dst; } } } return Mat(); /*以下为旧代码 目前不使用*/ 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; //nThres = 90; luffy_threshold::Threshold(foregroundImg, imgBinary, nThres);//0421 Mat dilatedImgBin; closeOper(imgBinary, 7); //dilate(imgBinary, dilatedImgBin, Mat::ones(7, 7, CV_32FC1));// //erode(dilatedImgBin, imgBinary, Mat::ones(7, 7, CV_32FC1)); //openOper(imgBinary, Mat::ones(1, 13, CV_32FC1));//集智抠图问题修改 20190329 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); } */ //筛选最大轮廓的作为圆拟合区域 int maxsize = 0; int nbestIndex = 0; for (int i = 0; i < conts.size(); i++) { if (conts.at(i).size()>maxsize) { maxsize = conts.at(i).size(); nbestIndex = i; } } if (conts.size() > 0) { drawContours(imgBinary, vector>(1,conts.at(nbestIndex)), -1, Scalar::all(255), -1); } //openOper(imgBinary, 17);//集智抠图问题修改 20190329 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); //luffy_imageProc::RansacParam rs(0.02, 2.5, 70, 100, 220); //luffy_imageProc::RansacParam rs(0.01, 2, 150, 150, 240);//20190117 int nMinFitNum = 150; if (pts.size() < nMinFitNum)//解决检测目标在图像边缘导致的抠图识别问题 { if (conts.size()>0) pts = conts.at(nbestIndex); } luffy_imageProc::RansacParam rs(0.01, 2, 150, nMinFitNum, 240); 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); 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; 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_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; #endif } // CircleDetector cd; // cd.setAlgoType(CircleDetector::PeakCircle); // cd.setEdgeWidth(cParam.CircleEdgeWidth); // // if (cParam.CirclePolarity == 0) // cd.setPolarity(Polarity::Black2White); // else // cd.setPolarity(Polarity::White2Black); // // cd.setFindBy(FindBy::Best); // double difRadiusMin = 0; // double difRadiusMax = (foregroundImg.cols>foregroundImg.rows? foregroundImg.rows/2 : foregroundImg.cols/2)-50; // cd.setRadii(difRadiusMin, difRadiusMax); // cd.setACThres(cParam.CircleACThres); // vector allScores; // Vec3f bestCircle; // float bestScore = cd.detectBest(foregroundImg, Point2f(imgTmp.cols/2, imgTmp.rows/2), bestCircle, &allScores); // if (abs(bestScore) <= FLT_EPSILON || bestCircle == Vec3f::zeros()) { // return Mat(); // } // // Point2f 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 rltMat = src(rect); // if (pCircle) // { // pCircle->fRadius = r; // pCircle->ptCenter = cen; // } // return rltMat;