opencv学习十六:圆检测

圆检测

原理
圆周上任意三点所确定的圆,经Hough变换后在三维参数空间应对应一点。遍历圆周上所有点,任意三个点所确定的候选圆进行投票。遍历结束后,得票数最高点(理论上圆周上任意三点确定的圆在Hough变换后均对应三维参数空间中的同一点)所确定的圆 即为该圆周上,绝大多数点所确定的圆(以下称为当选圆),即绝大多数点均在该当选圆的圆周上,以此确定该圆。

圆形的表达式为(x−xcenter)2+(y−ycenter)2=r2(x−xcenter)2+(y−ycenter)2=r2,一个圆环的确定需要三个参数。那么霍夫变换的累加器必须是三维的,但是这样的计算效率很低。
这里opencv中使用霍夫梯度的方法,这里利用了边界的梯度信息。
首先对图像进行canny边缘检测,对边缘中的每一个非0点,通过Sobel算法计算局部梯度。那么计算得到的梯度方向,实际上就是圆切线的法线。三条法线即可确定一个圆心,同理在累加器中对圆心通过的法线进行累加,就得到了圆环的判定。

在这里插入图片描述2、opencv API
因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波。
基于效率考虑,Opencv中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:
检测边缘,发现可能的圆心
基于第一步的基础上从候选圆心开始计算最佳半径大小
cv2.HoughCircles函数的参数

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

image为输入图像,需要灰度图

method为检测方法,常用CV_HOUGH_GRADIENT

dp为检测内侧圆心的累加器图像的分辨率于输入图像之比的倒数,如dp=1,累加器和输入图像具有相同的分辨率,如果dp=2,累计器便有输入图像一半那么大的宽度和高度

minDist表示两个圆之间圆心的最小距离,圆心距离小于mimDist认为为同一个圆

param1有默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半

param2有默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值,它越小,就越可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了

minRadius有默认值0,圆半径的最小值

maxRadius有默认值0,圆半径的最大值

import cv2 as cv
import numpy as np


def detect_circles_demo(image):
    dst = cv.pyrMeanShiftFiltering(image, 10, 100)#均值偏移滤波
    cv.imshow("dst", dst)
    cimage = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)#灰度图
    circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0)
    circles = np.uint16(np.around(circles))#取整
    for i in circles[0, :]:
        cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)#在原图上画圆,圆心,半径,颜色,线框
        cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)#画圆心
    cv.imshow("circles", image)

src = cv.imread("C:/Users/lenovo/Desktop/opencv/daima/banknum/template-matching-ocr/images/circle.png")  #读取图片位置
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
detect_circles_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()

我改了minDist的值,发现40的效果大于20
运行截图:
在这里插入图片描述

这是啥 为什么右上角那个硬币没检测出来?
在这里插入图片描述
为什这么辣眼睛(不太清楚)
在这里插入图片描述
和别人的不一样QAQ
在这里插入图片描述如果没有下面这一行

dst = cv.pyrMeanShiftFiltering(image, 10, 100)#均值偏移滤波

结果
在这里插入图片描述原理:
meanShfit均值漂移算法是一种通用的聚类算法,它的基本原理是:对于给定的一定数量样本,任选其中一个样本,以该样本为中心点划定一个圆形区域,求取该圆形区域内样本的质心,即密度最大处的点,再以该点为中心继续执行上述迭代过程,直至最终收敛。可以利用均值偏移算法的这个特性,实现彩色图像分割,
Opencv中对应的函数是pyrMeanShiftFiltering。这个函数严格来说并不是图像的分割,而是图像在色彩层面的平滑滤波,它可以中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的颜色区域,
第一个参数src,输入图像,8位,三通道的彩色图像,并不要求必须是RGB格式,HSV、YUV等Opencv中的彩色图像格式均可;

第二个参数dst,输出图像,跟输入src有同样的大小和数据格式;

第三个参数sp,定义的漂移物理空间半径大小;

第四个参数sr,定义的漂移色彩空间半径大小;

第五个参数maxLevel,定义金字塔的最大层数;

第六个参数termcrit,定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合;

pyrMeanShiftFiltering函数的执行过程是这样的:

迭代空间构建
求取迭代空间的向量并移动迭代空间球体后重新计算向量,直至收敛(一个图像,然后选取一个球形,求得所有点相对于中心点的色彩向量之和后,移动选取的球形继续操作,有点类似卷积层)
更新输出图像dst上对应的初始原点P0的色彩值为本轮迭代的终点Pn的色彩值,如此完成一个点的色彩均值漂移。
4.输入图像src上其他点,依次执行步骤1,、2、3,遍历完所有点位后,整个均值偏移色彩滤波完成

半径越大,图像的细节就丢失的越多

猜你喜欢

转载自blog.csdn.net/weixin_44145452/article/details/112775901