霍夫圆检测代码:
#-*- coding: UTF-8 -*-
'''
实现PEPB快速排版:ctl+alt+l
霍夫圆变换原理:
1、从平面到极坐标转换三个参数C(x0,y0,r)其中x0,y0是圆心;
2、假设平面坐标的任意一个圆上的点,转换到极坐标中,C(x0,y0,r)处有最大值,该点为圆心,反推其半径,检测为圆
(在一个圆上C,选任意个点,以这些点作为圆心绘制圆,这些圆会交于一点,该点为圆C的圆心)
霍夫圆检测对噪声敏感,所以先对图像做中值滤波
基于效率,OpenCV中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:
1、检测边缘,发现可能的圆心
2、基于第一步的基础上从候选圆心开始计算最佳半径大小
'''
import cv2 as cv
import numpy as np
def detectCircleDemo(image):
dst = cv.pyrMeanShiftFiltering(image,2,110 ) # 因为霍夫圆检测最噪声敏感,故因通过边缘滤波去噪
#sigmaSpace:尽量取小,那么“和”就小一点,主要的差异就保留下来;sigmaColor:尽量取大,目的将小的差异模糊掉,噪声去掉
cimage = cv.cvtColor(dst, cv.COLOR_BGR2GRAY) # 转为灰度图像
circles = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 90, param1=100, param2=20, minRadius=0, maxRadius=60)
'''
第二个参数默认,因为检测圆的方法,OpenCV2.*.*版本之中只有霍夫梯度法
第三个参数可以设置为1就行--默认参数,步长
第四个参数:非常重要!!是圆心与圆心之间的距离,这是一个经验值。这个大了,那么多个圆就是被认为一个圆
第五个参数 就设为默认值就OK
第六个参数是根据你的图像中的圆大小设置,当这张图片中的圆越小,那么此值就设置应该被设置越小。当设置的越小,那么检测出的圆越多,在检测较大的圆时则会产生很多噪声。所以要根据检测圆的大小变化。
第七个和第八个参数 是你检测圆 最小半径和最大半径是多少。这个值也是为了进一步筛选检测出的圆
'''
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, (0, 0, 255), 2)#画圆心:实质是一个小圆,此处设为一个半径为2个像素的小圆
cv.imshow("circles", image)
src = cv.imread("E:\OpenCVTests/timg (3).jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
detectCircleDemo(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果:为使圆检测结果准确,需要根据不同的图像调整各个API的参数
轮廓提取代码:
# -*- coding: UTF-8 -*-
import cv2 as cv
import numpy as np
# 轮廓查找
def edgeDemo(image):
blurred = cv.GaussianBlur(image, (3, 3), 0) # 降低噪声,因为Canny对噪声敏感
gray = cv.cvtColor(blurred, cv.COLOR_BGR2GRAY)
# 梯度值计算
xgrad = cv.Sobel(gray, cv.CV_16SC1, 1, 0)
ygrad = cv.Sobel(gray, cv.CV_16SC1, 0, 1) # 第三个参数为处理图像的深度,此处应该用整数型
# edgeOutPut=cv.Canny(gray,50,150)-----亦可使用本方法
edgeOutPut = cv.Canny(xgrad, ygrad, 50, 150)
return edgeOutPut
def contoursDemo(image):
dst = cv.GaussianBlur(image, (3, 3),0) # 高斯模糊,去噪点
gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU) # 二值化
cv.imshow("binaryImage", binary)
#binary = edgeDemo(image)
contous, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
#函数cv2.findContours()有三个参数。第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。
#而返回值根据OpenCV版本不同也不一样,但这俩个版本都会返回一个元组。OpenCV2.x版本第一个元素是轮廓,而在OpenCV3.x中第二个才是轮廓。这个轮廓是一个列表,每个列表元素代表着一个轮廓。
#本代码段使用的是OpenCV2.x版本
for i, contou in enumerate(contous): # 容器循环
cv.drawContours(image, contous, i, (0, 0, 255), 2) # 最后一个参数为-1时,填充
#第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,
#第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,
#第四个参数color为轮廓的颜色
#第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部
print(i)
cv.imshow("detectContour", image)
src = cv.imread("E://OpenCVTests//timg (3).jpg")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
contoursDemo(src)
cv.waitKey(0)
cv.destroyAllWindows()
运行结果:依次为原图、二值化图、查找轮廓结果