百科问答小站 logo
百科问答小站 font logo



如何用python来统计MacPro的圆圈个数? 第1页

  

user avatar   zamhown 网友的相关建议: 
      

不是CV方向的,抛砖引玉来一个简单的基于规则的方法吧。


最简单的方法是用霍夫变换实现圆形目标的识别,而且也能用python3和opencv-python库很轻松地实现。先上结果:


一、霍夫变换的原理


霍夫变换的原理并不复杂,下面以检测直线为例来简单介绍下(如果不感兴趣可以直接跳过):

上图有5个排列没啥规律的点,如果我们把它当成现实生活中图片的极简化情况(假设这5个点是黑色像素点),如果要从图片中识别一条最有可能的直线 ,要怎么找呢?一种很自然的思路是看哪一条直线经过了最多的黑色像素点。


霍夫变换的思想是将直线 变换为 的形式, 和 分别变成自变量和因变量,而 和 反而成了参数。我们把 和 展成的二维空间称为参数空间。根据霍夫变换的性质,一个在原空间的点 在参数空间中,作为参数描述了一条直线:


下面我们将原图片中5个点分别变换到参数空间,可得下图:


可以看到,5条直线除了C和D平行以外,其他两两相交(有些交点因为太远在上图无法看到),且A、B、C三条直线交于一点。这个交点代表什么呢?代表了存在相同的参数 和 ,也就是在原空间中A、B、C三点共线!求出交点坐标,也得到了那条直线的方程。


因此,霍夫变换将复杂的多点共线问题转化为简单的多线共点问题,我们只需求出参数空间中有最多条直线穿过的那个交点,就能识别原图中最明显的那条直线。而原空间中斜率不存在的情况(参数空间中直线平行)可以通过转换为极坐标解决。


霍夫变换识别圆同理,但变复杂了一些。我们都知道圆的方程 有三个参数,如果 确定,参数空间是二维,原空间的点在参数空间会对应一个圆 ;当 不确定时,参数空间变成三维,原空间的点则会变成一个个圆锥[1],如果直接求交点,计算量会很大。


二、OpenCV的相关算法和API


OpenCV对该算法进行了优化,称为霍夫梯度法,可以分为估计 和估计 两个步骤[2]


估计 (圆心):

  1. 用Canny算法进行边缘检测,得到边界二值图;
  2. 用Sobel算子计算原图的梯度;
  3. 遍历边缘二值图中的非0点,沿着梯度方向和反方向画线段(梯度方向为圆弧的法线方向,即半径方向),线段的起点和长度由参数允许的半径区间决定。将线段经过的点在累加器中记数;
  4. 对累加器中的点从大到小排序,记数越大越有可能成为圆心,优先估计半径。


估计 (半径):

  1. 计算所有边界图中的非0点离圆心的距离,并从小到大排序;
  2. 从最小半径 开始,距离相差在一个小量范围内的点,都认为是同一个圆,记数属于该半径 的非0点数,记为 ;
  3. 尝试放大半径,同样记数该半径上的点数;
  4. 判断两个半径孰优孰劣的依据——点的线密度( ),密度越高,半径的可信度越大;
  5. 重复以上步骤,直至半径超过参数允许的范围,从而得到最优半径。


说到这里,opencv-python库的相关API就好懂多了:

       cv2.HoughCircles(     image,      method,      dp,      minDist,      circles=None,      param1=None,      param2=None,      minRadius=None,      maxRadius=None )     


重要参数说明:

  • image:8位单通道图像(不能是彩色图像)。
  • method:检测方法,这里只能是cv2.HOUGH_GRADIENT。
  • dp:用来检测圆心的累加器图像的分辨率与输入图像之比的倒数,且此参数允许创建一个比输入图像分辨率低的累加器。如果dp=1,累加器和输入图像具有相同的分辨率。如果dp=2,累加器便有输入图像一半的宽度和高度。
  • min_dist:霍夫变换检测到的圆的圆心之间的最小距离,即算法能明显区分的两个不同圆之间的最小距离。
  • param1:Canny算法的高阈值,低阈值设为其的一半。
  • param2:累加器的阈值,它越小的话,就可以检测到更多残缺的圆,而它越大的话,能通过检测的圆就更加接近完整的圆。
  • minRadius和maxRadius:给定半径的上下界。


三、具体实现


既然是基于规则的方法,我们需要人工定义各个参数。首先我们找到一张Mac Pro的正面图片,粗略估计下图片中每个圆圈的半径范围:


根据测量结果(45px左右),可以把半径范围设为20到25px之间。半径范围严格一点,就能规避更多我们不需要的圆。


经过一番试验,我们可以调出所有参数。用到OpenCV的代码节选如下:

       img = cv2.imread('mp.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度图像 circle1 = cv2.HoughCircles(     gray,      cv2.HOUGH_GRADIENT,      1,      5,      param1=100,      param2=30,      minRadius=20,      maxRadius=25 ) circles = np.uint16(np.around(circle1[0, :, :]))  # 提取为二维并四舍五入 circle_count = 0 for i in circles[:]:     circle_count += 1     


答案是158,这毕竟是花了30分钟写出来的代码跑的珍贵成果。花30秒肉眼数一下,没错!(但好像有哪里不对)


完整代码我放进了GitHub,欢迎参考。

参考

  1. ^ https://blog.csdn.net/weixin_40196271/article/details/83346442
  2. ^ https://blog.csdn.net/hhyh612/article/details/54947205



  

相关话题

  如何看待与评价 AAAI 2022 的录用结果? 
  如何看待任正非在国家科技大会上的发言? 
  围棋中什么叫最善的下法? 
  大学生用 MacBook 会显得高调吗? 
  如何评价余凯在朋友圈发表呼吁大家用 caffe、mxnet 等框架,避免使用 TensorFlow? 
  deepmind发表的neural processes(神经过程),这个是怎么实现的呢? 
  当「虚拟数字人类」无限接近于拟人,会给我们的生活带来哪些影响? 
  目前来看,Affinity Photo 是否具有挑战Photoshop霸主地位的潜力?为什么? 
  如何看待学霸君的高考机器人 Aidam 高考全国文科数学卷考了 134 分? 
  在一个非常繁忙的十字路口,红绿灯坏了,请问无人驾驶汽车能顺利通过吗? 

前一个讨论
宇宙中有哪些令人感到快乐的天体?
下一个讨论
大学生活怎么也开心不起来怎么办?





© 2025-03-10 - tinynew.org. All Rights Reserved.
© 2025-03-10 - tinynew.org. 保留所有权利