要求:求出下图中心拟合圆的圆心坐标与半径,以及轮廓圆的面积与圆度。
import cv2
import numpy as np
import math
#读图
img=cv2.imread('jpg/3.jpg')
#图太大,方便观看,缩小为原来的0.4倍
resize = cv2.resize(img,dsize=None,fx=0.4,fy=0.4,interpolation=cv2.INTER_LINEAR)
cv2.imshow('ori',resize)
#灰度化
gray = cv2.cvtColor(resize, cv2.COLOR_BGR2GRAY)
#阈值
ret, img = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 中值滤波 效果好
img_median = cv2.medianBlur(img, 5)
#膨胀一下,方便观看
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
dst = cv2.dilate(img_median, kernel)
#边缘检测
canny = cv2.Canny(dst, 50, 150)
#霍夫找圆
circles = cv2.HoughCircles(canny,cv2.HOUGH_GRADIENT,1,700,param1=100,param2=20,minRadius=20,maxRadius=800)#霍夫圆变换
#第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(resize,(i[0],i[1]),(i[2]),(0,255,0),2)#第二参数()内是圆心坐标,第三参数是半径,第四参数()内是颜色,第五参数是线条粗细
# 画出圆心
cv2.circle(resize,(i[0],i[1]),2,(0,0,255),3)
#roi的掩码
roi = np.zeros(img_median.shape[:2], np.uint8)
#加上3的话,方便看圆度
roi = cv2.circle(roi, (i[0],i[1]),(i[2]+3), 255, cv2.FILLED)
#根据找出的圆来进行Roi合成
mask = np.ones_like(img_median) * 255
mask = cv2.bitwise_and(mask, img_median, mask=roi) + cv2.bitwise_and(mask, mask, mask=~roi)
#霍夫找圆的结果
print("圆的个数是:")
print(len(P))
for i in P:
r=int(i[2])
x=int(i[0])
y=int(i[1])
print("圆心坐标为:",(x,y))
print("圆的半径是:",r)
cv2.imshow('detected circles',resize)#第一参数为窗口名称
#roi区域进行处理
gaussian = cv2.GaussianBlur(mask, (3, 3), 0)
canny1 = cv2.Canny(gaussian, 50, 150)
cv2.imshow('canny1',canny1)
#对roi区域进行找轮廓,现在是实际圆形的轮廓
contours1, hierarchy = cv2.findContours(canny1,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
IMG_OUT = cv2.cvtColor(mask, cv2.COLOR_GRAY2RGB)
cv2.drawContours(IMG_OUT,contours1,-1,(0,0,255),1)
cv2.imshow('mask after operation', IMG_OUT)
#根据找出的轮廓找出最大的一个轮廓,就是那个圆
img_contours = []
for i in range(len(contours1)):
area = cv2.contourArea(contours1[i], False)
if area > 10000:
print("轮廓%d的面积是: %d" % (i, area))
cv2.drawContours(resize, contours1, i, (0, 0, 255), 1)
cv2.imshow("contours %d" % i, resize)
# 圆度计算公式:
# 4*PI*A/P^2
# 其中PI表示Π,A表示区域面积,P表示区域周长
a = cv2.contourArea(contours1[i]) * 4 * math.pi
b = math.pow(cv2.arcLength(contours1[i], True), 2)
circulation= a / b
print("圆度",circulation)
cv2.waitKey(0)