1,霍夫变换
霍夫变换是图像处理中从图像中识别几何形状的基本方法之一。主要用来从图像中分离出具有某种相同特征的几何形状(如,直线,圆等)。最基本的霍夫变换是从黑白图像中检测直线(线段)。
霍夫变换最简单的是检测直线。,直线的方程表示可以由斜率和截距表示(这种表示方法,称为斜截式),如下所示:
但是这样会参数问题,垂直线的斜率不存在(或无限大),这使得斜率参数m的值接近于无限。为此,为了更好的计算,提出了Hesse normal form(Hesse法线式):
其中r是原点到直线上最近点的距离(其他人可能把这记录为ρ,下面也可以把r看成参数ρ),θ是x轴与连接原点和最近点直线之间的夹角。因此,可以将图像的每一条直线与一对参数(r,θ)相关联。这个参数(r,θ)平面有时被称为霍夫空间,用于二维直线的集合。
在图像分析上下文,边缘段的点(一个或多个)的坐标(xi,yi)在图像中是已知的,并且因此作为参数线等式中的常量,而r与θ是未知变量是我们要寻找的。如果我们绘制由(r,θ)每个定义的可能值(xi,yi),笛卡尔图像空间中的点映射到极性霍夫参数空间中的曲线(即正弦曲线)。这个点到曲线的变换是直线的霍夫变换。当在霍夫参数空间中查看时,在笛卡尔图像空间中共线的点变得很明显,因为它们产生在相同(r,θ)点相交的曲线。
该变换的结果存储在矩阵中。单元格值表示通过任意点的曲线数量。更高的单元格值变得更亮。明显的亮点是直线的霍夫参数。从这些点的位置,可以确定输入图像中两条线的图像中心的角度和距离.
源代码示例:
import cv2 as cv
import numpy as np
def line_detection(image): #直线检测
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edges = cv.Canny(gray, 50, 150, apertureSize=3) #apertureSize是sobel算子窗口大小
lines = cv.HoughLines(edges, 1, np.pi/180, 200) #指定步长为1的半径和步长为π/180的角来搜索所有可能的直线
"""
oughLines(image, rho, theta, threshold, lines=None, srn=None, stn=None, min_theta=None, max_theta=None)
第一个参数image:是canny边缘检测后的图像
第二个参数rho和第三个参数theta:对应直线搜索的步长。在本例中,函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线。
最后一个参数threshold:是经过某一点曲线的数量的阈值,超过这个阈值,就表示这个交点所代表的参数对(rho, theta)在原图像中为一条直线
"""
for line in lines:
# print(type(lines))
rho, theta = line[0]#获取极值ρ长度和θ角度
a = np.cos(theta)
b = np.sin(theta)
x0 = a * rho #获取x轴值
y0 = b * rho
x1 = int(x0+1000*(-b)) #获取这条直线最大值点x1
y1 = int(y0+1000*(a))
x2 = int(x0-1000*(-b))
y2 = int(y0-1000*(a))#获取这条直线最小值点y2 其中*1000是内部规则
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)
lines = cv.HoughLinesP(edges, 1, np.pi/180, 100, minLineLength=50, maxLineGap=10)
"""
HoughLinesP概率霍夫变换(是加强版)使用简单,效果更好,检测图像中分段的直线(而不是贯穿整个图像的直线)
第一个参数是需要处理的原图像,该图像必须为cannay边缘检测后的图像;
第二和第三参数:步长为1的半径和步长为π/180的角来搜索所有可能的直线
第四个参数是阈值,概念同霍夫变换
第五个参数:minLineLength-线的最短长度,比这个线短的都会被忽略。
第六个参数:maxLineGap-两条线之间的最大间隔,如果小于此值,这两条线就会被看成一条线
"""
for line in lines:
# print(type(line))
x1, y1, x2, y2 = line[0]
cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow("line_detect_possible_demo", image)
src = cv.imread("F:/images/morph01.png")
cv.namedWindow("input image", cv.WINDOW_AUTOSIZE)
cv.imshow("input image", src)
line_detection(src)
line_detect_possible_demo(src)
cv.waitKey(0)
cv.destroyAllWindows()