opencv 的霍夫变化的直线检测

以下是一个使用 OpenCV 进行霍夫线条检测的完整 Python 例程,并附带一个用于测试的合成图像生成代码。该例程同时演示了标准霍夫变换 (HoughLines)和概率霍夫变换 (HoughLinesP)两种方法,并显示检测结果。

bash 复制代码
pip install opencv-python numpy matplotlib
python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

# ------------------------------
# 1. 生成测试图像(合成直线图)
# ------------------------------
def create_test_image():
    # 创建一个黑色背景的图像 (400x400)
    img = np.zeros((400, 400, 3), dtype=np.uint8)
    # 绘制几条不同颜色、不同角度的直线
    # 直线1: 白色,斜线 (起点(50,50) -> 终点(350,350))
    cv2.line(img, (50, 50), (350, 350), (255, 255, 255), 2)
    # 直线2: 蓝色,水平线 (y=200)
    cv2.line(img, (50, 200), (350, 200), (255, 0, 0), 2)
    # 直线3: 绿色,垂直线 (x=300)
    cv2.line(img, (300, 50), (300, 350), (0, 255, 0), 2)
    # 直线4: 红色,另一条斜线 (起点(350,50) -> 终点(50,350))
    cv2.line(img, (350, 50), (50, 350), (0, 0, 255), 2)
    return img

# 生成测试图像
test_img = create_test_image()
cv2.imwrite('test_lines.png', test_img)   # 保存图像以供后续使用
print("测试图像已保存为 test_lines.png")

# ------------------------------
# 2. 读取图像并预处理
# ------------------------------
# 实际使用时,可以替换为 cv2.imread('your_image.jpg')
image = test_img.copy()  # 使用生成的图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  # 转为灰度图

# Canny 边缘检测
edges = cv2.Canny(gray, 50, 150, apertureSize=3)

# ------------------------------
# 3. 标准霍夫变换 (HoughLines)
# ------------------------------
# 参数: 边缘图, 距离分辨率(rho), 角度分辨率(theta), 阈值
lines = cv2.HoughLines(edges, rho=1, theta=np.pi/180, threshold=100)

# 复制原图用于绘制标准霍夫检测结果
img_hough = image.copy()
if lines is not None:
    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_hough, (x1, y1), (x2, y2), (0, 0, 255), 2)

# ------------------------------
# 4. 概率霍夫变换 (HoughLinesP)
# ------------------------------
# 参数: 边缘图, rho, theta, 阈值, 最小线段长度, 最大间隔
linesP = cv2.HoughLinesP(edges, rho=1, theta=np.pi/180, threshold=50,
                         minLineLength=100, maxLineGap=10)

# 复制原图用于绘制概率霍夫检测结果
img_houghP = image.copy()
if linesP is not None:
    for line in linesP:
        x1, y1, x2, y2 = line[0]
        cv2.line(img_houghP, (x1, y1), (x2, y2), (0, 0, 255), 2)

# ------------------------------
# 5. 显示结果
# ------------------------------
plt.figure(figsize=(12, 8))

plt.subplot(2, 2, 1)
plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')

plt.subplot(2, 2, 2)
plt.imshow(edges, cmap='gray')
plt.title('Canny Edges')
plt.axis('off')

plt.subplot(2, 2, 3)
plt.imshow(cv2.cvtColor(img_hough, cv2.COLOR_BGR2RGB))
plt.title('Standard Hough Lines')
plt.axis('off')

plt.subplot(2, 2, 4)
plt.imshow(cv2.cvtColor(img_houghP, cv2.COLOR_BGR2RGB))
plt.title('Probabilistic Hough Lines')
plt.axis('off')

plt.tight_layout()
plt.show()

