Python----计算机视觉处理(Opencv:道路检测之提取车道线)

发布于:2025-04-04 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、提取车道线

        在道路检测中,提取车道线至关重要。我们采用两种主要方法进行车道线提取:梯度提取颜色提取。梯度提取包括高斯滤波、灰度化、梯度处理、二值化和形态学变换(膨胀和腐蚀),能有效突出车道线的边缘特征;颜色提取则通过 HLS 颜色空间提取白色车道线和使用 Lab 颜色空间提取黄色车道线,可以进一步增强车道线的可区分性。这两种方法结合使用,有助于实现更准确的车道线检测。

1.1、梯度提取

高斯滤波

  • 使用高斯滤波器对输入图像进行平滑,减少噪声,帮助后续的梯度计算。

灰度化

  • 将彩色图像转换为灰度图像,以简化图像数据。

梯度处理

  • 使用Sobel算子计算图像的梯度,可以计算x和y方向的梯度。

二值化

  • 通过阈值处理将图像二值化,突出边缘。

形态学变换(膨胀,腐蚀)

  • 使用膨胀和腐蚀来去除噪声和填补空洞。

1.2、颜色提取

白色提取(HLS空间

  • 通过转换到HLS颜色空间来提取白色车道线。

黄色提取(Lab空间

  • 将图像转换到Lab颜色空间,以便提取黄色区域。

二、梯度提取

 导入模块

import cv2
import numpy as np

输入图像

img_wrp=cv2.imread('img_wrp.png')

高斯滤波

img_Gaussian=cv2.GaussianBlur(img_wrp,(7,7),sigmaX=1)

 

灰度化

img_gray=cv2.cvtColor(img_Gaussian,cv2.COLOR_BGR2GRAY)

梯度处理

img_Sobel=cv2.Sobel(img_gray,-1,dx=1,dy=0)

二值化

ret,img_threshold=cv2.threshold(img_Sobel,127,255,cv2.THRESH_BINARY)

形态学变换(先膨胀后腐蚀)

kernel=np.ones((11,11),np.uint8)
img_dilate=cv2.dilate(img_threshold,kernel,iterations=2)
img_erode=cv2.erode(img_dilate, kernel, iterations=1)

 输出图像

cv2.imshow('img_wrp', img_wrp)
cv2.imshow('img_Gaussian', img_Gaussian)
cv2.imshow('img_gray', img_gray)
cv2.imshow('img_Sobel', img_Sobel)
cv2.imshow('img_threshold', img_threshold)
cv2.imshow('img_erode', img_erode)
cv2.waitKey(0)

完整代码 

import cv2
import numpy as np

# 读取透视变换后的图像 'img_wrp.png'  
img_wrp = cv2.imread('img_wrp.png')  

# 对图像应用高斯模糊,减少噪声,使用的卷积核为 (7, 7),sigmaX 为 1  
img_Gaussian = cv2.GaussianBlur(img_wrp, (7, 7), sigmaX=1)  

# 将模糊后的图像转换为灰度图  
img_gray = cv2.cvtColor(img_Gaussian, cv2.COLOR_BGR2GRAY)  

# 对灰度图像应用 Sobel 边缘检测,使用水平梯度 (dx=1, dy=0)  
img_Sobel = cv2.Sobel(img_gray, -1, dx=1, dy=0)  

# 对 Sobel 输出的图像应用二值化处理,将图像转换为黑白图像  
# 当像素值 > 127 时,设为 255;否则设为 0  
ret, img_threshold = cv2.threshold(img_Sobel, 127, 255, cv2.THRESH_BINARY)  

# 创建一个 11x11 的全 1 核,进行形态学操作  
kernel = np.ones((11, 11), np.uint8)  

# 对二值化图像进行膨胀操作,增加白色区域  
img_dilate = cv2.dilate(img_threshold, kernel, iterations=2)  

# 对膨胀后的图像进行腐蚀操作,减少白色区域  
img_erode = cv2.erode(img_dilate, kernel, iterations=1)  

# 显示各步骤处理后的图像  
cv2.imshow('img_wrp', img_wrp)           # 显示原始透视变换图  
cv2.imshow('img_Gaussian', img_Gaussian) # 显示高斯模糊后的图像  
cv2.imshow('img_gray', img_gray)         # 显示灰度图像  
cv2.imshow('img_Sobel', img_Sobel)       # 显示 Sobel 边缘检测结果  
cv2.imshow('img_threshold', img_threshold) # 显示二值化后的图像  
cv2.imshow('img_erode', img_erode)       # 显示腐蚀后的图像  

# 等待按键后关闭窗口  
cv2.waitKey(0)  
  1. 读取透视变换后保存的图像。
  2. 对图像应用高斯模糊,减少噪声以平滑图像。
  3. 将模糊图像转换为灰度图,以便进行边缘检测。
  4. 使用 Sobel 算子检测图像的水平边缘。
  5. 将 Sobel 输出的图像进行二值化处理,以获取明显的边缘部分。
  6. 进行形态学的膨胀和腐蚀操作,增加和减少白色区域,进一步改善图像质量。
  7. 显示处理后各个步骤的图像,方便观察效果。

三、颜色提取

 导入模块

import cv2
import numpy as np

 输入图像

img_wrp=cv2.imread('img_wrp.png')

 提取白色车道线

img_hls=cv2.cvtColor(img_wrp,cv2.COLOR_BGR2HLS)
l_channel=img_hls[:,:,1]
l_channel=l_channel/np.max(l_channel)*255
binary_output1=np.zeros_like(l_channel)
binary_output1[(l_channel>220) & (l_channel<255)]=1

 

 提取黄色车道线

img_lab=cv2.cvtColor(img_wrp,cv2.COLOR_BGR2Lab)
img_lab[:,240:,:]=(0,0,0)
lab_b=img_lab[:,:,2]
if np.max(lab_b)>100:
    lab_b=lab_b/np.max(lab_b)*255
binary_output2=np.zeros_like(l_channel)
binary_output2[(lab_b > 212) & (lab_b < 220)] = 1

 对车道线进行合并

#直接进行相加
binary_output=binary_output1+binary_output2

 或

#创建新的模板
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)

 输出图像

cv2.imshow('binary_output1',binary_output1)
cv2.imshow('binary_output2', binary_output2)
cv2.imshow('binary_output', binary_output)
cv2.imshow('img_erode_binary_output', img_erode_binary_output)
cv2.waitKey(0)

 完整代码

import cv2  # 导入 OpenCV 库,用于图像处理  
import numpy as np  # 导入 NumPy 库,用于数值计算  

# 读取透视变换后的图像 'img_wrp.png'  
img_wrp = cv2.imread('img_wrp.png')  

# 将图像从 BGR 转换到 HLS 颜色空间  
img_hls = cv2.cvtColor(img_wrp, cv2.COLOR_BGR2HLS)  

# 提取 HLS 中的亮度通道 (L通道)  
l_channel = img_hls[:, :, 1]  

# 将亮度通道归一化到 0 到 255 的范围  
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  

# 提取黄色车道线  
# 转换原图像为 Lab 颜色空间  
img_lab = cv2.cvtColor(img_wrp, cv2.COLOR_BGR2Lab)  

# 将 Lab 图像的某些区域(240列及之后的所有区域)设为黑色  
img_lab[:, 240:, :] = (0, 0, 0)  

# 提取 Lab 图像中的 b 通道  
lab_b = img_lab[:, :, 2]  

# 对 b 通道进行归一化处理(如果最大值大于 100)  
if np.max(lab_b) > 100:  
    lab_b = lab_b / np.max(lab_b) * 255  

# 创建一个与亮度通道同样大小的零数组,用于存放二值化结果  
binary_output2 = np.zeros_like(l_channel)  

# 使用阈值条件筛选出 b 通道中处于 212 到 220 之间的像素点  
binary_output2[(lab_b > 212) & (lab_b < 220)] = 1  

# 创建一个新的二值图像 binary_output,结合两个二值图像  
binary_output = np.zeros_like(binary_output1)  
binary_output[(binary_output1 == 1) | (binary_output2 == 1)] = 1  

# 创建一个 15x15 的全 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)  

# 显示不同阶段的二值化输出图像  
cv2.imshow('binary_output1', binary_output1)              # 显示亮度通道的二值化结果  
cv2.imshow('binary_output2', binary_output2)              # 显示黄色车道线的二值化结果  
cv2.imshow('binary_output', binary_output)                # 显示结合后的二值图像  
cv2.imshow('img_erode_binary_output', img_erode_binary_output)  # 显示腐蚀处理后的图像  

# 等待按键后关闭窗口  
cv2.waitKey(0)  

  1. 读取透视变换后的图像,并将其转换为 HLS 颜色空间,以提取亮度通道。
  2. 将亮度通道归一化并进行二值化,提取亮度较高的区域。
  3. 转换图像为 Lab 颜色空间,提取 b 通道并进行归一化处理,选择黄色车道线。
  4. 创建一个结合两个输出的最终二值图像,该图像包含亮度和黄色车道线的信息。
  5. 使用膨胀和腐蚀操作改善二值图像的形态,去除噪声和空隙。
  6. 显示每个步骤的结果,以便进行视觉比较和分析。

四、库函数

4.1、cvtColor()

cv.cvtColor(	src, code[, dst[, dstCn[, hint]]]	) ->	dst
方法 描述
src 输入图像:8 位无符号、16 位无符号 ( CV_16UC... ) 或单精度浮点。
dst 输出图像的大小和深度与 src 相同。
code 色彩空间转换代码(请参阅 ColorConversionCodes)。
dstCn 目标图像中的通道数;如果参数为 0,则 Channels 的数量会自动从 src 和 code 中得出。
hint 实现修改标志。请参阅 AlgorithmHint

4.2、GaussianBlur()

 

cv.GaussianBlur(	src, ksize, sigmaX[, dst[, sigmaY[, borderType[, hint]]]]	) ->	DST
方法 描述
src 输入图像;图像可以有任意数量的通道,这些通道是独立处理的,但深度应为 CV_8U、CV_16U、CV_16S、CV_32F 或 CV_64F。
dst 输出图像的大小和类型与 src 相同。
ksize Gaussian kernel 大小。ksize.width 和 ksize.height 可以不同,但它们都必须是正数和奇数。或者,它们可以是零,然后根据 sigma 计算。
sigmaX X 方向上的高斯核标准差
sigmaY Y 方向的高斯核标准差;如果 sigmaY 为零,则设置为等于 sigmaX,如果两个 sigma 都为零,则分别从 ksize.width 和 ksize.height 计算出来(详见 getGaussianKernel);为了完全控制结果,而不管所有这些语义将来可能如何修改,建议指定所有 ksize、sigmaX 和 sigmaY。
borderType 像素外插方法,请参阅 BorderTypes。不支持BORDER_WRAP
hint 实现修改标志。请参阅 AlgorithmHint

4.3、threshold()

 将固定级别的阈值应用于每个数组元素。

        该函数将固定级别的阈值应用于多通道数组。该函数通常用于从灰度图像中获取双层(二进制)图像( compare 也可用于此目的)或用于去除噪声,即过滤掉值太小或太大的像素。该函数支持多种类型的阈值。它们由 type parameter 确定。

        此外,特殊值 THRESH_OTSU 或 THRESH_TRIANGLE 可以与上述值之一结合使用。在这些情况下,该函数使用 Otsu 或 Triangle 算法确定最佳阈值,并使用它而不是指定的阈值。

注意

目前,Otsu 和 Triangle 方法仅针对 8 位单通道图像实现。

cv.threshold(src, thresh, maxval, type[, dst]) ->retval, dst
方法 描述
src 输入数组 (多通道、8 位或 32 位浮点)
thresh

阈值

maxval Maximum 值,用于 THRESH_BINARY 和 THRESH_BINARY_INV 阈值类型。
type 阈值类型

注意:

        该方法有两个返回值retval、dst 

阈值作的类型

THRESH_BINARY 

Python: cv.THRESH_BINARY

阈值法

THRESH_BINARY_INV 

Python: cv.THRESH_BINARY_INV

反阈值法

THRESH_TRUNC 

Python: cv.THRESH_TRUNC

截断阈值法

THRESH_TOZERO 

Python: cv.THRESH_TOZERO

低阈值零处理

THRESH_TOZERO_INV 

Python: cv.THRESH_TOZERO_INV

超阈值零处理

THRESH_MASK 

Python: cv.THRESH_MASK

THRESH_OTSU 

Python: cv.THRESH_OTSU

OTSU阈值法

flag 中,使用 Otsu 算法选择最佳阈值
THRESH_TRIANGLE 

Python: cv.THRESH_TRIANGLE

Triangle阈值法

标志,使用 Triangle 算法选择最佳阈值

4.4、Sobel()

 

cv.Sobel(	src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]	) ->	dst
方法 描述
src 输入图像
dst 输出图像
ddepth 目标图像的所需深度,请参阅组合
dx 导数 X 的阶数
dy 导数 y 的阶数
ksize 扩展 Sobel 核的大小;它必须是 1、3、5 或 7。
scale 计算的导数值的可选比例因子;默认情况下,不应用缩放(有关详细信息,请参阅 getDerivKernels)。
delta 在将过滤的像素存储到 DST 之前添加到过滤像素的可选值。
borderType 素外插方法,请参阅 BorderTypes。不支持BORDER_WRAP

