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

相关推荐
深度研习笔记8 小时前
OpenCV工业视觉实战11|多线程解耦+视频流稳流+推理加速,彻底解决卡顿阻塞,实现毫秒级工业实时检测
人工智能·opencv·计算机视觉
深度研习笔记1 天前
OpenCV工业视觉进阶14|SQLite违规数据库存储+历史记录查询+Excel报表导出,完成项目商用数据闭环(验收必备)
数据库·opencv·sqlite
C++ 老炮儿的技术栈1 天前
OpenCV 实现社保卡透视矫正:Hough 直线提取四角并转正证件图像
c语言·c++·人工智能·opencv·算法·计算机视觉·c
深度研习笔记1 天前
OpenCV工业视觉实战09|项目EXE打包+工控机无环境部署+后台常驻运行,彻底脱离Python环境,完成项目最终交付
python·opencv·webpack
深度研习笔记2 天前
OpenCV工业视觉实战06|ROI区域截取+局部精细化检测,锁定作业区域、屏蔽无效背景,大幅提升YOLO检测准确率
人工智能·opencv·yolo
fai厅的秃头姐!2 天前
OpenCV-基础篇
人工智能·opencv·计算机视觉
丨白色风车丨2 天前
OpenCV 基于 HSV 颜色空间实时颜色分割(摄像头蓝色识别)
人工智能·opencv·计算机视觉·hsv颜色识别·python计算机视觉
深度研习笔记2 天前
OpenCV工业视觉实战10|违规语音播报+弹窗告警+重复告警过滤,打造智能声光预警系统(项目加分必备)
人工智能·opencv·计算机视觉
在世修行2 天前
高斯模糊与图像去噪
opencv·gaussianblur
xgc_java3 天前
在Java里把ONNX/OpenCV/FFmpeg跑稳:28篇bytedeco实战小册完整指南
java·opencv·ffmpeg