OpenCV计算机视觉实战(15)——霍夫变换详解

OpenCV计算机视觉实战(15)------霍夫变换详解

    • [0. 前言](#0. 前言)
    • [1. 直线检测](#1. 直线检测)
      • [1.1 应用场景](#1.1 应用场景)
      • [1.2 实现过程](#1.2 实现过程)
    • [2. 圆形检测](#2. 圆形检测)
      • [2.1 应用场景](#2.1 应用场景)
      • [2.2 实现过程](#2.2 实现过程)
    • [3. 车道线检测](#3. 车道线检测)
    • 小结
    • 系列链接

0. 前言

在图像处理与计算机视觉领域,霍夫变换以其对抗噪声、鲁棒性强的特点,广泛应用于直线、圆形等几何模型的检测。从建筑立面分析到工业零件检测,再到自动驾驶中的车道线识别,掌握霍夫变换的各种变体与优化思路至关重要。本文将围绕三大核心任务------直线检测、圆形检测、以及车道线检测实现进行介绍。

1. 直线检测

使用标准霍夫变换和概率霍夫变换 (HoughLinesP) 检测图像中的直线,并根据长度、角度等条件过滤出我们关心的线段(例如水平方向或近垂直方向的长线段)。

1.1 应用场景

  • 建筑立面分析:提取窗框、梁柱等垂直与水平结构
  • 文本行分割:在扫描文档中检测基线,辅助 OCR 排版校正
  • 创意艺术:用直线检测结果生成抽象画,或做形状映射

1.2 实现过程

  • 读取图像与预处理
    • 转灰度,使用高斯模糊去噪
    • 利用 Canny 边缘检测获得边缘图
  • 直线检测
    • cv2.HoughLinesP:检测所有可能的线段
  • 线段过滤
    • 根据线段长度阈值剔除过短的伪线
    • 根据线段角度(例如与水平或垂直的夹角)只保留感兴趣方向的线段。
  • 可视化
    • 在彩色图上绘制保留的线段
python 复制代码
import cv2
import numpy as np
import math

# 1. 读取与预处理
img = cv2.imread('2.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 1.5)
edges = cv2.Canny(blur, 50, 150)

# 2. 概率霍夫线段检测
lines = cv2.HoughLinesP(
    edges, 
    rho=1, 
    theta=np.pi/180, 
    threshold=80, 
    minLineLength=50, 
    maxLineGap=10
)

# 3. 线段过滤:只保留与水平夹角 < 10° 或 > 30°
filtered = []
for x1,y1,x2,y2 in lines[:,0]:
    dx, dy = x2-x1, y2-y1
    angle = abs(math.degrees(math.atan2(dy, dx)))
    length = math.hypot(dx, dy)
    if length > 60 and (angle < 10 or angle > 30):
        filtered.append((x1,y1,x2,y2))

# 4. 绘制结果
output = img.copy()
for x1,y1,x2,y2 in filtered:
    cv2.line(output, (x1,y1), (x2,y2), (0,0,255), 2)

cv2.imshow('Filtered Lines', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键函数解析:

  • cv2.Canny(src, lowThresh, highThresh):提取图像边缘,为霍夫变换提供二值输入
  • cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap):概率霍夫直线检测,返回线段端点坐标
    • minLineLength:线段最小长度,小于该值将被忽略
    • maxLineGap:同一条直线的两段最大间隔,小于该值可被连接
  • 使用 atan2(dy,dx)hypot(dx,dy) 分别计算线段的角度和长度,用以过滤不符合需求的线段

2. 圆形检测

利用霍夫圆变换 (HoughCircles) 在图像中检测不同半径范围的圆形,并通过调节参数 (dpminDistparam1param2minRadiusmaxRadius) 来优化检测效果,尽量减少误检与漏检。

2.1 应用场景

  • 工业检测:识别轴承滚珠、齿轮孔位置
  • 医学影像:定位细胞、胶状囊泡等圆形结构
  • 天文图像:在星空照片中检测月亮、行星轮廓

2.2 实现过程

  • 读取图像与预处理
    • 转灰度,做高斯模糊减少噪声
  • 霍夫圆检测
    • cv2.HoughCircles:在灰度图中检测圆心和半径
  • 参数调优策略
    • dp:累加器分辨率与图像分辨率比例
    • minDist:检测到的圆心之间最小距离,防止多次检测同一圆
    • param1/param2Canny 边缘高阈值与累加阈值,影响边缘强度和圆心确认
    • minRadius/maxRadius:限制检测半径范围
  • 可视化
    • 在原图上绘制检测到的圆心和圆环
python 复制代码
import cv2
import numpy as np

# 1. 读取与预处理
img = cv2.imread('9.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.medianBlur(gray, 5)

# 2. 霍夫圆变换
circles = cv2.HoughCircles(
    blur, 
    method=cv2.HOUGH_GRADIENT, 
    dp=1.5, 
    minDist=50,
    param1=100, 
    param2=30, 
    minRadius=10, 
    maxRadius=50
)

# 3. 绘制结果
output = img.copy()
if circles is not None:
    circles = np.uint16(np.around(circles[0]))
    for x,y,r in circles:
        cv2.circle(output, (x,y), r, (0,255,0), 2)
        cv2.circle(output, (x,y), 2, (0,0,255), 3)

cv2.imshow('Detected Circles', output)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键函数解析:

  • cv2.medianBlur(src, ksize):中值滤波对脉冲噪声效果好,常用于圆检测前的预处理
  • cv2.HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)
    • dp:累加器分辨率与图像分辨率的反比,dp>1 可减少误检
    • minDist:同心圆心之间的最小距离,防止多次检测
    • param1Canny 边缘检测的高阈值
    • param2:累加器阈值,越大圆检测越严格
    • minRadius/maxRadius:限制半径搜索范围,加快速度并减少误检

3. 车道线检测

结合透视变换、感兴趣区域 (Region of Interest, ROI) 与概率霍夫线段检测,实现简单的车道线检测。

python 复制代码
import cv2, numpy as np

def region_of_interest(img):
    mask = np.zeros_like(img)
    h, w = img.shape[:2]
    pts = np.array([[(w*0.1,h), (w*0.4,h*0.6), (w*0.6,h*0.6), (w*0.9,h)]], dtype=np.int32)
    cv2.fillPoly(mask, pts, 255)
    return cv2.bitwise_and(img, mask)

# 1. 读取与颜色过滤
img = cv2.imread('11.jpeg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 白色掩码
white = cv2.inRange(hsv, (0,0,200), (180,30,255))
# 黄色掩码
yellow = cv2.inRange(hsv, (15,100,100), (35,255,255))
color_mask = cv2.bitwise_or(white, yellow)
filtered = cv2.bitwise_and(img, img, mask=color_mask)

# 2. ROI + 灰度+Canny
roi = region_of_interest(filtered)
gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150)

# 3. 透视变换
h, w = img.shape[:2]
src = np.float32([[w*0.45, h*0.6], [w*0.55, h*0.6], [w*0.1, h], [w*0.9, h]])
dst = np.float32([[w*0.2, 0], [w*0.8, 0], [w*0.2, h], [w*0.8, h]])
M = cv2.getPerspectiveTransform(src, dst)
warped = cv2.warpPerspective(edges, M, (w,h))

# 4. 滑动窗口+二次拟合
hist = np.sum(warped[h//2:,:], axis=0)
mid = w//2
left_base = np.argmax(hist[:mid])
right_base = np.argmax(hist[mid:]) + mid

nwindows = 9; margin=100; minpix=50
window_height = h // nwindows
nonzero = warped.nonzero()
nonx, nony = nonzero[1], nonzero[0]
left_current, right_current = left_base, right_base
left_inds, right_inds = [], []

for i in range(nwindows):
    win_y_low = h - (i+1)*window_height
    win_y_high = h - i*window_height
    win_xl_low = left_current - margin; win_xl_high = left_current + margin
    win_xr_low = right_current - margin; win_xr_high = right_current + margin
    good_left = ((nony>=win_y_low)&(nony<win_y_high)&
                 (nonx>=win_xl_low)&(nonx<win_xl_high)).nonzero()[0]
    good_right = ((nony>=win_y_low)&(nony<win_y_high)&
                  (nonx>=win_xr_low)&(nonx<win_xr_high)).nonzero()[0]
    left_inds.append(good_left); right_inds.append(good_right)
    if len(good_left)>minpix: left_current = int(np.mean(nonx[good_left]))
    if len(good_right)>minpix: right_current = int(np.mean(nonx[good_right]))

left_inds = np.concatenate(left_inds); right_inds = np.concatenate(right_inds)
leftx, lefty = nonx[left_inds], nony[left_inds]
rightx, righty = nonx[right_inds], nony[right_inds]
# 二次多项式拟合
left_fit = np.polyfit(lefty, leftx, 2)
right_fit = np.polyfit(righty, rightx, 2)

# 5. 绘制车道区域
ploty = np.linspace(0, h-1, h)
left_fitx = left_fit[0]*ploty**2 + left_fit[1]*ploty + left_fit[2]
right_fitx = right_fit[0]*ploty**2 + right_fit[1]*ploty + right_fit[2]
pts_left = np.array([np.transpose(np.vstack([left_fitx, ploty]))])
pts_right = np.array([np.flipud(np.transpose(np.vstack([right_fitx, ploty])))])
pts = np.hstack((pts_left, pts_right))

warped_color = cv2.cvtColor(warped, cv2.COLOR_GRAY2BGR)
cv2.fillPoly(warped_color, np.int32([pts]), (0,255, 0))
invM = np.linalg.inv(M)
lane = cv2.warpPerspective(warped_color, invM, (w,h))
result = cv2.addWeighted(img, 0.8, lane, 0.2, 0)

cv2.imshow('Advanced Lane Detection', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

关键函数解析:

  • cv2.cvtColor(img, cv2.COLOR_BGR2HSV):将 BGR 图像转换为 HSV 色彩空间,更适合分离颜色信息
  • cv2.inRange():用于颜色阈值分割,提取特定颜色
  • cv2.bitwise_or():将两种颜色掩码合并
  • cv2.bitwise_and():保留感兴趣颜色区域,背景设为黑色
  • cv2.getPerspectiveTransform(src, dst):计算透视变换矩阵
  • cv2.warpPerspective(img, M, size):执行图像透视变换
  • cv2.fillPoly():将拟合的车道区域填充为绿色
  • cv2.warpPerspective(..., invM):将鸟瞰图逆变换回原图视角
  • cv2.addWeighted():将车道绘制结果与原图进行加权叠加

小结

本文系统介绍了霍夫变换在三大经典任务中的应用与实践要点:

  • 直线检测:结合 Canny 边缘、概率霍夫变换与线段长度/角度过滤,快速提取图像中水平与垂直的主干直线,适用于建筑立面、文档基线或艺术化分割
  • 圆形检测:通过中值滤波降噪后使用 HoughCircles,并调节累加器分辨率、最小圆心距离与阈值参数,能精准定位多种尺寸的圆形目标,如工业零件、细胞结构或天文图像中的天体
  • 车道线检测:依次进行颜色空间筛选、ROI 裁剪、Canny 边缘检测、鸟瞰透视变换,再利用滑动窗口搜索与二次多项式拟合,最终将检测到的车道区域逆变换叠加回原图

系列链接

OpenCV计算机视觉实战(1)------计算机视觉简介
OpenCV计算机视觉实战(2)------环境搭建与OpenCV简介
OpenCV计算机视觉实战(3)------计算机图像处理基础
OpenCV计算机视觉实战(4)------计算机视觉核心技术全解析
OpenCV计算机视觉实战(5)------图像基础操作全解析
OpenCV计算机视觉实战(6)------经典计算机视觉算法
OpenCV计算机视觉实战(7)------色彩空间详解
OpenCV计算机视觉实战(8)------图像滤波详解
OpenCV计算机视觉实战(9)------阈值化技术详解
OpenCV计算机视觉实战(10)------形态学操作详解
OpenCV计算机视觉实战(11)------边缘检测详解
OpenCV计算机视觉实战(12)------图像金字塔与特征缩放
OpenCV计算机视觉实战(13)------轮廓检测详解
OpenCV计算机视觉实战(14)------直方图均衡化

相关推荐
千宇宙航4 小时前
闲庭信步使用图像验证平台加速FPGA的开发:第十四课——图像二值化的FPGA实现
图像处理·计算机视觉·fpga开发
橡晟4 小时前
深度学习入门:让神经网络变得“深不可测“⚡(二)
人工智能·python·深度学习·机器学习·计算机视觉
墨尘游子4 小时前
神经网络的层与块
人工智能·python·深度学习·机器学习
Leah01054 小时前
什么是神经网络,常用的神经网络,如何训练一个神经网络
人工智能·深度学习·神经网络·ai
PyAIExplorer5 小时前
图像亮度调整的简单实现
人工智能·计算机视觉
Striker_Eureka6 小时前
DiffDet4SAR——首次将扩散模型用于SAR图像目标检测,来自2024 GRSL(ESI高被引1%论文)
人工智能·目标检测
Rvelamen6 小时前
LLM-SECURITY-PROMPTS大模型提示词攻击测评基准
人工智能·python·安全
JNU freshman8 小时前
计算机视觉 之 数字图像处理基础(一)
人工智能·计算机视觉
千宇宙航8 小时前
闲庭信步使用图像验证平台加速FPGA的开发:第十五课——基于sobel算子边缘检测的FPGA实现
图像处理·计算机视觉·fpga开发