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) 作为起点,然后根据结果调整。

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

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

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

距离分辨率 (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~π)。计算量适中,检测效果良好。

相关推荐
qq_5260991321 小时前
图像采集卡:藏在机器“眼睛”背后的枢纽,撑起视觉智能化半边天
数码相机·opencv·计算机视觉
我是无敌小恐龙1 天前
Java SE 零基础入门Day01 超详细笔记(开发前言+环境搭建+基础语法)
java·开发语言·人工智能·opencv·spring·机器学习
是梦终空2 天前
计算机毕业设计271—基于python+深度学习+YOLOV7的车牌识别系统(源代码+数据库+3万字论文)
python·深度学习·opencv·yolo·毕业设计·pyqt5·车牌识别系统
爱凤的小光2 天前
OpenCV4机器学习算法原理与代码---个人学习篇
opencv·机器学习
JMchen1232 天前
集成第三方 C/C++ 库到 Android NDK 项目:OpenCV 与 FFmpeg 实战指南
opencv·ffmpeg·音视频开发·cmake·jni·ndk·abi 兼容性
明月醉窗台3 天前
Python-opencv批量处理文件夹中图像操作
开发语言·python·opencv
纤纡.3 天前
轻松实现多语言文字识别与实时检测:PaddleOCR 实战指南
人工智能·深度学习·opencv·paddlepaddle
格林威3 天前
工业相机“心跳”监测脚本(C# 版) 支持海康 / Basler / 堡盟工业相机
开发语言·人工智能·数码相机·opencv·计算机视觉·c#·视觉检测
编码小哥3 天前
OpenCV图像增强实战:对比度调整与Gamma校正
人工智能·opencv·计算机视觉
ComputerInBook5 天前
OpenCV图像处理——图像缩放函数 resize
图像处理·opencv·计算机视觉