You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
wheeldetect/doc/旧抠图算法.txt

575 lines
19 KiB
Plaintext

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

老算法 准确率低
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<mCircle> 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<vector<Point>> conts;
cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE);
imgBinary.setTo(0);
for (int i = 0; i < conts.size(); i++) {
const vector<Point> &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<Point> 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<Point> 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<Point> pts;
luffy_hit::firstHit4Circle(matBinary, hit, pts, pCircle->ptCenter, 0, pCircle->fRadius + 20, 360, luffy_hit::emHitOut2In);//luffy_hit::emHitOut2In
std::map<double, cv::Point> 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<double, cv::Point>::iterator it = mp.begin();
//std::advance(it, startIndex);
std::vector<cv::Point> 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<Point> 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<mCircle> 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<mCircle> 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<vector<Point>> 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<vector<Point>>(1, conts.at(nbestIndex)), -1, Scalar::all(255), -1);
}
Mat hit; vector<Point> 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<Point> 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<Point> 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<Point> 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+hight<src.cols && startY+hight<src.rows)
{
Mat cutMat = src(Rect(startX, startY, hight, hight));
if (cutMat.data != NULL)
{
if (hight < 50)
return Mat();
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);
cv::Point2d center;
center.x = centerX;// EDCircle[nIndex].center.x * REAIZE;
center.y = centerY;// EDCircle[nIndex].center.y * REAIZE;
pCircle->ptCenter = 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<vector<Point>> conts;
cv::findContours(imgBinary, conts, RETR_EXTERNAL, CHAIN_APPROX_NONE);
imgBinary.setTo(0);
/*
for (int i = 0; i < conts.size(); i++) {
const vector<Point> &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<vector<Point>>(1,conts.at(nbestIndex)), -1, Scalar::all(255), -1);
}
//openOper(imgBinary, 17);//集智抠图问题修改 20190329
Mat hit; vector<Point> 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<Point> 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<cv::Vec3b>(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<cv::Vec3b>(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<Point> 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<Point> 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<float> 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;