OpenCV中HoughLines检测直线原理图解 画线时点的确定:为什么要乘以1000 画出所有直线 Python代码实现

Table of Contents

 

原理图解

OpenCV中HoughLines两个点为什么要乘以1000​

Python代码实现

图片效果


原理图解

 

官方文档解释:

A line can be represented as y = mx+c or in parametric form, as \rho = x \cos \theta + y \sin \theta where \rhois the perpendicular distance from origin to the line, and \theta is the angle formed by this perpendicular line and horizontal axis measured in counter-clockwise ( That direction varies on how you represent the coordinate system. This representation is used in OpenCV).

So if line is passing below the origin, it will have a positive rho and angle less than 180. If it is going above the origin, instead of taking angle greater than 180, angle is taken less than 180, and rho is taken negative. Any vertical line will have 0 degree and horizontal lines will have 90 degree.

笔者翻译及补充:

在笛卡尔坐标系中一条线可以表示为y = mx + c,其中斜率,截距

在极坐标系中表示为ρ= xcosθ + ysinθ其中ρ是从原点到直线的垂直距离,θ是由此垂直线逆时针旋转和水平轴形成角度(该方向根据您表示坐标系的方式而变化。OpenCV用的是如下图所示坐标系,x轴向右,y轴向下)

如果线在原点以下通过(即截距c在原点下方),垂线ρ>0,0<θ<180°,如左图

如果它高于原点(即截距c在原点上方),垂线ρ<0,0<θ<180°,如右图

所有垂直线的角度都是0度,水平线为90度。

更多请参考官方文档

Hough Line Transform

OpenCV中HoughLines两个点为什么要乘以1000

原理:直线的斜率不变

在Python中,返回的lines是一个三维的np.ndarray,shape为(x, 1, 2),

x代表检测到几条直线,最后一维2里面的元素分别是(rho, theta)

它储存了检测到的线条矢量,每一条线由具有两个元素的矢量表示(rho, theta), 

这两个值只能是哪条确定直线,而不能确定线段是从哪开始到哪结束。

在图片上画直线需要两个点(x1, y1)和(x2, y2)(平面中两个点可以确定一条直线)

(你也可以乘以500,800等)

假设x1-x0=1000(-sinθ),那么x1 = x0 + 1000(-sinθ)

假设y1-y0=1000(cosθ),那么y1 = y0 + 1000(cosθ)

同理可得x2 = x0 - 1000(-sinθ),y2 = y0 - 1000(cosθ)

Python代码实现

import cv2
import numpy as np


img = cv2.imread('F:/images/1.jpg')
cv2.imshow('Origin', img)       # 显示图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

lines = cv2.HoughLines(edges, 1, np.pi / 180, 150)
imgCopy = img.copy()
print("lines.shape: ", lines.shape)
print("lines: ", lines)
print("lines[0]:", lines[0])

# 按照官网方法只能画出一条直线
for rho, theta in lines[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))
    cv2.line(img, (x1, y1), (x2, y2), (255, 0, 255), 1)
    print("rho:{}, theta:{}".format(rho, theta))
    print("(x1,y1):{}".format((x1, y1)))
    print("(x2,y2):{}".format((x2, y2)))
cv2.imwrite('houghlines_old.jpg', img)      # 保存图片

# 正确做法是如此,以下三种方法都可
# # 方法一:在原来的三维数组中迭代
for line in lines:
    rho = line[0][0]  # 第一个元素是距离rho
    theta = line[0][1]  # 第二个元素是角度theta
# # 方法二:在原来的三维数组中迭代
# for i in range(0, lines.shape[0]):
#     rho, theta = lines[i, 0]
# # 方法三:先将三维数组转变为二维,再迭代
# lines = lines[:, 0, :]  # 提取为为二维
# print("new lines", lines)
# for line in lines:
#     rho = line[0]  # 第一个元素是距离rho
#     theta = line[1]  # 第二个元素是角度theta
    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))
    cv2.line(imgCopy, (x1, y1), (x2, y2), (0, 0, 255), 1)
