車道線識別是自動駕駛和高級駕駛輔助系統(ADAS)中的關鍵技術之一。通過識別車道線,車輛可以保持在車道內行駛,避免偏離車道或發生碰撞。OpenCV(Open Source Computer Vision Library)是一個開源的計算機視覺庫,提供了豐富的圖像處理和計算機視覺算法,非常適合用于車道線識別。本文將詳細介紹如何使用OpenCV實現車道線識別,包括圖像預處理、邊緣檢測、霍夫變換、車道線擬合和可視化等步驟。
在開始之前,確保你已經安裝了OpenCV和Python。你可以通過以下命令安裝OpenCV:
pip install opencv-python
此外,為了進行圖像處理和可視化,你可能還需要安裝NumPy和Matplotlib:
pip install numpy matplotlib
車道線識別的第一步是對輸入圖像進行預處理,以便更好地提取車道線信息。常見的預處理步驟包括灰度化、高斯模糊和Canny邊緣檢測。
首先,我們需要讀取輸入圖像。假設我們有一張名為lane.jpg
的車道圖像:
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖像
image = cv2.imread('lane.jpg')
# 將圖像從BGR轉換為RGB格式
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 顯示圖像
plt.imshow(image)
plt.title('Original Image')
plt.show()
將彩色圖像轉換為灰度圖像可以減少計算量,同時保留車道線的邊緣信息:
# 將圖像轉換為灰度圖像
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# 顯示灰度圖像
plt.imshow(gray, cmap='gray')
plt.title('Grayscale Image')
plt.show()
高斯模糊可以平滑圖像,減少噪聲和細節,使得邊緣檢測更加準確:
# 應用高斯模糊
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# 顯示模糊后的圖像
plt.imshow(blur, cmap='gray')
plt.title('Blurred Image')
plt.show()
Canny邊緣檢測是一種常用的邊緣檢測算法,可以有效地檢測圖像中的邊緣:
# 應用Canny邊緣檢測
edges = cv2.Canny(blur, 50, 150)
# 顯示邊緣檢測結果
plt.imshow(edges, cmap='gray')
plt.title('Canny Edges')
plt.show()
在實際應用中,車道線通常位于圖像的下半部分。因此,我們可以通過定義一個感興趣區域(ROI)來減少計算量,并提高車道線檢測的準確性。
# 定義感興趣區域的頂點
height, width = edges.shape
roi_vertices = np.array([[(0, height), (width / 2, height / 2), (width, height)]], dtype=np.int32)
# 創建一個掩碼
mask = np.zeros_like(edges)
cv2.fillPoly(mask, roi_vertices, 255)
# 應用掩碼
masked_edges = cv2.bitwise_and(edges, mask)
# 顯示掩碼后的邊緣圖像
plt.imshow(masked_edges, cmap='gray')
plt.title('Masked Edges')
plt.show()
霍夫變換是一種用于檢測圖像中直線的技術。我們可以使用霍夫變換來檢測車道線。
# 應用霍夫變換檢測直線
lines = cv2.HoughLinesP(masked_edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=50, maxLineGap=100)
# 創建一個空白圖像用于繪制檢測到的直線
line_image = np.zeros_like(image)
# 繪制檢測到的直線
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 10)
# 將檢測到的直線疊加到原始圖像上
combined_image = cv2.addWeighted(image, 0.8, line_image, 1, 0)
# 顯示結果
plt.imshow(combined_image)
plt.title('Detected Lines')
plt.show()
通過霍夫變換檢測到的直線可能不是完整的車道線。為了得到更準確的車道線,我們可以對檢測到的直線進行擬合。
首先,我們需要將檢測到的直線分為左右兩組,分別對應左右車道線。
# 初始化左右車道線的點
left_lines = []
right_lines = []
# 遍歷所有檢測到的直線
for line in lines:
x1, y1, x2, y2 = line[0]
# 計算直線的斜率
slope = (y2 - y1) / (x2 - x1)
# 根據斜率將直線分為左右兩組
if slope < 0:
left_lines.append(line)
else:
right_lines.append(line)
接下來,我們可以使用最小二乘法對左右車道線的點進行擬合,得到左右車道線的方程。
# 擬合左車道線
left_points = np.array([(x1, y1) for line in left_lines for x1, y1, x2, y2 in line])
left_fit = np.polyfit(left_points[:, 0], left_points[:, 1], 1)
# 擬合右車道線
right_points = np.array([(x1, y1) for line in right_lines for x1, y1, x2, y2 in line])
right_fit = np.polyfit(right_points[:, 0], right_points[:, 1], 1)
最后,我們可以將擬合的車道線繪制到圖像上。
# 創建一個空白圖像用于繪制擬合的車道線
line_image = np.zeros_like(image)
# 計算左右車道線的起點和終點
y1 = height
y2 = int(height / 2)
left_x1 = int((y1 - left_fit[1]) / left_fit[0])
left_x2 = int((y2 - left_fit[1]) / left_fit[0])
right_x1 = int((y1 - right_fit[1]) / right_fit[0])
right_x2 = int((y2 - right_fit[1]) / right_fit[0])
# 繪制左車道線
cv2.line(line_image, (left_x1, y1), (left_x2, y2), (255, 0, 0), 10)
# 繪制右車道線
cv2.line(line_image, (right_x1, y1), (right_x2, y2), (255, 0, 0), 10)
# 將擬合的車道線疊加到原始圖像上
combined_image = cv2.addWeighted(image, 0.8, line_image, 1, 0)
# 顯示結果
plt.imshow(combined_image)
plt.title('Fitted Lane Lines')
plt.show()
為了更直觀地展示車道線識別的結果,我們可以將原始圖像、邊緣檢測結果、霍夫變換檢測到的直線以及擬合的車道線進行對比展示。
# 創建一個包含四個子圖的圖像
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 顯示原始圖像
axes[0, 0].imshow(image)
axes[0, 0].set_title('Original Image')
# 顯示邊緣檢測結果
axes[0, 1].imshow(edges, cmap='gray')
axes[0, 1].set_title('Canny Edges')
# 顯示霍夫變換檢測到的直線
axes[1, 0].imshow(combined_image)
axes[1, 0].set_title('Detected Lines')
# 顯示擬合的車道線
axes[1, 1].imshow(combined_image)
axes[1, 1].set_title('Fitted Lane Lines')
# 調整子圖之間的間距
plt.tight_layout()
# 顯示圖像
plt.show()
本文詳細介紹了如何使用OpenCV實現車道線識別。通過圖像預處理、邊緣檢測、霍夫變換、車道線擬合和可視化等步驟,我們可以有效地檢測和識別車道線。雖然本文的方法在簡單場景下表現良好,但在復雜場景(如彎道、陰影、光照變化等)下可能需要進行進一步的優化和改進。希望本文能為讀者提供車道線識別的基本思路和方法,并為后續的研究和開發提供參考。
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 讀取圖像
image = cv2.imread('lane.jpg')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# 灰度化
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
# 高斯模糊
blur = cv2.GaussianBlur(gray, (5, 5), 0)
# Canny邊緣檢測
edges = cv2.Canny(blur, 50, 150)
# 定義感興趣區域
height, width = edges.shape
roi_vertices = np.array([[(0, height), (width / 2, height / 2), (width, height)]], dtype=np.int32)
mask = np.zeros_like(edges)
cv2.fillPoly(mask, roi_vertices, 255)
masked_edges = cv2.bitwise_and(edges, mask)
# 霍夫變換檢測直線
lines = cv2.HoughLinesP(masked_edges, rho=1, theta=np.pi/180, threshold=50, minLineLength=50, maxLineGap=100)
line_image = np.zeros_like(image)
if lines is not None:
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 10)
combined_image = cv2.addWeighted(image, 0.8, line_image, 1, 0)
# 分離左右車道線
left_lines = []
right_lines = []
for line in lines:
x1, y1, x2, y2 = line[0]
slope = (y2 - y1) / (x2 - x1)
if slope < 0:
left_lines.append(line)
else:
right_lines.append(line)
# 擬合左車道線
left_points = np.array([(x1, y1) for line in left_lines for x1, y1, x2, y2 in line])
left_fit = np.polyfit(left_points[:, 0], left_points[:, 1], 1)
# 擬合右車道線
right_points = np.array([(x1, y1) for line in right_lines for x1, y1, x2, y2 in line])
right_fit = np.polyfit(right_points[:, 0], right_points[:, 1], 1)
# 繪制擬合的車道線
line_image = np.zeros_like(image)
y1 = height
y2 = int(height / 2)
left_x1 = int((y1 - left_fit[1]) / left_fit[0])
left_x2 = int((y2 - left_fit[1]) / left_fit[0])
right_x1 = int((y1 - right_fit[1]) / right_fit[0])
right_x2 = int((y2 - right_fit[1]) / right_fit[0])
cv2.line(line_image, (left_x1, y1), (left_x2, y2), (255, 0, 0), 10)
cv2.line(line_image, (right_x1, y1), (right_x2, y2), (255, 0, 0), 10)
combined_image = cv2.addWeighted(image, 0.8, line_image, 1, 0)
# 顯示結果
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
axes[0, 0].imshow(image)
axes[0, 0].set_title('Original Image')
axes[0, 1].imshow(edges, cmap='gray')
axes[0, 1].set_title('Canny Edges')
axes[1, 0].imshow(combined_image)
axes[1, 0].set_title('Detected Lines')
axes[1, 1].imshow(combined_image)
axes[1, 1].set_title('Fitted Lane Lines')
plt.tight_layout()
plt.show()
希望本文能為讀者提供車道線識別的基本思路和方法,并為后續的研究和開發提供參考。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。