话不多说直接上图:
# 加载环境包
import cv2
import numpy as np
# from PIL import Image
# 图片简单处理
img = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\hh_08.bmp') # 读取图片
GrayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 灰度化
GrayImage = cv2.medianBlur(GrayImage, 25) # 中值模糊,medianBlur()函数使用中值滤波器来平滑图像。
# 阈值处理,输入图片默认为单通道灰度图片
ret, th1 = cv2.threshold(GrayImage, 127, 255, cv2.THRESH_TOZERO) # 固定阈值二值化
# threshold为固定阈值二值化
# 第二参数为阈值
# 第三参数为当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值(一般情况下,都是256色,所以默认最大为255)
# thresh_binary是基于直方图的二值化操作类型,配合threshold一起使用。此外还有cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV;
# cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
th2 = cv2.adaptiveThreshold(GrayImage, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 5)
# adaptiveThreshold自适应阈值二值化,自适应阈值二值化函数根据图片一小块区域的值来计算对应区域的阈值,从而得到也许更为合适的图片。
# 第二参数为当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值(一般情况下,都是256色,所以默认最大为255)
# 第三参数为阈值计算方法,类型有cv2.ADAPTIVE_THRESH_MEAN_C,cv2.ADAPTIVE_THRESH_GAUSSIAN_C
# 第四参数是基于直方图的二值化操作类型,配合threshold一起使用。此外还有cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV;
# cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
# 第五参数是图片中分块的大小
# 第六参数是阈值计算方法中的常数项
th3 = cv2.adaptiveThreshold(GrayImage, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 3, 5)
# 同上
kernel = np.ones((6, 9), np.uint8) # 创建全一矩阵,数值类型设置为uint8
erosion = cv2.erode(th2, kernel, iterations=1) # 腐蚀处理
dilation = cv2.dilate(erosion, kernel, iterations=1) # 膨胀处理
imgray = cv2.Canny(erosion, 30, 100) # Canny算子边缘检测
# cv2.imshow("s", dilation)
circles = cv2.HoughCircles(imgray, cv2.HOUGH_GRADIENT, 1, 40, param1=100, param2=5.5, minRadius=8,
maxRadius=10) # 霍夫圆变换
# 第3参数默认为1
# 第4参数表示圆心与圆心之间的距离(太大的话,会很多圆被认为是一个圆)
# 第5参数默认为100
# 第6参数根据圆大小设置(圆越小设置越小,检测的圆越多,但检测大圆会有噪点)
# 第7圆最小半径
# 第8圆最大半径
circles = np.uint16(np.around(circles))
# np.uint16数组转换为整数,16位,0-65535
# np.around返回四舍五入后的值
P = circles[0] # 去掉circles数组一层外括号
for i in P:
# 画出外圆
cv2.circle(img, (i[0], i[1]), i[2], (0, 255, 0), 2) # 第二参数()内是圆心坐标,第三参数是半径,第四参数()内是颜色,第五参数是线条粗细
# 画出圆心
cv2.circle(img, (i[0], i[1]), 2, (0, 0, 255), 3)
print("圆的个数是:")
print(len(P))
# 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。
fresult = open('C:\\Users\\Tony.Hsu\\Desktop\\result.txt', 'w')
for i in P:
r = int(i[2])
x = int(i[0])
y = int(i[1])
print("圆心坐标为:", (x, y))
# 将圆心写入文件
fresult.writelines("圆心坐标为:(" + str(i[0]) + "," + str(i[1]) + ")" + "\n")
print("圆的半径是:", r)
cv2.imshow('detected circles', img) # 第一参数为窗口名称
cv2.waitKey(0) # 无穷大等待时间
cv2.destroyAllWindows()
1.medianBlur()函数:使用中值滤波器来平滑图像。
dst = cv2.medianBlur(src, ksize[, dst])-----该函数使用具有ksize*ksize孔径大小的中值滤波器来平滑图像。对多通道图像的各通道独立处理。支持in-place操作。
在边界类型( BorderTypes)方面,使用的是 BORDER_REPLICATE 。
2.python关于图片二值化在图片中已有详细注释,补充内容可参考此文章:https://blog.csdn.net/sinat_21258931/article/details/61418681
3.开运算闭运算可参考此文章:https://blog.csdn.net/caojinpei123/article/details/81916005
4.腐蚀:会把物体的边界腐蚀掉,卷积核沿着图象滑动,如果卷积核对应的原图的所有像素值为1,那么中心元素就保持原来的值,否则变为零。主要应用在去除白噪声,也可以断开连在一起的物体。
膨胀:卷积核所对应的原图像的像素值只要有一个是1,中心像素值就是1。一般在除噪是,先腐蚀再膨胀,因为腐蚀在去除白噪声的时候也会使图像缩小,所以我们之后要进行膨胀。当然也可以用来将两者物体分开。
"""
腐蚀
cv2.erode(src, # 输入图像
kernel, # 卷积核
dst=None,
anchor=None,
iterations=None, # 迭代次数,默认1
borderType=None,
borderValue=None)
膨胀
cv2.dilate(src, #输入图像
kernel, dst = None, anchor = None,
iterations = None #迭代次数,默认1
borderType = None,
borderValue = None)
"""
5.cv2.Canny()函数,
函数原型是这样的:edge = cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
image参数表示8位输入图像。
threshold1参数表示设置的低阈值minVal。
threshold2参数表示设置的高阈值maxVal,一般设定为低阈值的3倍 (根据Canny算法的推荐)。
edges参数表示输出边缘图像,单通道8位图像。
apertureSize参数表示Sobel算子(卷积核)的大小。
L2gradient参数表示一个布尔值,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开方),否则使用L1范数(直接将两个方向导数的绝对值相加)。
6.霍夫变换检测圆原理
7.霍夫变换检测圆函数:
cv.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
image:为输入图像,要求是灰度图像
method:为使用霍夫变换圆检测的算法
dp:用来检测圆心的累加器图像的分辨率于输入图像之比的倒数,此参数允许创建一个比输入图像分辨率低的累加器。例如,如果dp = 1时,累加器和输入图像具有相同的分辨率。如果dp = 2,累加器便有输入图像一半那么大的宽度和高度,为第一阶段所使用的霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一半。一般默认为1
minDist:为圆心之间的最小距离,如果检测到的两个圆心之间距离小于该值,则认为它们是同一个圆心,(太大的话,会很多圆被认为是一个圆)
circles- 找到的圆的输出向量。每个向量被编码为3元素的浮点向量 (x,y,半径).(可省略)
param1:阈值。第一个方法特定的参数。在CV_HOUGH_GRADIENT的情况下, 两个传递给Canny()边缘检测器的阈值较高(较小的两个小于两倍)。一般默认为100
param2:阈值。第二种方法参数。在CV_HOUGH_GRADIENT的情况下 ,它是检测阶段的圆心的累加器阈值。越小,可能会检测到越多的虚假圈子。首先返回对应于较大累加器值的圈子。(圆越小设置越小,检测的圆越多,但检测大圆会有噪点)
minRadius:所检测到的圆半径的最小值
maxRadius:所检测到的圆半径的最大值
8.画出圆和圆心,并写入文件(详见注释)
9.Python文件操作说明
本实验重点在于调参数,尤其是卷积核,阈值以及霍夫圆函数的参数调整,经过多次调参之后才能得到理想的实验结果。
对于不同的图片,参数要相应发生变化,就得再次调整参数。
参考文章:https://blog.csdn.net/weixin_41008860/article/details/88343696
https://blog.csdn.net/wsp_1138886114/article/details/82917661