Python+opencv学习记录19:圆检测

文章目录

  • 1.霍夫圆变换原理
  • 2.霍夫圆检测
  • 完整代码

1.霍夫圆变换原理

霍夫圆变换是将二维图像空间中一个圆转换为该圆半径、圆心横纵坐标所确定的三维参数空间中一个点的过程,因此圆周上任意三点所确定的圆经过霍夫变换后在三维参数空间应对应一点。该过程类似于选举投票过程,圆周上任意三个点为一选举人,而这三个点所确定的圆则为一侯选人。遍历圆周上所有点,任意三个点所确定的候选圆进行投票,遍历结束后,得票数最高点(理论上圆周上任意三点确定的圆在霍夫变换后均对应三维参数空间中的同一点)所确定的圆即为该圆周上绝大多数点所确定圆,即绝大多数点均在该当选圆的圆周上,以此确定该圆。
在笛卡尔坐标系中圆的方程为:

                         (x-a)²+(y-b)²=r²

Python+opencv学习记录19:圆检测_第1张图片
其中(a,b)是圆心,r是半径,也可以表述为:

                           x=a+rcosθ
                           y=b+rsinθ

即:

                           a=x-rcosθ
                           b=y-rsinθ

在笛卡尔的xy坐标系中经过某一点的所有圆映射到abr坐标系中就是一条三维的曲线,因此经过xy坐标系中所有的非零像素点的所有圆就构成了abr坐标系中很多条三维的曲线。
在xy坐标系中同一个圆上的所有点的圆方程是一样的,它们映射到abr坐标系中的是同一个点,所以在abr坐标系中该点就应该有圆的总像素N0个曲线相交。
通过判断abr中每一点的相交(累积)数量,大于一定阈值的点就认为是圆。

2.霍夫圆检测

因为霍夫圆检测对噪声比较敏感,所以首先要对图像进行滤波。
基于效率考虑,Opencv中实现的霍夫圆检测是基于图像梯度的实现,分为两步:
1.检测边缘,发现可能的圆心;
2.在基于第一步的基础上从候选圆心开始计算最佳半径大小。

其代码为:

def detect_circles_demo(image):
    dst = cv.medianBlur(image, 15)
    # dst = cv.pyrMeanShiftFiltering(image, 10, 98)
    # 均值迁移滤波,定义的漂移物理空间半径大小10,定义的漂移色彩空间半径大小98(必须为98,否则检测不全)
    cimage = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
    circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=55, param2=30, minRadius=0, maxRadius=0)
    # 霍夫梯度法检测圆,检测到圆心之间的最小距离20,Canny边缘检测的高阈值50,圆心检测阈值20,能检测到的最小圆和最大圆的半径为0
    circles = np.uint16(np.around(circles))         # 把circles包含的圆心和半径的值变成整数
    for i in circles[0, :]:
        cv.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)        # 画出圆
        cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)           # 画出圆心
    cv.imshow("circles", image)

在写这段代码时,最开始我用的是均值迁移滤波,其中的参数我最开始设置的是10,100,下面的霍夫梯度法检测圆的两个阈值是50,30,但是效果并不好,得到的结果为:
Python+opencv学习记录19:圆检测_第2张图片
可以看出右下角的硬币没有被检测出,接着就修改参数,发现均值迁移滤波的漂移色彩空间半径修改为98后效果要稍微好一点,
Python+opencv学习记录19:圆检测_第3张图片
之后将均值迁移滤波换成了中值滤波,并将边缘检测的高阈值改成了55,得到的效果为:
Python+opencv学习记录19:圆检测_第4张图片
可以看出此时的效果要好于均值迁移滤波得到的效果。
其中的原因应该是霍夫圆检测的确对噪声异常敏感,所以降噪时的参数和霍夫圆检测函数的阈值参数也需要细调(如有不对,还希望各位大佬指正)

完整代码

import cv2 as cv                # 导入opencv模块
import numpy as np              # 导入数学函数库


def detect_circles_demo(image):
    dst = cv.medianBlur(image, 15)                  # 中值滤波
    # dst = cv.pyrMeanShiftFiltering(image, 10, 98)
    # 均值迁移滤波,定义的漂移物理空间半径大小10,定义的漂移色彩空间半径大小98(必须为98,否则检测不全)
    cimage = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
    circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=55, param2=30, minRadius=0, maxRadius=0)
    # 霍夫梯度法检测圆,检测到圆心之间的最小距离20,Canny边缘检测的高阈值50,圆心检测阈值20,能检测到的最小圆和最大圆的半径为0
    circles = np.uint16(np.around(circles))         # 把circles包含的圆心和半径的值变成整数
    for i in circles[0, :]:
        cv.circle(image, (i[0], i[1]), i[2], (0, 255, 0), 2)        # 画出圆
        cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)           # 画出圆心
    cv.imshow("circles", image)


print("------------hello python!------------")

src = cv.imread("D:/opencv3/image/coins.jpg")
cv.namedWindow("input_image", cv.WINDOW_AUTOSIZE)
cv.imshow("input_image", src)
detect_circles_demo(src)

cv.waitKey(0)
cv.destroyAllWindows()          # 释放所有窗口

你可能感兴趣的:(Python+opencv学习,opencv,计算机视觉,cv)