1、霍夫变换是一种在图像中寻找直线、圆形及其他简单形状的方法。
2、笛卡尔空间与霍夫空间映射关系
3、霍夫变换选择直线的基本思路:选择由尽可能多条线汇成的点。
1、绘制直线方法
2、cv.line优点
没有必要检查交叉点是否位于图像内部,即使点的坐标超出了图像的范围,也能正确画出线来。
3、基本霍夫变换——HoughLines函数
(1)要求:所操作的原图像是一个二值图像,变换之前先将原图像进行二值化或进行canny边缘检测。
(2)HoughLines检测到的是图像中的直线而不是线段,即检测到的直线是没有端点的。
(3)代码
# 直线检测
def line_detection(image):
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
edges = cv.Canny(gray, 50, 150, apertureSize=3)
"""
HoughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None)
image:8位,单通道二值源图像
rho:以像素为单位的距离r的精度,一般为1.
theta:角度0的精度, CV.PI/180表示搜索所有可能的角度。
threshold:阈值,线段超过设定的阈值才被检测出来。值越小,判定出的直线就越多。
lines:检测到的直线的参数vector(ρ,θ) or (ρ,θ,votes) ;ρ是距坐标原点的距离,θ是以弧度表示的线旋转角度(0∼垂直直线,π/2∼水平直线) ,votes 曲线交点累加计数
srn:
stn:
min_theta:检查线条的最小角度。必须介于0和maxθ之间。
max_theta:要检查线条的最大角度。必须介于minθ和CV_PI之间
"""
lines = cv.HoughLines(edges, 1, np.pi / 180, 200)
# 遍历lines,绘制出所有的直线
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho
y0 = b * rho
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * a)
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * a)
cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow('image_lines', image)
概率霍夫变换没有考虑所有的点,只需要一个足以进行检测的随机点子集即可。
def line_detect_possible_demo(image):
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150, apertureSize=3)
"""
HoughLinesP(image, rho, theta, threshold, lines=None, minLineLength=None, maxLineGap=None)
minLineLength:用来控制“接受直线的最小长度”的值,默认0
maxLineGap:用来控制接受共线线段之间的最小间隔,如果两点之间的最大间隔大于maxLineGap,认为这两点不在一条线上,默认0
"""
lines = cv.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
for line in lines:
x1, y1, x2, y2 = line[0]
cv.line(image, (x1, y1), (x2, y2), (0, 255, 0), 2)
cv.imshow('line_detect_possible_demo', image)
在霍夫圆变换中,需要考虑圆半径和圆心(x坐标,y坐标)共3个系数,采用的策略是两轮筛选。第1轮筛选找出可能存在圆的位置(圆心),第2轮再根据第1轮的结果筛选出半径大小。
def Mdetect_circles_demo(image):
"""
:param image: pyrMeanShiftFiltering(src, sp, sr, dst=None, maxLevel=None, termcrit=None)
:return: src:输入图像,8位,三通道的彩色图像
sp:定义的漂移物理空间半径大小
sr:定义的漂移色彩空间半径大小
dst:输出图像,跟输入src有同样的大小和数据格式
maxLevel:定义金字塔的最大层数
termcrit:定义的漂移迭代终止条件,可以设置为迭代次数满足终止,迭代目标与中心点偏差满足终止,或者两者的结合
"""
# pyrMeanShiftFiltering:漂移圆检测
dst = cv.pyrMeanShiftFiltering(image, 50, 30)
circles = np.uint16(np.around(dst))
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('Mdetect_circles_demo', image)
def circles_demo(image):
# 消除噪声
cimage = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
circle = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circle))
for i in circles[0, :]:
# 取圆心
cv.circle(image, (i[0], i[1]), 2, (255, 0, 0), 2)
cv.imshow('circles_demo', image)
def detect_circles_demo(image):
# 消除噪声
cimage = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
"""
HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)
image:8位单通道灰度图像
method:检测方法,HOUGH_GRADIENT:基于梯度做比较快且是唯一可用的参数值
dp:累加器分辨率,用来指定图像分辨率与圆心累加器分辨率的比率。1表示输入图像和累加器具有相同的分辨率。
minDist:圆心间的最小间距。如果存在圆心间距离小于该值的圆,仅有一个会被检测出来。如20:把小于20最近的多个合并成一个圆。
circles:返回值,由圆心坐标和半径构成的numpy.ndarry
param1:缺省,默认100.对应是canny边缘检测器的高阈值(底阈值是高阈值的二分之一)
param2:圆心位置必须收到的投票数。值越大,检测到的圆越少;越小,检测到的圆越多。缺省,默认100.
minRadius:圆半径的最小值,小于该值的圆不会被检测出来。缺省,默认0,不起作用。
maxRadius:圆半径的最大值,大于该值的圆不会被检测出来。缺省,默认0,不起作用。
"""
circle = cv.HoughCircles(cimage, cv.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
"""
around(a, decimals=0, out=None)
a:输入列表或矩阵
decimals:为n对输入近似后保留小数点后n位,默认为0,若值为-n,则对小数点左边第n位近似
out:保存近似返回结果
"""
circles = np.uint16(np.around(circle))
for i in circles[0, :]:
# 图像,中心点位置,半径,颜色
"""
circle(img, center, radius, color, thickness=None, lineType=None, shift=None)
img:单通道或多通道的图像
center:圆心坐标
radius:半径,数值为整数类型
color:圆线条的颜色
thickness:圆线条的粗细,值越大则线条越粗。
lineType:线条的类型。CV_AA(采用了高斯滤波)三个值,分别代表8邻接连接线,4邻接连接线和反锯齿连接线,默认值为8邻接。
shift:圆心坐标点和半径值的小数点位数,数值为整数类型。
"""
# 圆变换
cv.circle(image, (i[0], i[1]), i[2], (0, 0, 255), 2)
cv.imshow('detect_circles_demo', image)