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

Python----計算機視覺處理(Opencv:道路檢測之道路透視變換)

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

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

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

一、透視變換

def img_to_wrp(img):height, width,_= img.shape  # 獲取輸入圖像的高度和寬度# 定義源點(透視變換前的點)src = np.float32([[width // 2 - 75, height // 2],  # 左側車道線的源點[width // 2 + 100, height // 2],  # 右側車道線的源點[0, height],  # 底部左側點[width, height]  # 底部右側點])# 定義目標點(透視變換后的點)dst = np.float32([[0, 0],  # 目標左上角[width, 0],  # 目標右上角[0, height],  # 目標左下角[width, height]  # 目標右下角])# 計算透視變換矩陣M = cv2.getPerspectiveTransform(src, dst)# 計算逆透視變換矩陣W = cv2.getPerspectiveTransform(dst, src)# 應用透視變換img_wrp = cv2.warpPerspective(img, M, (width, height), flags=cv2.INTER_LINEAR)return img_wrp, W  # 返回透視變換后的圖像和逆變換矩陣

????????這段代碼的作用是對輸入圖像進行透視變換,以便為后續的車道線檢測做好準備。

????????首先,它獲取輸入圖像的高度和寬度,并定義源點(`src`),這些點是透視變換前車道線和底邊的具體位置。源點的選取基于圖像中車道線的預期位置,以確保透視變換能夠有效地將車道區域從圖像的視角轉變為一個鳥瞰視圖。

????????接下來,定義目標點(`dst`),這些點表示在透視變換后的標準位置,即四個角分別為上左、上右、下左和下右,以便將車道區域展現為一個矩形。

????????然后,通過 `cv2.getPerspectiveTransform` 計算透視變換矩陣 `M`,同時也計算出逆變換矩陣 `W`。

????????最后,使用 `cv2.warpPerspective` 應用透視變換,將輸入圖像轉換為新的視角,輸出變換后的圖像 `img_wrp` 和逆變換矩陣 `W`,這為后續的圖像處理和車道線繪制提供了良好的基礎。

二、提取車道線

def img_road_show1(img):img_Gaussian = cv2.GaussianBlur(img, (7, 7), sigmaX=1)  # 對圖像進行高斯模糊,減少噪聲img_gray = cv2.cvtColor(img_Gaussian, cv2.COLOR_BGR2GRAY)  # 將模糊后的圖像轉換為灰度圖像img_Sobel = cv2.Sobel(img_gray, -1, dx=1, dy=0)  # 使用Sobel算子進行邊緣檢測,提取水平邊緣ret, img_threshold = cv2.threshold(img_Sobel, 127, 255, cv2.THRESH_BINARY)  # 二值化處理kernel = np.ones((11, 11), np.uint8)  # 創建一個11x11的結構元素img_dilate = cv2.dilate(img_threshold, kernel, iterations=2)  # 膨脹操作,增強白色區域img_erode = cv2.erode(img_dilate, kernel, iterations=2)  # 腐蝕操作,去除小噪聲return img_erode  # 返回處理后的圖像def img_road_show2(img):# 將圖像從BGR顏色空間轉換為HLS顏色空間img_hls = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)# 提取亮度通道l_channel = img_hls[:, :, 1]# 將亮度通道進行歸一化處理l_channel = l_channel / np.max(l_channel) * 255# 創建與亮度通道同樣大小的零數組binary_output1 = np.zeros_like(l_channel)# 根據亮度閾值提取車道線區域(亮度值范圍為220到255)binary_output1[(l_channel > 220) & (l_channel < 255)] = 1# 提取黃色車道線img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)  # 將圖像轉換為Lab顏色空間# 將圖像的下部分設置為黑色,以減少干擾img_lab[:, 240:, :] = (0, 0, 0)# 提取Lab顏色空間中的藍色通道lab_b = img_lab[:, :, 2]# 如果藍色通道的最大值大于100則歸一化處理if np.max(lab_b) > 100:lab_b = lab_b / np.max(lab_b) * 255# 創建與亮度通道同樣大小的零數組binary_output2 = np.zeros_like(l_channel)# 根據藍色通道的閾值提取車道線區域(藍色值范圍為212到220)binary_output2[(lab_b > 212) & (lab_b < 220)] = 1# 創建結構元素,用于形態學操作kernel = np.ones((15, 15), np.uint8)# 對binary_output2進行膨脹操作,以增強車道線binary_output2 = cv2.dilate(binary_output2, kernel, iterations=1)# 對膨脹后的圖像進行兩次腐蝕操作,去除小噪聲binary_output2 = cv2.erode(binary_output2, kernel, iterations=1)binary_output2 = cv2.erode(binary_output2, kernel, iterations=1)# 創建一個與binary_output1同樣大小的零數組binary_output = np.zeros_like(binary_output1)# 將兩個二值輸出結合,提取最終車道線區域binary_output[(binary_output1 == 1) | (binary_output2 == 1)] = 1# 對最終的二值輸出進行膨脹處理kernel = np.ones((15, 15), np.uint8)img_dilate_binary_output = cv2.dilate(binary_output, kernel, iterations=1)# 對膨脹后的圖像進行腐蝕處理,以便進一步去噪聲img_erode_binary_output = cv2.erode(img_dilate_binary_output, kernel, iterations=1)# 返回最終處理后的圖像return img_erode_binary_output