4.5、dilate()

cv.dilate(	src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]	) ->	dst
方法 描述
src 输入图像;通道数可以是任意的,但深度应该是 CV_8U、 CV_16U、 CV_16S、 CV_32F 或 CV_64F 之一。
dst 输出图像的大小和类型与 src 相同。
kernel 用于扩张的结构元件;如果 element=Mat(),则使用 3 x 3 矩形结构元素。可以使用 getStructuringElement 创建 Kernel
anchor 锚点在元素中的位置;默认值 (-1, -1) 表示锚点位于元素中心。
iterations 应用扩张的次数。
borderType 像素外插方法,请参阅 BorderTypes。不支持BORDER_WRAP
borderValue border 值(如果边界为常量)
BorderTypes
BORDER_CONSTANT

Python:cv.BORDER_CONSTANT

iiiiii|abcdefgh|iiiiiii并指定一些i

BORDER_REPLICATE

Python:cv.BORDER_REPLICATE

aaaaaa|abcdefgh|hhhhhhh

BORDER_REFLECT

Python:cv.BORDER_REFLECT

fedcba|abcdefgh|hgfedcb

BORDER_REFLECT_101

Python:cv.BORDER_REFLECT_101

gfedcb|abcdefgh|gfedcba

BORDER_TRANSPARENT

