python+opencv--Hough直线检测

python+opencv–Hough直线检测

通过Canny算子等边缘检测方法获得图像的边缘信息之后, 我们得到仅是多组连续的边缘像素点, 这些像素点包含了极为有用的信息, 但是这些信息我们无法直接使用, 因为图像噪声和图像像素误差的存在,图像的边缘轮廓并不是规则的几何线条, 不能直接通过函数来表达。比如从下面的建筑物图片和Canny算子提取的边缘图中,可以明显看到边缘图像中包含了大量建筑物的边缘信息。
建筑物原图
Canny边缘检测
但是,放大建筑物的边缘图像, 可以发现原来我们主观认为很笔直的建筑, 在图像中并不是笔直的线条,而是曲折的像素点, 如下图所示, 因此边缘检测之后还需要对图像边缘进行特征提取, 从离散的像素点中提取有用的特征信息.
在这里插入图片描述

Hough变换

在直线检测中, Hough变换采用参数空间变换的方法提取边缘像素带中直线, Hough变换可以降低噪声的影响,对连续直线的检测具有鲁棒性.
在这里插入图片描述
在直角坐标系中, 直线的方程为: y = k x + b y = kx + b y=kx+b.
直线方程可以唯一的用 ( k , b ) (k,b) (k,b)来表示,也可以用极坐标中 ( ρ , θ ) (ρ,\theta) (ρ,θ)唯一的表示。其中, ρ \rho ρ表示直线垂点到原点的距离, θ \theta θ表示 ρ \rho ρ x x x轴的夹角。
直线方程是唯一的,所以直线上所有的点在极坐标系中对应 ( ρ , θ ) (\rho,\theta) (ρ,θ)也是唯一的。
而直角坐标系中的一个点 ( x , y ) (x,y) (x,y),过该点的直线可能有无数条,这无数条直线与 x x x轴的夹角取值范围是 [ 0 , 2 π ] [0, 2\pi] [0,2π],则直角坐标系中的一个点对应于极坐标系中的一条正弦曲线
ρ = x c o s θ + y s i n θ \rho=xcos\theta + ysin\theta ρ=xcosθ+ysinθ
同一条直线的 ( ρ , θ ) (\rho, \theta) (ρ,θ)是唯一的,因此同一条直线上的点在极坐标中的正弦曲线必然相交于一点

轮廓边缘像素点在直角坐标系中的二维像素坐标,转换到极坐标中,就可以得到对应的正弦曲线,如果直接统计所有的正弦曲线的交点,我们会得到很多误匹配的直线。
Hough变换方法是通过统计量化的局部空间的正弦曲线交点,数量满足阈值条件的点才会被选做直线拟合点,具体方法为:

  • ( ρ , θ ) (\rho, \theta) (ρ,θ)空间量化成许多小格子
  • 将图像平面直角坐标系中的每一个直线点变换到 ( ρ , θ ) (\rho, \theta) (ρ,θ)空间
  • 统计每个小格子中的共线点,设置累计阈值 T T T,如果小格子中的共线点数量大于 T T T,则格子中的共线点可以用于拟合直线参数,小于 T T T的格子被认为是非共线点,丢弃

opencv函数

opencv中提供了两个函数用于Hough直线检测

  • cv.HoughLines()

    C++:
    	void cv::HoughLines	(	InputArray 	image, 		# 输入单通道8-bit二值化图像
    			OutputArray 	lines, 	 # 输出的直线向量,每条直线用2或3个元素向量(ρ,θ)表示
    			double 	rho, 				# 累加器的像素分辨率,一般取1像素
    			double 	theta,			# 累加器的角度分辨率(弧度),一般取np.pi/180
    			int 	threshold,				# 累加器阈值
    			
    			''' srn用于多尺度Hough变换,粗累加器距离分辨率为rho,
    			精确累加器的分辨率为rho/srn(提高提取精度),
    			srn和stn取0的话表示采用经典Hough变换,不使用多尺度Hough变换'''
    			double 	srn = 0,			
    			double 	stn = 0,									# 同上,针对角度分辨率theta
    			double 	min_theta = 0, 					# 检测直线的最小角度
    			double 	max_theta = CV_PI 		# 检测直线的最大角度
    			)		
    Python:
    	lines	=	cv.HoughLines(	image, rho, theta, threshold[, lines[, srn[, stn[, min_theta[, max_theta]]]]]	)
    
    • cv.HoughLinesP()
      Hough变换的改进版本——概率Hough变换
    C++:
    	void cv::HoughLinesP	(	InputArray 	image,
    			OutputArray 	lines,
    			double 	rho,
    			double 	theta,
    			int 	threshold,
    			double 	minLineLength = 0,	# 最小直线长度
    			double 	maxLineGap = 0 			# 最大线段间隙
    			)		
    Python:
    	lines	=	cv.HoughLinesP(	image, rho, theta, threshold[, lines[, minLineLength[, maxLineGap]]]	)
    

示例代码

import cv2 as cv
import numpy as np
import matplotlib as plt

# read image and check
filename = "/home/lihoon/code/opencvImg/hough/building.jpg"
img = cv.imread(filename)
img_p = img.copy() #用于显示概率Hough变换的检测结果

if img is None:
    print("Image read error!")
else:
    print("Image read successful!")
# cv.imshow("Source", img)

# image space change from BGR to GRAY
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)

# threshold
# _, binary = cv.threshold(img, 200, 255, cv.THRESH_BINARY)
_, binary = cv.threshold(gray, 0, 255, cv.THRESH_OTSU)
# cv.imshow("Threshold", binary)

# edges detection with Canny method
edges = cv.Canny(binary, threshold1=50, threshold2=200)
# cv.imshow("Canny", edges)

# HoughLines()函数
lines = cv.HoughLines(edges, rho = 1, theta = 1 * np.pi/180, threshold=120, srn=0, stn = 0, min_theta=1, max_theta=2)

for i in range(0, len(lines)):
    rho, theta = lines[i][0][0], lines[i][0][1]
    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(img, (x1, y1), (x2, y2), (0, 0, 255), 2)

cv.imshow("Hough_line", img)

# HoughLinesP()函数
lines_p = cv.HoughLinesP(edges, rho = 1, theta = np.pi/180, threshold = 50, minLineLength= 30, maxLineGap=10)

for i in range(len(lines_p)):
    x_1, y_1, x_2, y_2 = lines_p[i][0]
    cv.line(img_p, (x_1, y_1), (x_2, y_2), (0, 255, 0), 2)

print("code successful!")
cv.imshow("Hough_line_p", img_p)

cv.waitKey(0)
cv.destroyAllWindows()

检测结果如下图所示
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值