iT邦幫忙

2025 iThome 鐵人賽

DAY 20
0
佛心分享-IT 人自學之術

OpwnCV影像處理新手村系列 第 20

🚀 DAY 20:霍夫轉換直線檢測(Hough Line Transform)

  • 分享至 

  • xImage
  •  

本章將介紹如何利用霍夫轉換(Hough Transform)在影像中偵測直線,並比較標準霍夫轉換與機率霍夫轉換的差異與應用。


目錄

  1. 霍夫轉換原理
  2. OpenCV 直線偵測方法
  3. 影像準備與前處理
  4. 標準霍夫轉換程式範例
  5. 機率霍夫轉換程式範例
  6. 方法比較與應用

1. 霍夫轉換原理

  • 直線在笛卡爾座標的表示: y = mx + c,當直線垂直時 m → ∞ 不易處理。
  • 霍夫轉換改用極座標: ρ = x cosθ + y sinθ
    • ρ (rho):點到原點的垂直距離
    • θ (theta):法線與 x 軸的夾角
  • 這種表示法能處理所有方向的直線,並將共線點轉換為參數空間的峰值。

2. OpenCV 直線偵測方法

OpenCV 提供兩種直線偵測方式:

  1. cv2.HoughLines():標準霍夫轉換,回傳 (ρ, θ)
  2. cv2.HoughLinesP():機率霍夫轉換,回傳線段兩端點座標,適合實務應用

3. 影像準備與前處理

請準備一張圖片 road.jpg,並放在程式同一資料夾。

import cv2
import numpy as np

# 讀取原始圖片並複製備份
img = cv2.imread("road.jpg")
img_hough = img.copy()    # 用於標準霍夫轉換繪圖
img_houghP = img.copy()   # 用於機率霍夫轉換繪圖

# 轉為灰階,便於後續邊緣偵測
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

cv2.imshow('Original', img)
cv2.waitKey()
cv2.destroyAllWindows()

https://ithelp.ithome.com.tw/upload/images/20250921/20129482YAmARrld47.png


設定 ROI(區域選取)

有時我們只關心影像的特定區域(如車道下半部),可設定 ROI 來聚焦偵測範圍。

# 設定ROI(下半部區域,根據實際需求可調整)
height, width = img.shape[:2]
roi_y1 = int(height / 1.5)
roi_y2 = height
roi_x1 = int(width / 3)
roi_x2 = width

roi = img[roi_y1:roi_y2, roi_x1:roi_x2]
img_hough_roi = img.copy()
img_houghP_roi = img.copy()
gray_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)

4. 標準霍夫轉換程式範例

# 邊緣檢測(只針對ROI)
edges_roi = cv2.Canny(gray_roi, 50, 150, apertureSize=3)

lines_roi = cv2.HoughLines(edges_roi, 1, np.pi/180, 80)
# 標準霍夫直線畫在 img_hough_roi(加回ROI偏移量)
if lines_roi is not None:
    for rho, theta in lines_roi[:,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_roi, (x1+roi_x1, y1+roi_y1), (x2+roi_x1, y2+roi_y1), (0,0,255), 2)

# 將ROI邊緣圖像放大到原圖大小顯示
edges_full = np.zeros((height, width), dtype=np.uint8)
edges_full[roi_y1:roi_y2, roi_x1:roi_x2] = edges_roi
cv2.imshow("Edges (ROI)", edges_full)
cv2.imshow("Hough Lines (ROI)", img_hough_roi)

說明:先用 Canny 邊緣偵測取得輪廓,再用 HoughLines 找出所有直線,最後將直線繪製於原圖。

https://ithelp.ithome.com.tw/upload/images/20250921/201294821BGAKYGxx9.png
https://ithelp.ithome.com.tw/upload/images/20250921/20129482qkOlPBHL5y.png


參數說明

cv2.Canny

  • image:輸入灰階影像
  • threshold1threshold2:低/高閾值,決定邊緣敏感度
  • apertureSize:Sobel 核大小,常用 3

cv2.HoughLines

  • image:二值化或邊緣影像
  • rho:距離解析度(像素),通常設為 1
  • theta:角度解析度(弧度),通常設為 np.pi/180
  • threshold:累加器門檻值,越高偵測到的線越少

cv2.HoughLinesP

  • image:二值化或邊緣影像
  • rhothetathreshold:同上
  • minLineLength:線段最短長度(像素)
  • maxLineGap:線段間最大間距(像素),允許斷線連接

5. 機率霍夫轉換程式範例

# linesP_roi = cv2.HoughLinesP(edges_roi, 1, np.pi/180, 100, minLineLength=50, maxLineGap=10)
linesP_roi = cv2.HoughLinesP(edges_roi, 1, np.pi/180, 80, minLineLength=50, maxLineGap=10)
# 機率霍夫直線畫在 img_houghP_roi(加回ROI偏移量)
if linesP_roi is not None:
    for line in linesP_roi:
        x1, y1, x2, y2 = line[0]
        cv2.line(img_houghP_roi, (x1+roi_x1, y1+roi_y1), (x2+roi_x1, y2+roi_y1), (0, 255, 0), 2)

cv2.imshow("Probabilistic Hough Lines (ROI)", img_houghP_roi)

說明:HoughLinesP 直接回傳線段端點座標,繪製更直觀,適合實務應用如車道線偵測。

https://ithelp.ithome.com.tw/upload/images/20250921/201294820XIlJR6eP0.png


6. 方法比較與應用

方法 回傳結果 適用場景
HoughLines (ρ, θ) 數學分析、特殊直線偵測
HoughLinesP (x1, y1, x2, y2) 車道線偵測、工業檢測

HoughLines 適合數學分析與特殊需求,需手動轉換座標;HoughLinesP 更直觀,直接取得線段端點,適合實務應用。

常見應用:

  • 車道線偵測 🚗
  • 文件傾斜校正 📄
  • 工業檢測(直線結構)

📖 今日結語

霍夫轉換是影像直線偵測的經典方法,標準與機率霍夫轉換各有優勢。選擇合適方法並搭配前處理,可有效提升偵測精度與效率


上一篇
🚀 DAY 19:直方圖反向投影(Histogram Backprojection)
下一篇
🎯 DAY 21:霍夫轉換圓檢測(Hough Circle Transform)
系列文
OpwnCV影像處理新手村22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言