想用openCV的 cvHoughCircles去识别实心的黑圆。但是cvHoughCircles的效果并不好,会检测出很多并不存在的拟合圆。因此还需在霍夫变换的基础上限定一些条件,对识别出的圆进行check。

因为我想要识别的是实心圆,因此对霍夫变换后的结果进行判断,圆心周围是否都是黑色的,是否是实心圆。

还加入了圆度公式对霍夫变换后的结果进行check:圆度D = 4πS/(L*L)。当对象越接近于圆时,圆度D越接近于1。

加上了这两个check条件后,cvHoughCircles的识别结果,达到了我想要的结果~

首先选定ROI,再对选定区域进行Canny算子的边缘检测。

IplImage *srcBitmap;
srcBitmap = cvLoadImage(fileNameFull, 1);
cvCvtColor(srcBitmap, srcBitmap, CV_RGB2GRAY);
cvThreshold(srcBitmap,srcBitmap,200,255,THRESH_BINARY);
cvSetImageROI(srcBitmap, cvRect(0, 0, 400, 400));
//pImg8uOri为原图,pImg8u为边缘检测后的图片
pImg8uOri = cvCreateImage(cvSize(400, 400), srcBitmap->depth, srcBitmap->nChannels);
pImg8u = cvCreateImage(cvSize(400, 400), srcBitmap->depth, srcBitmap->nChannels);
cvCopy(srcBitmap, pImg8uOri, NULL);cvResetImageROI(srcBitmap);cvCanny(pImg8uOri, pImg8u, 1, 2, 3);

再对边缘检测后的图片用cvHoughCircles进行找圆,对霍夫变换后的结果进行check。满足条件的则为要找的圆。