代码说明

  1. 生成测试图像
    create_test_image() 函数创建了一张 400×400 的黑色图像,并在上面绘制了四条不同颜色、不同方向的直线(白色斜线、蓝色水平线、绿色垂直线、红色斜线)。该图像被保存为 test_lines.png,方便后续使用。你也可以用 cv2.imread() 替换为自己的图片。

  2. 预处理

    • 将彩色图像转为灰度图(cv2.cvtColor)。

    • 使用 Canny 边缘检测提取边缘(参数可调)。

  3. 标准霍夫变换 (cv2.HoughLines)

    • 输入:边缘图像,距离分辨率 rho=1(像素),角度分辨率 theta=π/180(弧度),阈值 threshold=100(至少需要多少条曲线交于一点才视为一条直线)。

    • 输出:每条直线由 (ρ, θ) 表示,然后通过极坐标公式转换为两点坐标,并在原图上绘制红色直线。

  4. 概率霍夫变换 (cv2.HoughLinesP)

    • 输入:边缘图像,rho=1, theta=π/180,阈值 threshold=50,最小线段长度 minLineLength=100,最大间隔 maxLineGap=10。

    • 输出:线段端点坐标,直接绘制红色线段。

  5. 结果显示

    使用 Matplotlib 并排显示原图、Canny 边缘图、标准霍夫结果和概率霍夫结果。

常见参数调整建议

  • Canny 阈值 :较低的值会检测到更多边缘(可能包含噪声),较高的值会忽略弱边缘。建议使用 cv2.Canny(gray, 50, 150) 作为起点,然后根据结果调整。

  • 霍夫阈值:值越大,检测到的直线越少但越准确;值越小,检测到的直线越多但可能包含虚假直线。

  • 概率霍夫的 minLineLength 和 maxLineGap:控制检测线段的最小长度和断裂线段的连接间隔。

标准霍夫变换 函数 cv2.HoughLines 中,参数 rho 和 theta 分别对应 距离分辨率 和 角度分辨率,它们是霍夫参数空间(霍夫空间)中两个坐标轴的离散化步长。

距离分辨率 (rho) 的含义

直线在极坐标下的表示为:

ρ=xcos⁡θ+ysin⁡θρ=xcosθ+ysinθ

其中:

  • ρρ 是原点到直线的垂直距离(有正负,通常取绝对值时代表距离);

  • θθ 是法线与 x 轴正方向的夹角(弧度)。

在霍夫变换中,我们将所有可能直线映射到 (ρ,θ)(ρ,θ) 参数空间。这个空间是连续的,但算法必须将其离散化成一个二维累加器(网格),以便对每个边缘点进行投票。

距离分辨率 rho 就是这个网格中 ρρ 轴的步长(间隔) 。例如,如果 rho = 1,那么参数空间中的 ρρ 值取为 0,1,2,...0,1,2,...(或负值),单位是像素。这意味着:

  • 算法只考虑距离原点距离为整数像素的直线;

  • 两个非常接近的直线(距离相差小于 1 像素)会被视为同一条直线而合并投票。

代码示例回顾

在之前的例程中:

复制代码
lines = cv2.HoughLines(edges, rho=1, theta=np.pi/180, threshold=100)

这里 rho=1 表示距离分辨率为 1 像素,theta=np.pi/180 表示角度分辨率为 1 度(π/180 弧度)。这样参数空间共有 ρmax⁡−ρmin⁡ρmax​−ρmin​(约等于图像对角线长度)个格子,θθ 轴有 180 个格子(因为只考虑 0~π)。计算量适中,检测效果良好。

相关推荐
TTTrees3 小时前
(11)最重要的结构体Mat
opencv
可爱系程序猿5 小时前
OpenCV 项目启动时报 opencv_world480.dll:先核对构建与架构
人工智能·opencv·程序人生·架构·电脑
FOAF-lambda6 小时前
Python实战:基于OpenCV与单调栈,精准定位PDF中最大的空白区域
python·opencv·pdf
小豆庄1 天前
处理含车牌/人脸的隐私视频,如何做到数据不离机?
opencv·ai·云计算·视频
小徐不徐说1 天前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
晨间晓4 天前
图片里的高频和低频是什么?用华为云码道开发 OpenCV 傅里叶频谱分析工具
opencv·计算机视觉·华为云
晨间晓4 天前
图片里的阴影能不能减弱?用华为云码道开发 OpenCV 光照校正工具
人工智能·opencv·华为云
晨间晓5 天前
图片里的细小噪点怎么平滑?用华为云码道开发 OpenCV 图像滤波对比工具
人工智能·opencv·华为云
偷吃米饭5 天前
图片特征怎么描述?用华为云码道开发 OpenCV ORB 特征提取工具
人工智能·opencv·华为云
晨间晓5 天前
图片里的关键点怎么找?用华为云码道开发 OpenCV FAST 特征点检测工具
人工智能·opencv·华为云