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

相关推荐
Daydream.V3 小时前
OpenCV——人脸识别
人工智能·opencv·计算机视觉·人脸识别·人脸识别的三种算法·附代码实现
我材不敲代码3 小时前
OpenCV 实现人脸识别全流程:从人脸检测到 LBPH/Eigen/Fisher 三种算法实战
人工智能·opencv·计算机视觉
Westward-sun.17 小时前
基于 OpenCV DNN 模块实现图像风格迁移
人工智能·神经网络·opencv·计算机视觉·dnn
yongui4783421 小时前
MATLAB小波变换图像融合
opencv·计算机视觉·matlab
Fleshy数模1 天前
基于OpenCV实现人脸与微笑检测:从入门到实战
人工智能·opencv·计算机视觉
我材不敲代码1 天前
OpenCV 实战——Python 实现图片人脸检测 + 视频人脸微笑检测
人工智能·python·opencv
纤纡.1 天前
从单图风格迁移到实时视频四宫格滤镜:OpenCV DNN 实战全解析
人工智能·opencv·dnn
feasibility.1 天前
OpenCV图像滤波算法应用:常见滤波器的原理与效果对比(含c++/python代码与中文显示)
c++·opencv·算法
Daydream.V1 天前
OpenCV——DNN模块实现风格迁移
人工智能·opencv·dnn