????????這段代碼包含兩個函數 `img_road_show1` 和 `img_road_show2`,用于處理輸入圖像并提取車道線區域。

????????`img_road_show1` 首先對輸入圖像應用高斯模糊,以減少噪聲,然后將其轉換為灰度圖并使用 Sobel 算子進行邊緣檢測,以提取水平邊緣。接著,進行二值化處理,將邊緣圖像轉為黑白圖像。之后,通過形態學操作(膨脹和腐蝕)增強白色區域并去除噪聲,最終返回處理后的圖像。

????????`img_road_show2` 則使用 HLS 顏色空間提取亮度通道,并通過閾值劃分提取亮度較高的車道線區域。接著,將圖像轉換為 Lab 顏色空間,提取藍色通道并進行歸一化,依次利用閾值檢測提取特定顏色的車道線,然后通過形態學操作去噪。

????????最終,將兩個二值化結果結合,提取出合并的車道線區域,進行再一次的膨脹和腐蝕操作,以確保得到干凈的二值圖像,最后返回這一處理后的圖像,以供后續分析或顯示。整體上,這兩個函數通過不同的方式(邊緣檢測和顏色空間分析)強化了車道線的可見性,以便于自動駕駛或圖像分析任務。

三、車道線擬合

def road_polyfit(img):# 獲取圖像的高度和寬度height, width = img.shape# 創建一個與輸入圖像相同大小的RGB圖像,用于繪制窗口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_numwindows_width = 30# 定義在窗口中檢測到的白色像素的最小數量min_pix = 400# 初始化當前窗口的位置,后續會根據檢測結果更新left_current = img_left_argmaxright_current = img_right_argmaxleft_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_widthwin_x_left_right = left_current + windows_width# 計算右側窗口的左右邊界x坐標win_x_right_left = right_current - windows_widthwin_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_preleft_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_preright_current = right_current + offset# 更新上一個窗口位置left_pre = left_currentright_pre = right_current# 將所有的索引連接成一個數組,以便后續提取像素點的坐標left_lane_inds = np.concatenate(left_lane_inds)right_lane_inds = np.concatenate(right_lane_inds)# 提取左側和右側車道線像素的位置leftx = nonzerox[left_lane_inds]  # 左側車道線的x坐標lefty = nonzeroy[left_lane_inds]  # 左側車道線的y坐標rightx = nonzerox[right_lane_inds]  # 右側車道線的x坐標righty = nonzeroy[right_lane_inds]  # 右側車道線的y坐標# 對左側和右側車道線進行多項式擬合,得到擬合曲線的參數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]# 計算中間車道線的位置middle_fitx = (left_fitx + right_fitx) // 2# 在輸出圖像上標記車道線像素點out_img[lefty, leftx] = [255, 0, 0]  # 左側車道線out_img[righty,rightx]=[0,0,255]# 右側車道線return left_fitx, right_fitx, middle_fitx, ploty

????????這段代碼實現了車道線檢測與擬合的功能,主要通過滑動窗口的方法來識別和擬合車道線。首先獲取輸入圖像的高度和寬度,并創建一個與輸入圖像相同大小的RGB圖像用于繪制結果。

????????接著,通過計算每一列的白色像素總和生成直方圖,找到左右車道線的起始點。

