#include "ImageProcess.h" #include "qstring.h" #include "CVUtils.h" #include "ED.h" #include "EDLines.h" #include "EDCircles.h" #include "CircleDetector.h" //摩轮宏定义 表示该算法用于摩轮型号识别检测 #define MOTO_DETECT ImageProcess::ImageProcess() { } ImageProcess::~ImageProcess() { } 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; } #define REAIZE 2 cv::Mat ImageProcess::findCircleObject(const Mat &srcImg, const Mat& backgroundImg, bool useBackgroundFlag, int nThres /*= 20*/, luffy_base::luffyCircle *pCircle /*= NULL*/) { #ifdef MOTO_DETECT//摩轮型号识别抠图算法 if (!useBackgroundFlag) { Mat detectImg; Mat src = srcImg(Rect(435, 53, 1721, 1824)); 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) { 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; 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 { //结合背景图原始找圆算法 Mat src = srcImg; if (src.empty() || backgroundImg.empty() || src.rows < 500) { return Mat(); } assert(backgroundImg.type() == CV_8UC1); Mat imgTmp = src, imgBinary; using namespace luffy_base; luffy_threshold::Threshold(imgTmp, imgBinary, 50);//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); int maxArea = 0; for (int i = 0; i < conts.size(); i++) { const vector &pt = conts.at(i); if (pt.size() < 120) { continue; } Rect rt = boundingRect(pt); if (rt.width < 150 || rt.height < 150) { continue; } drawContours(imgBinary, conts, i, Scalar::all(255), -1); } Mat hit; vector pts; luffy_hit::firstHit4Circle(imgBinary, hit, pts, Point(imgBinary.cols / 2, imgBinary.rows / 2), 0, imgBinary.cols / 2, 360, luffy_hit::emHitIn2Out); 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); 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 } cv::Mat ImageProcess::getForeImage(const Mat & src, const Mat &backgroundImg) { Mat resizedBackgroundImg = backgroundImg; if (backgroundImg.size() != src.size()) { resize(backgroundImg, resizedBackgroundImg, src.size()); } return (src - resizedBackgroundImg); } //输入一张灰度图,输出抠出的圆小图和半径,圆心坐标 cv::Mat ImageProcess::findCircle(const Mat &srcImg, Point2f& center ,double &radius, bool bEqual,int filterSize) { 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*REAIZE) < filterSize) 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; radius = EDCircle[nIndex].r; int hight = 2 * radius * REAIZE; center.x = (EDCircle[nIndex].center.x * REAIZE); center.y = (EDCircle[nIndex].center.y * REAIZE); radius = radius * REAIZE; return DetectCircle(srcImg, center, radius, bEqual); } else {//EDCirle 没找到圆 直径调用精细找圆算法 center.x = srcImg.cols / 2; center.y = srcImg.rows / 2; radius = 0; return DetectCircle(srcImg, center, radius, bEqual); } } Mat ImageProcess::DetectCircle(Mat img, Point2f& 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.x = img.cols / 2; center.y = 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()) { center.x = 0; center.y = 0; radius = 0; 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 s = img(rect); center = cen; radius = r; return s; }