python学opencv|读取图像(七十)使用cv2.HoughCircles()函数实现图像中的霍夫圆形检测

发布于:2025-02-16 ⋅ 阅读:(33) ⋅ 点赞:(0)

【1】引言

前序学习进程中,已经掌握了使用cv2.HoughLinesP()函数实现图像中的霍夫直线检测,相关文章链接为:

python学opencv|读取图像(六十九)使用cv2.HoughLinesP()函数实现图像中的霍夫直线检测-CSDN博客

在此基础上,很容易想到进行圆形检测,这就是本次文章的学习目标: 使用cv2.HoughCircles()函数实现图像中的霍夫圆形检测。

【2】官网教程

点击下方链接,直达霍夫圆形检测cv2.HoughCircles()函数的官网教程:

OpenCV: Feature Detection

官网页面对cv2.HoughCircles()函数的说明为:

图1  cv2.HoughCircles()函数的官网说明

具体的,官网页面对cv2.HoughCircles()函数的参数说明为:

cv.HoughCircles(    

image                 #输入图像,要求是8位单通道图像

method               #检测方法,包括HOUGH_GRADIENT和HOUGH_GRADIENT_ALT两种

dp                       #累加器和图片分辨率比值的倒数,一般取1

minDist               #圆心之间的最小距离

param1              #边缘检测的第一个阈值,一般较大

param2              #边缘检测的第二个阈值,一般较小

minRadius         #小圆半径

maxRadius    )   #大圆半径

【3】代码检测

代码设计包括三大部分。

第一部分是引入模块和相关图像:

import cv2 as cv #引入cv2模块
import numpy as np #引入numpy模块

# 读取图片
src = cv.imread('srcpp.png')

第二部分是对图像进行预处理,因为霍夫圆形检测只能对灰度图执行,所以需要提前转化图像:

# 预处理图像
srcb = cv.medianBlur(src, 3)  # 中值滤波
gray = cv.cvtColor(srcb, cv.COLOR_BGR2GRAY)  # 将图像转化为灰度图

第三部分是对图像进行霍夫圆形检测,由于逐个调整参数,所以需要设置for循环:

# 定义霍夫圆检测的参数列表
hough_params_list = [
    (70, 100, 25, 10, 50),
    (100, 100, 25, 10, 50),
    (100, 120, 25, 10, 50),
    (100, 120, 50, 10, 50),
    (100, 120, 50, 25, 50)
]

transformed_images = [src.copy()]  # 先将原始图像添加到列表中

# 进行霍夫圆检测并绘制圆形
for i,(minDist, param1, param2, minRadius, maxRadius) in enumerate(hough_params_list,start=1):
    circleparams = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)
    circleimg =src.copy() #复制原始图像进行绘图
    if circleparams is not None:
        circles = np.uint16(np.around(circleparams))
        for circle in circles[0,:]:
            x, y, r = circle
            circleimg=cv.circle(circleimg, (x, y), r, (200, 150, 200), 5)
        transformed_images.append(circleimg) #图像逐个累加

上述代码中,cv2.HoughCircles()函数通过enumerate()函数逐项调取hough_params_list矩阵中的参数,执行了5次霍夫圆形检测。

每次检测完毕后,都直接进行了圆形绘制,transformed_images.append(circleimg)把绘制的圆形按照顺序叠加在一起。

第四部分是对图像进行横向组合和竖向组合:

# 确保图像数量足够进行两行三列的拼接
while len(transformed_images) < 6:
    # 如果图像数量不足 6 个,用空白图像填充
    blank_image = np.zeros_like(src)
    transformed_images.append(blank_image)

# 分割图像列表为两行
first_row = transformed_images[:3]
second_row = transformed_images[3:6]

# 水平拼接每行的图像
h_concat_first_row = cv.hconcat(first_row)
h_concat_second_row = cv.hconcat(second_row)

# 垂直拼接两行的图像
final_image = cv.vconcat([h_concat_first_row, h_concat_second_row])

第五部分是显示和保存图像:

# 显示和保存最终拼接图像
cv.imshow('Concatenated Images', final_image)
cv.imwrite('concatenated_images.png', final_image)

# 等待按键关闭窗口
cv.waitKey()
cv.destroyAllWindows()

代码运行相关的图像有:

图2 初始图像

 图3 多个霍夫曲线变换图像对比图像