????????然后,定義滑動窗口的數量、每個窗口的高度和寬度,設置檢測到的白色像素的最小數量。接下來,遍歷每個窗口,繪制窗口并在窗口內檢測白色像素的索引。

????????如果在窗口中找到足夠的白色像素,則更新當前窗口的位置;如果沒有找到,則根據相鄰車道線的像素位置進行調整。

????????最后,提取所有窗口中檢測到的車道線像素的坐標,利用多項式擬合(使用二次多項式)計算出車道線的方程,并生成均勻分布的y坐標以繪制車道線。

????????最終,將左側和右側車道線的像素標記在輸出圖像上,并返回擬合的車道線坐標和對應的y坐標。這一過程有效地提取并可視化了車道線,便于后續的自動駕駛或圖像分析應用。

四、車道線顯示

def road_show_concatenate(img, img_wrp, W, img_road1, left_fitx, right_fitx, middle_fitx, ploty):# 創建一個與 img_road1 相同大小的零圖像,數據類型為 uint8wrp_zero = np.zeros_like(img_road1).astype(np.uint8)# 創建一個三通道的零圖像,用于存放車道線color_wrp = np.dstack((wrp_zero, wrp_zero, wrp_zero))# 組合車道線點的坐標,用于繪制# pts_left, pts_right, pts_middle 是車道線在(y, x)坐標系中的坐標點pts_left = np.transpose(np.vstack([left_fitx, ploty]))  # 包括左側車道線的坐標pts_right = np.transpose(np.vstack([right_fitx, ploty]))  # 包括右側車道線的坐標pts_middle = np.transpose(np.vstack([middle_fitx, ploty]))  # 包括中間車道線的坐標# 在 zero 圖像上繪制車道線cv2.polylines(color_wrp, np.int32([pts_left]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制左側車道線cv2.polylines(color_wrp, np.int32([pts_right]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制右側車道線cv2.polylines(color_wrp, np.int32([pts_middle]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制中間車道線# 將繪制的車道線通過逆透視變換映射到原始圖像的空間newwarp = cv2.warpPerspective(color_wrp, W, (img.shape[1], img.shape[0]))# 將透視變換后的圖像與原始圖像進行加權融合result1 = cv2.addWeighted(img, 1, newwarp, 1, 0)# 創建一個背景圖像,并將其初始化為中間灰色background_zero = np.zeros_like(img).astype(np.uint8) + 127# 將新變換的車道線圖像與背景圖像進行加權融合result = cv2.addWeighted(background_zero, 1, newwarp, 1, 0)# 將原始圖像與透視變換的圖像進行水平拼接concatenate_image1 = np.concatenate((img, img_wrp), axis=1)# 將加權融合的結果與車道線圖像進行水平拼接concatenate_image2 = np.concatenate((result1, result), axis=1)# 將兩個拼接結果進行垂直拼接,形成最終圖像concatenate_image = np.concatenate((concatenate_image1, concatenate_image2), axis=0)return concatenate_image  # 返回最終拼接的圖像

????????這段代碼的目的是將車道線可視化結果與輸入圖像進行拼接,以便于展示處理效果。

????????首先,通過創建一個與 `img_road1` 同樣大小的零圖像和一個三通道的零圖像,準備繪制車道線。

????????然后,通過將左側、右側和中間車道線的坐標點(通過擬合獲得)組合在一起以便繪制。

????????接著,使用 `cv2.polylines` 在零圖像上繪制車道線,賦予其顏色和厚度。

????????接下來,利用逆透視變換將繪制的車道線圖像映射到原始圖像的空間,并將其與原始圖像進行加權融合,生成一個包含車道線的圖像。為提供背景對比,創建一個中間灰色的背景圖像,并將車道線圖像與該背景融合。

????????隨后,將原始圖像與透視變換后的圖像以及加權融合的結果進行水平拼接。

????????最終,將這兩個拼接結果進行垂直拼接,形成一個展示原始圖像、透視圖和加權結果的最終圖像,便于查看車道線檢測與處理效果。該過程為圖像處理和計算機視覺任務提供了直觀的可視化方式。

五、完整代碼