Python:cv.BORDER_TRANSPARENT

uvwxyz|abcdefgh|ijklmno- 将离群值视为透明值。

BORDER_REFLECT101

Python:cv.BORDER_REFLECT101

与 BORDER_REFLECT_101 相同

BORDER_DEFAULT

Python:cv.BORDER_DEFAULT

与 BORDER_REFLECT_101 相同

BORDER_ISOLATED

Python:cv.BORDER_ISOLATED

插值限制在 ROI 边界内。

4.6、erode()

cv.erode(	src, kernel[, dst[, anchor[, iterations[, borderType[, borderValue]]]]]	) ->	dst
方法 描述
src 输入图像;通道数可以是任意的,但深度应该是 CV_8U、 CV_16U、 CV_16S、 CV_32F 或 CV_64F 之一。
dst 输出图像的大小和类型与 src 相同。
kernel 用于侵蚀的结构元件;如果 ,则使用矩形结构元素。可以使用 getStructuringElement 创建 Kernel。element=Mat()3 x 3
anchor 锚点在元素中的位置;默认值 (-1, -1) 表示锚点位于元素中心。
iterations 应用 腐蚀的次数。
borderType 像素外插方法,请参阅 BorderTypes。不支持BORDER_WRAP
borderValue border 值(如果边界为常量)
BorderTypes
BORDER_CONSTANT

Python:cv.BORDER_CONSTANT

iiiiii|abcdefgh|iiiiiii并指定一些i

BORDER_REPLICATE

Python:cv.BORDER_REPLICATE

aaaaaa|abcdefgh|hhhhhhh

BORDER_REFLECT

Python:cv.BORDER_REFLECT

fedcba|abcdefgh|hgfedcb

BORDER_REFLECT_101

Python:cv.BORDER_REFLECT_101

gfedcb|abcdefgh|gfedcba

BORDER_TRANSPARENT

Python:cv.BORDER_TRANSPARENT

uvwxyz|abcdefgh|ijklmno- 将离群值视为透明值。

BORDER_REFLECT101

Python:cv.BORDER_REFLECT101

与 BORDER_REFLECT_101 相同

BORDER_DEFAULT

Python:cv.BORDER_DEFAULT

与 BORDER_REFLECT_101 相同

BORDER_ISOLATED

Python:cv.BORDER_ISOLATED

插值限制在 ROI 边界内。