CvSeq * circles=NULL;
CvMemStorage* storage = cvCreateMemStorage(0);
circles=cvHoughCircles(pImg8u,storage,CV_HOUGH_GRADIENT,1,   //最小分辨率,应当>=1  //double类型的dp,用来检测圆心的累加器图像的分辨率于输入图像之比的倒数//且此参数允许创建一个比输入图像分辨率低的累加器。//例如,如果dp = 1,累加器和输入图像具有相同的分辨率//如果dp = 2,累加器便有输入图像一半那么大的宽度和高度50,    //pImg8u->height/4,   //该参数是让算法能明显区分的两个不同圆之间的最小距离40,  //用于Canny的边缘阀值上限,下限被置为上限的一半2,  //累加器的阀值//越小就可以检测到更多根本不存在的圆。//越大的话,检测到的圆就越接近完美的圆形10,  //最小圆半径 40  //最大圆半径);
int k;
int circleCount = 0;
double maxD = 0;
int maxPx = 0;
int maxPy = 0;
int maxR = 0;
for (k=0;k<circles->total;k++){float *p=(float*)cvGetSeqElem(circles,k);if ((cvRound(p[0])-15 < 0) || (cvRound(p[0]) + 15 >399)) continue;if ((cvRound(p[1])-15 < 0) || (cvRound(p[1]) + 15 >399)) continue;//check所找到的圆是否是实心的if (!(isFilled(pImg8uOri,cvRound(p[0]),cvRound(p[1]),15))) continue;int oriCount = 0;int cannyCount = 0;//圆度D = 4πS/(L*L)。当对象越接近于圆时,圆度D越接近于1int xLeft = cvRound(p[0]) - 24;if (xLeft < 0){xLeft = 0;}int xRight = cvRound(p[0]) + 25;if (xRight > 399){xRight = 399;}int yLeft = cvRound(p[1]) - 24;if (yLeft < 0){yLeft = 0;}int yRight = cvRound(p[1]) + 25;if (yRight > 399){yRight = 399;}int xCoordinate = 0;int yCoordinate = 0;int rightOri = 0;int rightCanny = 0;for(int x1 = xLeft; x1 < xRight; x1++){for(int y1 = yLeft; y1 < yRight; y1++){CvScalar s1 = cvGet2D(pImg8uOri, y1, x1);if (s1.val[0] < 128){oriCount ++;xCoordinate = xCoordinate + x1;yCoordinate = yCoordinate + y1;                    } CvScalar s2 = cvGet2D(pImg8u, y1, x1);if (s2.val[0] > 128) cannyCount ++;       if (x1 == xRight - 1){if (s1.val[0] < 128){rightOri = rightOri + 1;}if (s2.val[0] > 128){rightCanny = rightCanny + 1;}}}//圆度公式需要算出周长,周长的算法我用的是求边缘检测后的该区域黑点的个数//如果实心区域超出了选取的目标区域,则周长没闭合。需补偿//暂时未考虑上下边超出了目标区域的情况if (x1 == xLeft){if (cannyCount < oriCount){cannyCount = cannyCount + oriCount;}}if (x1 == xRight - 1){if (rightCanny < rightOri) {cannyCount = cannyCount + rightOri;}}}//圆度越大越接近于圆double D = 4 * PI * oriCount/(cannyCount * cannyCount);if (D < 0.4 || D >= 1) continue;//根据平均值校准圆心int rectifyX = (double)xCoordinate/(double)oriCount + 0.5;int rectifyY = (double)yCoordinate/(double)oriCount + 0.5;//校准半径int rectifyR1 = 0;for (int x1 = xLeft ; x1 < xRight; x1++ ){CvScalar s = cvGet2D(pImg8uOri, rectifyY, x1);if (s.val[0] < 128) {rectifyR1 = rectifyX - x1;break;}}int rectifyR2 = 0;for (int x1 = xRight ; x1 > xLeft; x1-- ){CvScalar s = cvGet2D(pImg8uOri, rectifyY, x1);if (s.val[0] < 128) {rectifyR2 = x1 - rectifyX;break;}}int rectifyR3 = 0;for (int y1 = yLeft ; y1 < yRight; y1++ ){CvScalar s = cvGet2D(pImg8uOri, y1, rectifyX);if (s.val[0] < 128) {rectifyR3 = rectifyY - y1;break;}}int rectifyR4 = 0;for (int y1 = yRight ; y1 > yLeft; y1-- ){CvScalar s = cvGet2D(pImg8uOri, y1, rectifyX);if (s.val[0] < 128) {rectifyR4 = y1 - rectifyY;break;}}int rectifyR = (double)(rectifyR1 + rectifyR2 + rectifyR3 + rectifyR4)/(double)4 + 0.5;//cvCircle(pImg8uOri,cvPoint(cvRound(p[0]),cvRound(p[1])),cvRound(p[2]),CV_RGB(0,255,0),1,CV_AA,0);//cvCircle(pImg8uOri,cvPoint(cvRound(p[0]),cvRound(p[1])),1,CV_RGB(155,50,255),1,CV_AA,0);int p2 = rectifyR;if(p2 >= 18 || p2 <= 12){p2 = 15;}circleCount = circleCount + 1;if(maxD == 0){maxD = D;maxPx = rectifyX;maxPy = rectifyY;maxR = p2;px = maxPx;py = maxPy;pr = maxR;}if(circleCount > 1){/如果有多个圆符合条件,则选出圆度最大的圆,也就是最圆的圆if(maxD > D){//原来识别出的圆更圆px = maxPx;py = maxPy;pr = maxR;}else{//新圆更圆maxPx = rectifyX;maxPy = rectifyY;maxR = p2;px = maxPx;py = maxPy;pr = maxR;}}return cvPoint(px,py);
}
bool  Card::isFilled(IplImage *pImg8u , int x ,int y , int r)
{int xRight = x;int xLeft = x;int yTop = y;int yBottom = y;for (int x1 = x ; x1<=x+r;x1++ ){CvScalar s = cvGet2D(pImg8u, y, x1);if (s.val[0] < 128) {xRight = x1;} else {break ;}}for (int y1=y ; y1<=y+r;y1++ ){CvScalar s = cvGet2D(pImg8u, y1, x);if (s.val[0] < 128){yBottom =y1;} else {break;}}for (int x1 = x ; x1>=x-r;x1-- ){CvScalar s = cvGet2D(pImg8u, y, x1);if (s.val[0] < 128) {xLeft = x1;} else {break ;}}for (int y1=y ; y1>=y-r;y1-- ){CvScalar s = cvGet2D(pImg8u, y1, x);if (s.val[0] < 128){yTop =y1;} else {break;}}//边缘检测后的圆可能并不十分完美,houghCircle可能不能十分准确的找出圆心//参数被从10调为7if ((xRight-x)<7 || (x-xLeft)<7 || (yBottom-y)<7 || (y-yTop)<7) {return false;}else{//圆点周围11*11的范围,点的覆盖率需大于95%if((x - 5)<=0 || (y - 5)<=0 || (x + 5)>=400 || (y + 5)>=400){return false;}int SqCount = 0;for(int m1=x-5; m1<=x+5; m1++){for(int m2=y-5; m2<=y+5; m2++){CvScalar s3 = cvGet2D(pImg8u, m2, m1);if (s3.val[0] < 128){SqCount = SqCount + 1;}}}if(SqCount >= 115){return true;}else{return false;}}}

圆度公式的那块,算法还有点问题,不完善。

主要问题是,我简单的把边缘检测后的黑点累加和认为是周长,原图片的黑点累加和认为是面积了。

但是如果,所截取的部分并不是完整的时候,周长的计算就会有问题。

以后有空再进行完善~

OpenCV霍夫变换识别圆相关推荐

  1. 【OpenCV】高精度识别圆(支持复杂场景下的圆)

    使用 OpenCV 霍夫变换-圆检测,对周围背景比较敏感,容易误识别,不受控.若你也有此困惑,建议试试本文中的方法,识别效果佳,能够很好地排除类圆矩形的干扰,话不多说直接上代码. 目录 代码 一.实现 ...

  2. STM32识别圆——色块追踪法

    前言 识别圆采用OpenCV来做比较简单,可以用HoughCircles函数,但是如何在内存和资源都很紧张的STM32上面实现圆识别算法,是本文的写作目的.本文的算法采用Python实现,不采用库函数 ...

  3. OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑

    本篇文章中,我们一起探讨了OpenCV中霍夫变换相关的知识点,以及了解了OpenCV中实现霍夫线变换的HoughLines.HoughLinesP函数的使用方法,实现霍夫圆变换的HoughCircle ...

  4. OpenCV霍夫变换的演示代码(附完整代码)

    OpenCV霍夫变换的演示代码 OpenCV霍夫变换的演示代码 OpenCV霍夫变换的演示代码 #include "opencv2/imgcodecs.hpp" #include ...

  5. OpenCV霍夫变换查找圆的实例(附完整代码)

    OpenCV霍夫变换查找圆的实例 OpenCV霍夫变换查找圆的实例 OpenCV霍夫变换查找圆的实例 #include "opencv2/imgcodecs.hpp" #inclu ...

  6. 【OpenCV新手教程之十四】OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/26977557 作者:毛星云(浅墨) ...

  7. opencv霍夫变换检测圆cvHoughCircles和直线cvHoughLines2的应用

    opencv霍夫变换检测圆cvHoughCircles和直线cvHoughLines2的应用 1)cvHonghLines2:直线 2)cvHoughCircles:该函数用Hough变换在二值图像中 ...

  8. 【OpenCV入门教程之十四】OpenCV霍夫变换:霍夫线变换,霍夫圆变换合辑

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/26977557 作者:毛星云(浅墨) ...

  9. OpenCV识别圆(复杂背景下的圆)

    文章目录 颜色模式 HSL和HSV cv2.inRange函数 边缘提取 图像阈值 OpenCv的HoughCircles函数 函数原型: 参数解释: 实例: 检测复杂背景下的圆 颜色模式 HSL和H ...