import numpy as np
import cv2# 定義透視變換函數
def img_to_wrp(img):height, width,_= img.shape  # 獲取輸入圖像的高度和寬度# 定義源點(透視變換前的點)src = np.float32([[width // 2 - 75, height // 2],  # 左側車道線的源點[width // 2 + 100, height // 2],  # 右側車道線的源點[0, height],  # 底部左側點[width, height]  # 底部右側點])# 定義目標點(透視變換后的點)dst = np.float32([[0, 0],  # 目標左上角[width, 0],  # 目標右上角[0, height],  # 目標左下角[width, height]  # 目標右下角])# 計算透視變換矩陣M = cv2.getPerspectiveTransform(src, dst)# 計算逆透視變換矩陣W = cv2.getPerspectiveTransform(dst, src)# 應用透視變換img_wrp = cv2.warpPerspective(img, M, (width, height), flags=cv2.INTER_LINEAR)return img_wrp, W  # 返回透視變換后的圖像和逆變換矩陣# 定義圖像處理函數,提取車道線
def img_road_show1(img):img_Gaussian = cv2.GaussianBlur(img, (7, 7), sigmaX=1)  # 對圖像進行高斯模糊,減少噪聲img_gray = cv2.cvtColor(img_Gaussian, cv2.COLOR_BGR2GRAY)  # 將模糊后的圖像轉換為灰度圖像img_Sobel = cv2.Sobel(img_gray, -1, dx=1, dy=0)  # 使用Sobel算子進行邊緣檢測,提取水平邊緣ret, img_threshold = cv2.threshold(img_Sobel, 127, 255, cv2.THRESH_BINARY)  # 二值化處理kernel = np.ones((11, 11), np.uint8)  # 創建一個11x11的結構元素img_dilate = cv2.dilate(img_threshold, kernel, iterations=2)  # 膨脹操作,增強白色區域img_erode = cv2.erode(img_dilate, kernel, iterations=2)  # 腐蝕操作,去除小噪聲return img_erode  # 返回處理后的圖像def img_road_show2(img):# 將圖像從BGR顏色空間轉換為HLS顏色空間img_hls = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)# 提取亮度通道l_channel = img_hls[:, :, 1]# 將亮度通道進行歸一化處理l_channel = l_channel / np.max(l_channel) * 255# 創建與亮度通道同樣大小的零數組binary_output1 = np.zeros_like(l_channel)# 根據亮度閾值提取車道線區域(亮度值范圍為220到255)binary_output1[(l_channel > 220) & (l_channel < 255)] = 1# 提取黃色車道線img_lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)  # 將圖像轉換為Lab顏色空間# 將圖像的下部分設置為黑色,以減少干擾img_lab[:, 240:, :] = (0, 0, 0)# 提取Lab顏色空間中的藍色通道lab_b = img_lab[:, :, 2]# 如果藍色通道的最大值大于100則歸一化處理if np.max(lab_b) > 100:lab_b = lab_b / np.max(lab_b) * 255# 創建與亮度通道同樣大小的零數組binary_output2 = np.zeros_like(l_channel)# 根據藍色通道的閾值提取車道線區域(藍色值范圍為212到220)binary_output2[(lab_b > 212) & (lab_b < 220)] = 1# 創建結構元素,用于形態學操作kernel = np.ones((15, 15), np.uint8)# 對binary_output2進行膨脹操作,以增強車道線binary_output2 = cv2.dilate(binary_output2, kernel, iterations=1)# 對膨脹后的圖像進行兩次腐蝕操作,去除小噪聲binary_output2 = cv2.erode(binary_output2, kernel, iterations=1)binary_output2 = cv2.erode(binary_output2, kernel, iterations=1)# 創建一個與binary_output1同樣大小的零數組binary_output = np.zeros_like(binary_output1)# 將兩個二值輸出結合,提取最終車道線區域binary_output[(binary_output1 == 1) | (binary_output2 == 1)] = 1# 對最終的二值輸出進行膨脹處理kernel = np.ones((15, 15), np.uint8)img_dilate_binary_output = cv2.dilate(binary_output, kernel, iterations=1)# 對膨脹后的圖像進行腐蝕處理,以便進一步去噪聲img_erode_binary_output = cv2.erode(img_dilate_binary_output, kernel, iterations=1)# 返回最終處理后的圖像return img_erode_binary_outputdef road_polyfit(img):# 獲取圖像的高度和寬度height, width = img.shape# 創建一個與輸入圖像相同大小的RGB圖像,用于繪制窗口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_numwindows_width = 30# 定義在窗口中檢測到的白色像素的最小數量min_pix = 400# 初始化當前窗口的位置,后續會根據檢測結果更新left_current = img_left_argmaxright_current = img_right_argmaxleft_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_widthwin_x_left_right = left_current + windows_width# 計算右側窗口的左右邊界x坐標win_x_right_left = right_current - windows_widthwin_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_preleft_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_preright_current = right_current + offset# 更新上一個窗口位置left_pre = left_currentright_pre = right_current# 將所有的索引連接成一個數組,以便后續提取像素點的坐標left_lane_inds = np.concatenate(left_lane_inds)right_lane_inds = np.concatenate(right_lane_inds)# 提取左側和右側車道線像素的位置leftx = nonzerox[left_lane_inds]  # 左側車道線的x坐標lefty = nonzeroy[left_lane_inds]  # 左側車道線的y坐標rightx = nonzerox[right_lane_inds]  # 右側車道線的x坐標righty = nonzeroy[right_lane_inds]  # 右側車道線的y坐標# 對左側和右側車道線進行多項式擬合,得到擬合曲線的參數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]# 計算中間車道線的位置middle_fitx = (left_fitx + right_fitx) // 2# 在輸出圖像上標記車道線像素點out_img[lefty, leftx] = [255, 0, 0]  # 左側車道線out_img[righty,rightx]=[0,0,255]# 右側車道線return left_fitx, right_fitx, middle_fitx, plotydef road_show_concatenate(img, img_wrp, W, img_road1, left_fitx, right_fitx, middle_fitx, ploty):# 創建一個與 img_road1 相同大小的零圖像,數據類型為 uint8wrp_zero = np.zeros_like(img_road1).astype(np.uint8)# 創建一個三通道的零圖像,用于存放車道線color_wrp = np.dstack((wrp_zero, wrp_zero, wrp_zero))# 組合車道線點的坐標,用于繪制# pts_left, pts_right, pts_middle 是車道線在(y, x)坐標系中的坐標點pts_left = np.transpose(np.vstack([left_fitx, ploty]))  # 包括左側車道線的坐標pts_right = np.transpose(np.vstack([right_fitx, ploty]))  # 包括右側車道線的坐標pts_middle = np.transpose(np.vstack([middle_fitx, ploty]))  # 包括中間車道線的坐標# 在 zero 圖像上繪制車道線cv2.polylines(color_wrp, np.int32([pts_left]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制左側車道線cv2.polylines(color_wrp, np.int32([pts_right]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制右側車道線cv2.polylines(color_wrp, np.int32([pts_middle]), isClosed=False, color=(202, 124, 0), thickness=15)  # 繪制中間車道線# 將繪制的車道線通過逆透視變換映射到原始圖像的空間newwarp = cv2.warpPerspective(color_wrp, W, (img.shape[1], img.shape[0]))# 將透視變換后的圖像與原始圖像進行加權融合result1 = cv2.addWeighted(img, 1, newwarp, 1, 0)# 創建一個背景圖像,并將其初始化為中間灰色background_zero = np.zeros_like(img).astype(np.uint8) + 127# 將新變換的車道線圖像與背景圖像進行加權融合result = cv2.addWeighted(background_zero, 1, newwarp, 1, 0)# 將原始圖像與透視變換的圖像進行水平拼接concatenate_image1 = np.concatenate((img, img_wrp), axis=1)# 將加權融合的結果與車道線圖像進行水平拼接concatenate_image2 = np.concatenate((result1, result), axis=1)# 將兩個拼接結果進行垂直拼接,形成最終圖像concatenate_image = np.concatenate((concatenate_image1, concatenate_image2), axis=0)return concatenate_image  # 返回最終拼接的圖像if __name__ == '__main__':# 讀取圖像文件 '15.png'img = cv2.imread('15.png')# 對圖像進行透視變換,以便后續的車道線檢測img_wrp, W = img_to_wrp(img)# 通過顯示車道線的函數生成一個車道線顯示圖像img_road1 = img_road_show1(img_wrp)# 調用 road_polyfit 函數進行車道線的多項式擬合# left_fitx, right_fitx, middle_fitx 包含了左右車道線和中間車道線的 x 坐標# ploty 包含了 y 坐標的范圍left_fitx, right_fitx, middle_fitx, ploty = road_polyfit(img_road1)# 將處理后的圖像與繪制的車道線組合在一起concatenate_image = road_show_concatenate(img, img_wrp, W, img_road1, left_fitx, right_fitx, middle_fitx, ploty)# 顯示最終的拼接圖像cv2.imshow('concatenate_image', concatenate_image)# 等待用戶按下任意鍵,以退出顯示窗口cv2.waitKey(0)

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

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