cv2.imwrite('houghlines_new.jpg', imgCopy)  # 保存图片

cv2.imshow('Edged', edges)       # 显示图片
cv2.imshow('Hough_Old', img)     # 显示图片
cv2.imshow('Hough_New', imgCopy)    # 显示图片
cv2.waitKey(0)

图片效果

如下:

 

 

 

  • 12
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import cv2 as cv import numpy as np #直线检测 #使用霍夫直线变换做直线检测,前提条件:边缘检测已经完成 #标准霍夫线变换 def line_detection(image): gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY) edges = cv.Canny(gray, 50, 150) #apertureSize参数默认其实就是3 cv.imshow("edges", edges) #cv.HoughLines参数设置:参数1,灰度图像;参数二,以像素为单位的距离精度(一般都是1,进度高,但是速度会慢一点) #参数三,以弧度为单位的角度精度(一般是1rad);参数四,阈值,大于阈值threshold的线段才可以被检测通过并返回到结果 #该函数返回值为rho与theta lines = cv.HoughLines(edges, 1, np.pi/180, 200) for line in lines: rho, theta = line[0] #line[0]存储的是点到直线的极径和极角,其极角是弧度表示的。 a = np.cos(theta) #theta是弧度 b = np.sin(theta) x0 = a * rho #代表x = r * cos(theta) y0 = b * rho #代表y = r * sin(theta) x1 = int(x0 + 1000 * (-b)) #计算直线起点横坐标 y1 = int(y0 + 1000 * a) #计算起始起点纵坐标 x2 = int(x0 - 1000 * (-b)) #计算直线终点横坐标 y2 = int(y0 - 1000 * a) #计算直线终点纵坐标 注:这里的数值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_RGB2GRAY) edges = cv.Canny(gray, 50, 150, apertureSize=3) # apertureSize参数默认其实就是3 lines = cv.HoughLinesP(edges, 1, np.pi / 180, 60, minLineLength=60, maxLineGap=5) for line in lines: 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("E:/opencv/picture/track.jpg") print(src.shape) cv.namedWindow('input_image', cv.WINDOW_AUTOSIZE) cv.imshow('input_image', src) line_detection(src) src = cv.imread("E:/opencv/picture/track.jpg") #调用上一个函数后,会把传入的src数组改变,所以调用下一个函数时,要重新读取图片 line_detect_possible_demo(src) cv.waitKey(0) cv.destroyAllWindows() 霍夫检测直线原理: 关于hough变换,核心以及难点就是关于就是有原始空间到参数空间的变换上。以直线检测为例,假设有一条直线L,原点到该直线的垂直距离为p,垂线与x轴夹角为θθ,那么这条直线是唯一的,且直线的方程为 ρ=xcosθ+ysinθρ=xcosθ+ysinθ, 如下图所
来,你知道如何实现吗? 可以使用OpenCVHoughLines函数来通过霍夫变换检测直线,并使用cv2.line函数在原始图片上画出检测到的直线。具体实现可以参考以下代码: ``` import cv2 import numpy as np # 读取图片 img = cv2.imread('test.jpg') # 转为灰度图像并进行边缘检测 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) edges = cv2.Canny(gray, 50, 150, apertureSize=3) # 进行霍夫变换检测直线 lines = cv2.HoughLines(edges, 1, np.pi / 180, 200) # 在原始图片上画出检测到的直线 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)) cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2) # 展示结果 cv2.imshow('img', img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 以上代码,我们首先读取待检测的图片,然后将其转换成灰度图像并进行边缘检测。接着使用cv2.HoughLines函数进行霍夫变换检测直线,默认情况下该函数会返回检测到的所有直线,并且每条直线由rho和theta两个参数表示。再根据直线的参数rho和theta,使用cv2.line函数在原始图片上画出检测到的直线。 注意,在使用cv2.line函数画出直线时,需要先将rho和theta转换成x1,y1,x2,y2这些坐标点,这里的1000是一个画线时的长度参数,可以根据实际需求进行调整。 希望以上答能帮到您!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值