最新文章

  1. 微信支付:“当前页面的URL未注册”
  2. 会计的思考(38):会计--让业务做到心中有数,有真数
  3. IO多路复用:select/poll/epoll
  4. 复合索引的列顺序判断
  5. 移除添加的文件_文件压缩教程-文件批量压缩
  6. 优先级反转和解决方法
  7. python中if语句缺省else_9_【Python学习分享文章】_if(条件语句)
  8. [数论]线性筛——约数个数与约数和
  9. libpcap讲解与API接口函数讲解
  10. ASP.NET AJAX Timer Trouble? Location is key.
  11. c语言数码管的动态显示时间,8位数码管动态显示时间,可调节,调节的数闪烁显示...
  12. 为什么学习Python数据分析,python数据分析有什么用?
  13. 【报告分享】2019年全球数字化风险调查报告-德勤.pdf(附下载链接)
  14. 使用HTML5中的Canves标签制作时钟特效
  15. leetcode 125 valid-palindrome
  16. 如何在网上下载自己需要的资源
  17. 小写金额转换成大写金额
  18. 迷你双核RK3066 安卓4.1智能网络高清TV 安卓播放器MK802III-淘宝网
  19. mysql外联多表查询
  20. iTunes_12.7 iPhone 自定义铃声

热门文章

  1. golang测试框架 GoConvey使用总结
  2. pspice如何隔离驱动mosfet,MEG和M的
  3. 众筹平台建立步骤有哪些
  4. 论文收集和整理(三)
  5. 【反编译】安卓APK反编译为java文件
  6. 计算机毕设(附源码)JAVA-SSM佳音大学志愿填报系统
  7. 计算机怎么在表格里打勾,excel中怎么输入打勾符号在哪里,excel表格中怎么输入打勾符号...
  8. ocr大pk(阿里读光,百度,face++,有道)
  9. Springboot+Vue成果统一管理系统
  10. 上三角矩阵的乘法C语言,【数据结构】——基于压缩存储的半三角矩阵乘法运算的实现...