相關文章

【Oracle篇】跨字符集遷移:基于數據泵的ZHS16GBK轉AL32UTF8全流程遷移

&#x1f4ab;《博主主頁》&#xff1a;奈斯DB-CSDN博客 &#x1f525;《擅長領域》&#xff1a;擅長阿里云AnalyticDB for MySQL(分布式數據倉庫)、Oracle、MySQL、Linux、prometheus監控&#xff1b;并對SQLserver、NoSQL(MongoDB)有了解 &#x1f496;如果覺得文章對你有所幫…

【C++算法】50.分治_歸并_翻轉對

文章目錄 題目鏈接&#xff1a;題目描述&#xff1a;解法C 算法代碼&#xff1a;圖解 題目鏈接&#xff1a; 493. 翻轉對 題目描述&#xff1a; 解法 分治 策略一&#xff1a;計算當前元素cur1后面&#xff0c;有多少元素的兩倍比我cur1小&#xff08;降序&#xff09; 利用單…

深入講解:智能合約中的讀寫方法

前言 在探秘區塊鏈開發:智能合約在 DApp 中的地位及與傳統開發差異一文中我提到對于智能合約中所有的寫入其實都算是交易。而在一個完整的智能合約代碼中最大的兩個組成部分就是讀取和寫入。 本文將為你深入探討該兩者方法之間的區別。 寫方法 寫方法其實就是對區塊鏈這一…

