Python----計算機視覺處理(Opencv:道路檢測之車道線擬合)

完整版:?Python----計算機視覺處理(Opencv:道路檢測完整版:透視變換,提取車道線,車道線擬合,車道線顯示)

一、獲取左右車道線的原始位置?

導入模塊

import cv2
import numpy as np
from matplotlib import pyplot as plt

輸入圖像?

img = cv2.imread('img_road.png')

獲取圖像的高和寬?

height, width, _ = img.shape

對圖像的高進行求和?

num_ax0 = np.sum(img, axis=0)

顯示圖像求和圖?

plt.plot(num_ax0)
plt.show()

得到直方圖左右兩側最高點的位置?

    img_left_argmax=np.argmax(num_ax0[:width//2])img_right_argmax=np.argmax(num_ax0[width//2:])+width//2

二、繪制小窗口

獲取圖像中所有非零像素的x和y的位置

nonzeroy,nonzerox=np.array(img.nonzero())

定義一些小窗口的概念參數

# 定義小窗口的個數
windows_num=10#小窗口的寬度和高度
windows_height=height//windows_num
windows_width=30#小窗口白色個數閾值
min_pix=40#初始化當前窗口的位置
left_current=img_left_argmax
right_current=img_right_argmax

創建空列表接收左側和右側車道線像素的索引

left_lane_inds=[]
right_lane_inds=[]

繪制小窗口一

for window in range(windows_num):# 計算當前窗口的上邊界的y坐標win_y_high=height-windows_height*(window+1)# 計算當前窗口的下邊界的y坐標win_y_low = height - windows_height * window# 計算左邊窗口左右邊界的x坐標win_x_left_left=left_current - windows_widthwin_x_left_right=left_current + windows_width# 計算右邊窗口左右邊界的x坐標win_x_right_left=right_current - windows_widthwin_x_right_right=right_current + windows_widthcv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)

?

? ? ? ? 通過上述代碼繪畫出的小窗口沒有隨路線的彎曲程度而彎曲,需要該進?

改進小窗口,讓窗口隨路線的走勢而走勢

    for window in range(windows_num):# 計算當前窗口的上邊界的y坐標win_y_high=height-windows_height*(window+1)# 計算當前窗口的下邊界的y坐標win_y_low = height - windows_height * window# 計算左邊窗口左右邊界的x坐標win_x_left_left=left_current - windows_widthwin_x_left_right=left_current + windows_width# 計算右邊窗口左右邊界的x坐標win_x_right_left=right_current - windows_widthwin_x_right_right=right_current + windows_widthcv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)good_left_index=((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)& (nonzerox >= win_x_left_left) & (nonzerox < win_x_left_right)).nonzero()[0]good_right_index=((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)& (nonzerox >= win_x_right_left) & (nonzerox < win_x_right_right)).nonzero()[0]left_lane_inds.append(good_left_index)right_lane_inds.append(good_right_index)if len(good_left_index)>min_pix:left_current = int(np.mean(nonzerox[good_left_index]))else:if len(good_right_index)>min_pix:offset=int(np.mean(nonzerox[good_right_index]))-right_preleft_current=left_current+offsetif len(good_right_index)>min_pix:right_current = int(np.mean(nonzerox[good_right_index]))else:if len(good_left_index)>min_pix:offset=int(np.mean(nonzerox[good_left_index]))-left_preright_current=right_current+offsetleft_pre=left_currentright_pre=right_current

三、擬合車道線

#連接索引的列表,為了后續更方便的提取出這些像素點的和y的坐標,以便進行車道線的擬合left_lane_inds=np.concatenate(left_lane_inds)right_lane_inds=np.concatenate(right_lane_inds)# 提取左側和右側車道線像素的位置# left_lane_inds 是一個一維數組,它包含了左側車道線在滑動窗口中找到的白色像素點的x坐標的索引# 通過將這些索引作為索引器應用到 nonzerox數組上,就可以得到相應的左側車道線的x坐標# leftx 包含了左側車道線自色像素點的華標leftx=nonzerox[left_lane_inds]lefty=nonzeroy[left_lane_inds]rightx=nonzerox[right_lane_inds]righty=nonzeroy[right_lane_inds]# 有了坐標之后,就要去對左側和右側車道線進行多項式擬合,從而得到擬合的車道線# np.polyfit()是numpy中用于進行多項式擬合的函數# 他接受三個參數:xy 和deg# x:自變量數組,y:因變量數組# deg:多項式的次數,如果是y=ax^2+b^x+C# left_fit里存放的就是 a、b、c的參數,left_fit=np.polyfit(lefty,leftx,2)right_fit=np.polyfit(righty, rightx, 2)# 使用np.linspace 生成一組均勻分布的數值,用于表示豎直方向上的像素坐標,方便后續的車道線的繪制# 使用多項式擬合來估計左側和右側車道線的x坐標# left_fitx 就是左側擬合出來的車道線ploty=np.linspace(0,height-1,height)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]# 計算中間車道線的位置middle_fitx=(left_fitx+right_fitx)//2# 使用不同顏色將車道線標出來out_img[lefty,leftx]=[255,0,0]out_img[righty,rightx]=[0,0,255]

四、完整代碼

?

import cv2  
import numpy as np  
import matplotlib.pyplot as plt  # 讀取圖像  
img = cv2.imread('img_road.png')  # 將圖像復制到三個通道,以便于處理  
out_img = np.dstack((img, img, img))  # 計算每列像素的總和,以便找到車道線的最高點  
num_ax0 = np.sum(img, axis=0)  # 獲取左右兩側最高點的位置  
img_left_argmax = np.argmax(num_ax0[:width // 2])  # 左側最高點  
img_right_argmax = np.argmax(num_ax0[width // 2:]) + width // 2  # 右側最高點  # 獲取圖像中所有非零像素的x和y的位置  
nonzeroy, nonzerox = np.array(img.nonzero())  # 定義小窗口的個數  
windows_num = 10  # 小窗口的高度和寬度  
windows_height = height // windows_num  
windows_width = 30  # 小窗口白色像素的個數閾值  
min_pix = 400  # 初始化當前窗口的位置  
left_current = img_left_argmax  
right_current = img_right_argmax  # 記錄上一個窗口的位置  
left_pre = left_current  
right_pre = right_current  # 創建空列表以接收左側和右側車道線像素的索引  
left_lane_inds = []  
right_lane_inds = []  # 遍歷每個窗口  
for window in range(windows_num):  # 計算當前窗口的上邊界y坐標  win_y_high = height - windows_height * (window + 1)  # 計算當前窗口的下邊界y坐標  win_y_low = height - windows_height * window  # 計算左側窗口的左右邊界x坐標  win_x_left_left = left_current - windows_width  win_x_left_right = left_current + windows_width  # 計算右側窗口的左右邊界x坐標  win_x_right_left = right_current - windows_width  win_x_right_right = right_current + windows_width  # 在圖像上繪制窗口  cv2.rectangle(out_img, (win_x_left_left, win_y_high), (win_x_left_right, win_y_low), (0, 255, 0), 2)  cv2.rectangle(out_img, (win_x_right_left, win_y_high), (win_x_right_right, win_y_low), (0, 255, 0), 2)  # 找到在當前窗口內的好像素索引  good_left_index = ((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)  & (nonzerox >= win_x_left_left) & (nonzerox < win_x_left_right)).nonzero()[0]  good_right_index = ((nonzeroy >= win_y_high) & (nonzeroy < win_y_low)  & (nonzerox >= win_x_right_left) & (nonzerox < win_x_right_right)).nonzero()[0]  # 將找到的索引添加到列表中  left_lane_inds.append(good_left_index)  right_lane_inds.append(good_right_index)  # 更新當前窗口位置  if len(good_left_index) > min_pix:  left_current = int(np.mean(nonzerox[good_left_index]))  # 更新左側窗口位置  else:  if len(good_right_index) > min_pix:  offset = int(np.mean(nonzerox[good_right_index])) - right_pre  # 計算偏移量  left_current = left_current + offset  # 更新左側窗口位置  if len(good_right_index) > min_pix:  right_current = int(np.mean(nonzerox[good_right_index]))  # 更新右側窗口位置  else:  if len(good_left_index) > min_pix:  offset = int(np.mean(nonzerox[good_left_index])) - left_pre  # 計算偏移量  right_current = right_current + offset  # 更新右側窗口位置  # 更新上一個窗口位置  left_pre = left_current  right_pre = right_current  # 將找到的索引合并為一個數組  
left_lane_inds = np.concatenate(left_lane_inds)  
right_lane_inds = np.concatenate(right_lane_inds)  # 獲取左右車道線的x和y坐標  
leftx = nonzerox[left_lane_inds]  
lefty = nonzeroy[left_lane_inds]  rightx = nonzerox[right_lane_inds]  
righty = nonzeroy[right_lane_inds]  # 使用多項式擬合左側和右側車道線  
# 有了坐標之后,就要去對左側和右側車道線進行多項式擬合,從而得到擬合的車道線# np.polyfit()是numpy中用于進行多項式擬合的函數
# 他接受三個參數:xy 和deg
# x:自變量數組,y:因變量數組
# deg:多項式的次數,如果是2y=ax^2+b^x+C
# left_fit里存放的就是 a、b、c的參數,
left_fit = np.polyfit(lefty, leftx, 2)  # 左側擬合  
right_fit = np.polyfit(righty, rightx, 2)  # 右側擬合  # 創建y坐標的線性空間  
ploty = np.linspace(0, height - 1, height)  # 根據擬合的多項式計算x坐標  
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]  # 計算中間車道線的x坐標  
middle_fitx = (left_fitx + right_fitx) // 2  # 在輸出圖像上標記左側和右側車道線像素  
out_img[lefty, leftx] = [255, 0, 0]  # 左側車道線為紅色  
out_img[righty, rightx] = [0, 0, 255]  # 右側車道線為藍色  # 顯示結果圖像  
cv2.imshow('out_img', out_img)  
cv2.waitKey(0)  
  1. 圖像讀取和準備:讀取圖像并為處理做好準備。
  2. 直方圖計算:計算像素值的總和,以找到車道的位置。
  3. 滑動窗口:使用滑動窗口技術識別車道像素。
  4. 車道像素索引:收集左側和右側車道的好像素索引。
  5. 多項式擬合:對識別出的車道點進行多項式擬合,以生成平滑的車道線。
  6. 可視化:在輸出圖像上繪制檢測到的車道線并展示。

五、庫函數

5.1、nonzero()

????????返回數組中非零元素的索引

numpy.nonzero(a)

用途:它通常用來查找非零元素的位置,常用于圖像處理中篩選出特定的像素。

返回值:函數返回一個元組,每個元素是一個數組,表示非零元素在每個維度上的索引。例如,對于二維數組?AA.nonzero()?返回兩個數組,第一個數組表示行索引,第二個數組表示列索引。

import numpy as nparr=np.array([[0,1,2,3,4,5,6],[1,2,3,4,5,6,7],[0,0,0,0,0,0,0]]
)
print(arr.nonzero())
#(array([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1]), array([1, 2, 3, 4, 5, 6, 0, 1, 2, 3, 4, 5, 6]))

5.2、polyfit()

????????用于計算數據點的多項式擬合

numpy.polyfit(x, y, deg, rcond=None, full=False, w=None, cov=False)
方法描述
xM 個采樣點的 x 坐標。(x[i],?y[i])
y采樣點的 y 坐標。樣本的多個數據集 共享相同 x 坐標的點可以通過以下方式一次擬合 傳入一個 2D 數組,該數組每列包含一個數據集。
deg擬合多項式的次數
rcond擬合的相對條件編號。小于 this 相對于最大奇異值將被忽略。這 默認值為 len(x)*eps,其中 eps 是 float 類型,大多數情況下約為 2E-16。
fullSwitch 確定返回值的性質。當為 False 時( default) 僅返回系數,當 True diagnostic 還會返回來自奇異值分解的信息。
w權重。如果不是 None,則權重適用于未平方的 殘差 。理想情況下,權重為 選中,這樣產品的誤差都具有 相同的方差。使用逆方差加權時,請使用 。默認值為 None。w[i]y[i]?-?y_hat[i]x[i]w[i]*y[i]w[i]?=?1/sigma(y[i])
cov如果給定且非?False,則不僅返回估計值,還返回其 協方差矩陣。默認情況下,協方差的縮放比例為 chi2/dof,其中 dof = M - (度 + 1),即假定權重 不可靠,除非在相對意義上,并且一切都是縮放的 使得還原的 Chi2 是 Unity。如果 ,則省略此縮放,因為與權重 w = 1/sigma,其中已知 sigma 是 不確定性。cov='unscaled'
import numpy as np
x = np.array([1, 2, 3, 4])
y = np.array([2, 3, 5, 7])
# ax**2+bx+c
a,b,c = np.polyfit(x, y, 2)  # 進行二次多項式擬合
print(a,b,c)
#[0.25 0.45 1.25]

5.3、linspace()

????????用于生成指定范圍內的等間距數字

numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None, axis=0, *, device=None)
方法描述
start序列的起始值。
stop序列的結束值,除非?endpoint?設置為 False。 在這種情況下,序列由除最后一個均勻分布的樣本之外的所有樣本組成,因此不包括?stop。請注意,步驟 當?endpoint?為 False 時,size 會發生變化。num?+?1
num要生成的樣本數。默認值為 50。必須為非負數。
endpoint如果為 True,則 stop?是最后一個樣本。否則,不包括在內。 默認值為 True。
retstep如果為 True,則返回 (samples,?step),其中?step?是間距 樣本之間。
dtype輸出數組的類型。如果未給出,則數據類型 是從?start?和?stop?推斷出來的。推斷的 dtype 永遠不會是 整數;float?的 整數數組。
axis結果中用于存儲樣本的軸。僅在啟動時相關 或 stop 是類似數組的。默認情況下 (0),樣本將沿著 在開頭插入新軸。使用 -1 在末尾獲取一個軸。
device要放置創建的陣列的設備。默認值:None。 僅對于 Array-API 互作性,如果通過,則必須這樣做。
import numpy as np
samples = np.linspace(0, 1, 5)  # 生成 0 到 1 之間的 5 個等間距點
print(samples)
# [0.   0.25 0.5  0.75 1.  ]

5.4、dstack()

????????用于沿著深度(第三個軸)拼接數組。

numpy.dstack(tup)
方法描述
tup數組沿除第三個軸之外的所有軸必須具有相同的形狀。 一維或二維數組必須具有相同的形狀。
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
c = np.dstack((a, b))  # 沿著深度軸拼接,結果形狀為 (2, 2, 2)
print(c)
'''
[[[1 5][2 6]][[3 7][4 8]]]
'''

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/75757.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/75757.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/75757.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

優選算法的妙思之流:分治——歸并專題

專欄&#xff1a;算法的魔法世界 個人主頁&#xff1a;手握風云 目錄 一、歸并排序 二、例題講解 2.1. 排序數組 2.2. 交易逆序對的總數 2.3. 計算右側小于當前元素的個數 2.4. 翻轉對 一、歸并排序 歸并排序也是采用了分治的思想&#xff0c;將數組劃分為多個長度為1的子…

C語言查漏補缺:基礎篇

1.原理 C語言是一門編譯型計算機語言&#xff0c;要編寫C代碼&#xff0c;C源代碼文本文件本身無法直接執行&#xff0c;必須通過編譯器翻譯和鏈接器的鏈接&#xff0c;生成二進制的可執行文件&#xff0c;然后才能執行。這里的二進制的可執行文件就是我們最終要形成的可執行程…

TPS入門DAY02 服務器篇

1.創建空白插件 2.導入在線子系統以及在線steam子系統庫 MultiplayerSessions.uplugin MultiplayerSessions.Build.cs 3.創建游戲實例以及初始化會話創建流程 創建會話需要的函數&#xff0c;委托&#xff0c;委托綁定的回調&#xff0c;在線子系統接口綁定某一個委托的控制其…

產品經理課程

原型工具 一、土耳其機器人 這個說法來源于 1770 年出現的一個騙局&#xff0c;一個叫沃爾夫岡馮肯佩倫&#xff08;Wolfgang von Kempelen&#xff09;的人為了取悅奧地利女皇瑪麗婭特蕾莎&#xff08;Maria Theresia&#xff09;&#xff0c;“制造”了一個會下國際象棋的機…

nginx中的limit_req 和 limit_conn

在 Nginx 中&#xff0c;limit_req 和 limit_conn 是兩個用于限制客戶端請求的指令&#xff0c;它們分別用于限制請求速率和并發連接數。 limit_req limit_req 用于限制請求速率&#xff0c;防止客戶端發送過多請求影響服務器性能。它通過 limit_req_zone 指令定義一個共享內存…

基于winform的串口調試助手

目錄 一、串口助手界面設計 1.1 串口配置 1.2 接收配置 1.3 發送配置 1.4 接收窗口和發送窗口 1.5 狀態顯示窗口 1.6 串口通訊控件 二、程序編寫 2.1 端口號自動識別并顯示在端口號下拉框 功能說明&#xff1a; 2.2 波特率下拉框顯示 2.3 數據位下拉框顯示 2.4 校…

Docker基礎2

如需轉載&#xff0c;標記出處 本次我們將下載一個 Docker 鏡像&#xff0c;從鏡像中啟動容器 上一章&#xff0c;安裝 Docker 時&#xff0c;獲得兩個主要組件&#xff1a; Docker 客戶端 Docker 守護進程&#xff08;有時稱為“服務器”或“引擎”&#xff09; 守護進程實…

Rocketmq2

一、生產者端防丟失 1. 發送方式選擇 同步發送&#xff1a;使用 send() 方法&#xff0c;等待 Broker 確認響應&#xff08;SendResult&#xff09;&#xff0c;確保消息已成功發送。異步發送&#xff1a;使用 sendAsync() 方法并設置回調函數&#xff0c;處理發送成功 / 失敗…

RabbitMQ詳解,RabbitMQ是什么?架構是怎樣的?

目錄 一,RabbitMQ是什么? 二,RabbitMQ架構 2.1 首先我們來看下RabbitMQ里面的心概念Queue是什么? 2.2 交換器Exchange 2.3 RabbitMQ是什么? 2.4 重點看下優先級隊列是什么? 三,RabbitMQ集群 3.1 普通集群模式 3.2 鏡像隊列集群 一,RabbitMQ是什么? 假設我們程序…

【一步步開發AI運動APP】六、運動計時計數能調用

之前我們為您分享了【一步步開發AI運動小程序】開發系列博文&#xff0c;通過該系列博文&#xff0c;很多開發者開發出了很多精美的AI健身、線上運動賽事、AI學生體測、美體、康復鍛煉等應用場景的AI運動小程序&#xff1b;為了幫助開發者繼續深耕AI運動領域市場&#xff0c;今…

MySQL——DQL的多表查詢

一、交叉連接 標準語法&#xff1a;select * from 表1 cross join 表2 where 表1.公共列 表2.公共列; 簡單語法&#xff1a;select * from 表1 , 表2 where 表1.公共列 表2.公共列; 公共列&#xff1a;兩張表具有相同含義的列&#xff0c;不是列名一樣。 …

【Linux內核】如何更加優雅閱讀Linux內核源碼(vscode)

1. 前言 因為已經習慣在Ubuntu下進行嵌入式工作開發&#xff0c;但Linux源碼在Source Insight下進行閱讀&#xff0c;一直很苦惱Linux/Windows來回切換的開發方式&#xff0c;當前發現可以通過 vscode clangd(擴展組件) 方式進行更好的內核源碼閱讀。 2. 環境 操作系統&…

21.OpenCV獲取圖像輪廓信息

OpenCV獲取圖像輪廓信息 在計算機視覺領域&#xff0c;識別和分析圖像中的對象形狀是一項基本任務。OpenCV 庫提供了一個強大的工具——輪廓檢測&#xff08;Contour Detection&#xff09;&#xff0c;它能夠幫助我們精確地定位對象的邊界。這篇博文將帶你入門 OpenCV 的輪廓…

LETTERS(DFS)

【題目描述】 給出一個rowcolrowcol的大寫字母矩陣&#xff0c;一開始的位置為左上角&#xff0c;你可以向上下左右四個方向移動&#xff0c;并且不能移向曾經經過的字母。問最多可以經過幾個字母。 【輸入】 第一行&#xff0c;輸入字母矩陣行數RR和列數SS&#xff0c;1≤R,S≤…

Day2-2:前端項目uniapp壁紙實戰

再在wallpaper新建一個目錄components 在components下新建組件common-title 記得點擊創建同名目錄 在index加 <view class"select"><common-title></common-title></view> 圖片換了下&#xff0c;原來的有點丑&#xff0c;圖片可按自己喜歡…

其他 vector 操作詳解(四十)

介紹 除去向 vector 添加元素&#xff08;如 push_back&#xff09;之外&#xff0c;vector 還提供了許多其他操作&#xff0c;這些操作大多與 string 的操作類似。通過掌握這些操作&#xff0c;我們可以方便地查詢、修改和比較 vector 中的元素&#xff0c;從而構建靈活、高效…

【Leetcode 每日一題】368. 最大整除子集

問題背景 給你一個由 無重復 正整數組成的集合 n u m s nums nums&#xff0c;請你找出并返回其中最大的整除子集 a n s w e r answer answer&#xff0c;子集中每一元素對 ( a n s w e r [ i ] , a n s w e r [ j ] ) (answer[i], answer[j]) (answer[i],answer[j]) 都應當…

python基礎-13-處理excel電子表格

文章目錄 【README】【13】處理Excel電子表格【13.1】Excel文檔【13.2】安裝openpyxl模塊【13.3】讀取Excel文檔【13.3.1】使用openpyxl模塊打開excel文檔【13.3.2】從工作簿取得工作表【13.3.3】從工作表sheet獲取單元格cell【13.3.5】從表中獲取行和列【13.3.6】工作簿、工作…

ABS函數c++

簡介&#xff1a; abs 函數用于計算一個數的絕對值&#xff0c;在 C 中它繼承自 C 語言的標準庫&#xff0c;其歷史可以追溯到早期的 C 語言發展歷程&#xff0c;以下是詳細介紹&#xff1a; 早期編程語言的需求 在計算機編程的早期階段&#xff0c;處理數學運算就是一項基本…

閉環SOTA!北航DiffAD:基于擴散模型實現端到端自動駕駛「多任務閉環統一」

端到端自動駕駛目前是有望實現完全自動駕駛的一條有前景的途徑。然而&#xff0c;現有的端到端自動駕駛系統通常采用主干網絡與多任務頭結合的方式&#xff0c;但是它們存在任務協調和系統復雜度高的問題。為此&#xff0c;本文提出了DiffAD&#xff0c;它統一了各種駕駛目標并…