图5显示了多个霍夫直线变换图像对比效果,相对来说,第一行第三列的图像效果好一些。

第一行第三列的图像和第一行第二列的图像相比,调高了圆心最小间距,从70到100,圆形数量减少;

第二行第一列的图像和第一行第三列的图像相比。提高了线段最小长度,从80到100,影响不大,圆形数量和位置均没有变化;

第二行第二列的图像和第二行第一列的图像相比。提高了第二个阈值,从25到50,圆形数量减少,两个较小的圆形消失了;

第二行第三列的图像和第二行第二列的图像相比。增大了最小圆形半径,从10增大到25,圆形数量减少,又一个较小的圆形消失了。

此时的完整代码为:

import cv2 as cv #引入cv2模块
import numpy as np #引入numpy模块

# 读取图片
src = cv.imread('srcpp.png')

# 预处理图像
srcb = cv.medianBlur(src, 3)  # 中值滤波
gray = cv.cvtColor(srcb, cv.COLOR_BGR2GRAY)  # 将图像转化为灰度图

# 定义霍夫圆检测的参数列表
hough_params_list = [
    (70, 100, 25, 10, 50),
    (100, 100, 25, 10, 50),
    (100, 120, 25, 10, 50),
    (100, 120, 50, 10, 50),
    (100, 120, 50, 25, 50)
]

transformed_images = [src.copy()]  # 先将原始图像添加到列表中

# 进行霍夫圆检测并绘制圆形
for i,(minDist, param1, param2, minRadius, maxRadius) in enumerate(hough_params_list,start=1):
    circleparams = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)
    circleimg =src.copy() #复制原始图像进行绘图
    if circleparams is not None:
        circles = np.uint16(np.around(circleparams))
        for circle in circles[0,:]:
            x, y, r = circle
            circleimg=cv.circle(circleimg, (x, y), r, (200, 150, 200), 5)
        transformed_images.append(circleimg) #图像逐个累加

# 确保图像数量足够进行两行三列的拼接
while len(transformed_images) < 6:
    # 如果图像数量不足 6 个,用空白图像填充
    blank_image = np.zeros_like(src)
    transformed_images.append(blank_image)

# 分割图像列表为两行
first_row = transformed_images[:3]
second_row = transformed_images[3:6]

# 水平拼接每行的图像
h_concat_first_row = cv.hconcat(first_row)
h_concat_second_row = cv.hconcat(second_row)

# 垂直拼接两行的图像
final_image = cv.vconcat([h_concat_first_row, h_concat_second_row])

# 显示和保存最终拼接图像
cv.imshow('Concatenated Images', final_image)
cv.imwrite('concatenated_images.png', final_image)

# 等待按键关闭窗口
cv.waitKey()
cv.destroyAllWindows()

【4】细节说明

cv.circle()函数有一个特点是,如果没有反复说明,多个cv.circle()函数依次放在一起时,后面的圆形其实会在前面已经画过圆形的图像上继续画圆,并且每个图都指向了最后的画圆效果。

比如圆形绘制代码:

c1=cv.circle(src,(x1,y1),r,(200,150,200),5)
c2=cv.circle(c1,(x1,y1),50,(200,150,200),5)
cv.imshow('c1', c1)
cv.imshow('c2', c2)

图像c1和c2显示的效果一样。

为了让每次绘制圆形的效果单独呈现,需要不断把最初的圆形绘制模板复制出来,这就是 circleimg =src.copy() #复制原始图像进行绘图代码的意义:

for i,(minDist, param1, param2, minRadius, maxRadius) in enumerate(hough_params_list,start=1):
    circleparams = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, minDist=minDist, param1=param1, param2=param2, minRadius=minRadius, maxRadius=maxRadius)
    circleimg =src.copy() #复制原始图像进行绘图
    if circleparams is not None:
        circles = np.uint16(np.around(circleparams))
        for circle in circles[0,:]:
            x, y, r = circle
            circleimg=cv.circle(circleimg, (x, y), r, (200, 150, 200), 5)
        transformed_images.append(circleimg) #图像逐个累加

如果对圆形绘制技巧不太熟悉,可以通过下述链接回忆:

python学opencv|读取图像(二十)使用cv2.circle()绘制圆形_python cv2.circle-CSDN博客

【5】总结

掌握了python+opencv实现使用cv2.HoughCircles()函数实现图像中的霍夫圆形检测的技巧。