Go語言類型捕獲及內存大小判斷

代碼如下&#xff1a; 類型捕獲可使用&#xff1a;reflect.TypeOf()&#xff0c;fmt.Printf在的%T。 內存大小判斷&#xff1a;len()&#xff0c;unsafe.Sizeof。 package mainimport ("fmt""unsafe""reflect" )func main(){var i , j 1, 2f…

MyBatis Plus 在 ZKmall開源商城持久層的優化實踐

ZKmall開源商城作為基于 Spring Cloud 的高性能電商平臺&#xff0c;其持久層通過 MyBatis Plus 實現了多項深度優化&#xff0c;涵蓋分庫分表、緩存策略、分頁性能、多租戶隔離等核心場景。以下是具體實踐總結&#xff1a; 一、分庫分表與插件集成優化 1. 分庫分表策略 ?Sh…

學習MySQL第七天

夕陽無限好 只是近黃昏 一、子查詢 1.1 定義 將一個查詢語句嵌套到另一個查詢語句內部的查詢 我們通過具體示例來進行演示&#xff0c;這一篇博客更側重于通過具體的小問題來引導大家獨立思考&#xff0c;然后熟悉子查詢相關的知識點 1.2 問題1 誰的工資比Tom高 方…

Nginx 常見面試題

一、nginx常見錯誤及處理方法 1.1 404 bad request 一般原因&#xff1a;請求的Header過大 解決辦法&#xff1a; 配置nginx.conf 相關設置1. client_header_buffer_size 16k; 2. large_client_header_buffers 4 64k;1.2 413 Request Entity Too Large 一般原因&#xff1…

LeetCode 每日一題 2025/3/31-2025/4/6

記錄了初步解題思路 以及本地實現代碼&#xff1b;并不一定為最優 也希望大家能一起探討 一起進步 目錄 3/31 2278. 字母在字符串中的百分比4/1 2140. 解決智力問題4/2 2873. 有序三元組中的最大值 I4/3 2874. 有序三元組中的最大值 II4/4 1123. 最深葉節點的最近公共祖先4/5 1…

Docker Compose 常用命令 運行 docker-compose.yaml

Docker Compose 中有兩個重要的概念 服務 (service)&#xff1a;一個應用的容器&#xff0c;實際上可以包括若干運行相同鏡像的容器實例。 項目 (project)&#xff1a;由一組關聯的應用容器組成的一個完整業務單元&#xff0c;在 docker-compose.yml 文件中定義。 為了更方便…

深度學習中的 Batch 機制:從理論到實踐的全方位解析

一、Batch 的起源與核心概念 1.1 批量的中文譯名解析 Batch 在深度學習領域標準翻譯為"批量"或"批次"&#xff0c;指代一次性輸入神經網絡進行處理的樣本集合。這一概念源自統計學中的批量處理思想&#xff0c;在計算機視覺先驅者Yann LeCun于1989年提出…

