1.霍夫变换
霍夫变换(Hough Transform)于1962年首次提出,是图像处理领域内从图像中检测几何形状的基本方法之一。经典霍夫变换用来检测图像中的直线,后来霍夫变换经过扩展可以进行任意形状物体的识别,例如圆和椭圆。
霍夫变换运用两个坐标空间之间的变换,将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。
2.霍夫直线变换
霍夫直线变换是一种用来寻找直线的方法,其原理为:
一条直线在图像二维空间可由两个变量表示,分别为:
(1).在笛卡尔坐标系:可由斜率和截距(k,b)表示;
(2).在极坐标系:可由极径和极角(r,θ)表示。
对于霍夫变换,我们采用第二种方式极坐标系来表示直线,因此,直线的表达式为:y=(-cosθ/sinθ)x+r/sinθ
经过化简后,r=xcosθ+ysinθ
对于点(x0,y0),可以将通过该点的直线统一定义为:
r0=x0cosθ+y0sinθ
这意味着(r0,θ)代表一条通过点(x0,y0)的直线。
一条直线能够通过在平面θ-r寻找交于一点的曲线数量来检测。而越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成。一般来说我们可以设置直线上的点的阈值来定义多少条曲线交于一点,这样才认为检测到了一条直线。
霍夫直线检测就是追踪图像每个点对应曲线间的交点,如果交于一点的曲线的数量超过了阈值,便可认为该交点所代表的参数对(r0,θ)在图像中为一条直线。
利用霍夫变换检测直线的步骤为:
1.彩色图像—>灰度图像;
2.边缘提取;
3.映射到霍夫空间;
4.取局部极大值,设定阈值,过滤干扰直线;
5.绘制直线。
2.1霍夫检测的Opencv实现
OpenCV支持三种霍夫直线检测算法:
1)Standard Hough Transform(SHT,标准霍夫变换)
2)Multiscale Hough Transform(MSHT,多尺度霍夫变换)
3)Progressive Probability Houth Transform(PPHT,渐进概率式霍夫变换)
在使用霍夫检测时,会用到两个函数,分别是HoughLines和HoughLinesP。
2.1.1HoughLines(标准霍夫变换,多尺度霍夫变换)
def line_detection(image): # 标准霍夫变换,多尺度霍夫变换
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edge = cv.Canny(gray, 50, 150, apertureSize=3) # apertureSize是sobel算子大小,只能为1,3,5,7
lines = cv.HoughLines(edge, 1, np.pi / 180, 200) # 函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
# 这里注意第四个参数,表示阈值,阈值越大,表明检测的越精准,速度越快,得到的直线越少(得到的直线都是很有把握的直线)
# 依次画出每条线段
for line in lines:
# print(type(lines))
rho, theta = line[0] # 获取极值ρ长度和θ角度
a = np.cos(theta) # 获取角度cos值
b = np.sin(theta) # 获取角度sin值
x0 = a * rho # 获取x轴值
y0 = b * rho # 获取y轴值 x0和y0是直线的中点
x1 = int(x0 + 1000 * (-b)) # 获取这条直线最大值点x1
y1 = int(y0 + 1000 * (a)) # 获取这条直线最大值点y1
x2 = int(x0 - 1000 * (-b)) # 获取这条直线最小值点x2
y2 = int(y0 - 1000 * (a)) # 获取这条直线最小值点y2 其中*1000是内部规则
cv.line(image, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv.imshow("image-lines", image)
原图为:
结果标准霍夫检测或多尺度霍夫检测后:
2.1.2HoughLinesP(渐进概率式霍夫变换)
def line_detect_possible_demo(image): # 渐进概率式霍夫变换
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edge = cv.Canny(gray, 50, 150, apertureSize=3)
lines = cv.HoughLinesP(edge, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
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)
得到的结果为:
完整代码
import cv2 as cv # 导入opencv模块
import numpy as np # 导入数学函数库
def line_detection(image): # 标准霍夫变换,多尺度霍夫变换
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
edge = cv.Canny(gray, 50, 150, apertureSize=3) # apertureSize是sobel算子大小,只能为1,3,5,7
lines = cv.HoughLines(edge, 1, np.pi / 180, 200) # 函数将通过步长为1的半径和步长为π/180的角来搜索所有可能的直线
# 这里注意第四个参数,表示阈值,阈值越大,表明检测的越精准,速度越快,得到的直线越少(得到的直线都是很有把握的直线)
# 依次画出每条线段
for line in lines:
# print(type(lines))
rho, theta = line[0] # 获取极值ρ长度和θ角度
a = np.cos(theta) # 获取角度cos值
b = np.sin(theta) # 获取角度sin值
x0 = a * rho # 获取x轴值
y0 = b * rho # 获取y轴值 x0和y0是直线的中点
x1 = int(x0 + 1000 * (-b)) # 获取这条直线最大值点x1
y1 = int(y0 + 1000 * (a)) # 获取这条直线最大值点y1
x2 = int(x0 - 1000 * (-b)) # 获取这条直线最小值点x2
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)
edge = cv.Canny(gray, 50, 150, apertureSize=3)
lines = cv.HoughLinesP(edge, 1, np.pi / 180, 100, minLineLength=50, maxLineGap=10)
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)
print("------------hello python!------------")
src = cv.imread("D:/opencv3/Opencv3.2.0/opencv/sources/samples/data/sudoku.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() # 释放所有窗口