Unity Internal-ScreenSpaceShadows 分析

一、代碼結構 // Unity built-in shader source. Copyright (c) 2016 Unity Technologies. MIT license (see license.txt)Shader "Hidden/Internal-ScreenSpaceShadows" {Properties {_ShadowMapTexture ("", any) "" {} // 陰影貼圖紋理&…

Token+JWT+Redis 實現鑒權機制

TokenJWTRedis 實現鑒權機制 使用 Token、JWT 和 Redis 來實現鑒權機制是一種常見的做法&#xff0c;尤其適用于分布式應用或微服務架構。下面是一個大致的實現思路&#xff1a; 1. Token 和 JWT 概述 Token&#xff1a;通常是一個唯一的字符串&#xff0c;可以用來標識用戶…

RPC與其他通信技術的區別,以及RPC的底層原理

1、什么是 RPC&#xff1f; 遠程過程調用&#xff08;RPC&#xff09; 是一種協議&#xff0c;它允許程序在不同計算機之間進行通信&#xff0c;讓開發者可以像調用本地函數一樣發起遠程請求。 通過 RPC&#xff0c;開發者無需關注底層網絡細節&#xff0c;能夠更專注于業務邏…

簡潔的 PlantUML 入門教程

評論中太多朋友在問&#xff0c;我的文章中圖例如何完成的。 我一直用plantUML,也推薦大家用&#xff0c;下面給出一個簡潔的PlantUML教程。 &#x1f331; 什么是 PlantUML&#xff1f; PlantUML 是一個用純文本語言畫圖的工具&#xff0c;支持流程圖、時序圖、用例圖、類圖、…

互聯網三高-高性能之JVM調優

1 運行時數據區 JVM運行時數據區是Java虛擬機管理的內存核心模塊&#xff0c;主要分為線程共享和線程私有兩部分。 &#xff08;1&#xff09;線程私有 ① 程序計數器&#xff1a;存儲當前線程執行字節碼指令的地址&#xff0c;用于分支、循環、異常處理等流程控制? ② 虛擬機…

淺談StarRocks 常見問題解析

StarRocks數據庫作為高性能分布式分析數據庫&#xff0c;其常見問題及解決方案涵蓋環境部署、數據操作、系統穩定性、安全管控及生態集成五大核心領域&#xff0c;需確保Linux系統環境、依賴庫及環境變量配置嚴格符合官方要求以避免節點啟動失敗&#xff0c;數據導入需遵循格式…

P1332 血色先鋒隊(BFS)

題目背景 巫妖王的天災軍團終于卷土重來&#xff0c;血色十字軍組織了一支先鋒軍前往諾森德大陸對抗天災軍團&#xff0c;以及一切沾有亡靈氣息的生物。孤立于聯盟和部落的血色先鋒軍很快就遭到了天災軍團的重重包圍&#xff0c;現在他們將主力只好聚集了起來&#xff0c;以抵…

大文件上傳之斷點續傳實現方案與原理詳解

一、實現原理 文件分塊&#xff1a;將大文件切割為固定大小的塊&#xff08;如5MB&#xff09; 進度記錄&#xff1a;持久化存儲已上傳分塊信息 續傳能力&#xff1a;上傳中斷后根據記錄繼續上傳未完成塊 塊校驗機制&#xff1a;通過哈希值驗證塊完整性 合并策略&#xff1a;所…

【動手學深度學習】卷積神經網絡(CNN)入門

【動手學深度學習】卷積神經網絡&#xff08;CNN&#xff09;入門 1&#xff0c;卷積神經網絡簡介2&#xff0c;卷積層2.1&#xff0c;互相關運算原理2.2&#xff0c;互相關運算實現2.3&#xff0c;實現卷積層 3&#xff0c;卷積層的簡單應用&#xff1a;邊緣檢測3.1&#xff0…

Opencv計算機視覺編程攻略-第十一節 三維重建

此處重點討論在特定條件下&#xff0c;重建場景的三維結構和相機的三維姿態的一些應用實現。下面是完整投影公式最通用的表示方式。 在上述公式中&#xff0c;可以了解到&#xff0c;真實物體轉為平面之后&#xff0c;s系數丟失了&#xff0c;因而無法會的三維坐標&#xff0c;…