【Lane Detection】车道线检测的简单实现 (OpenCV)

本文通过OpenCV实现车道线检测,详细介绍了从图片灰度处理、Canny边缘检测、霍夫变换到直线拟合的步骤。文章还讨论了方法的改进,包括使用HSV空间提取黄色和白色像素,应用高斯模糊减少噪声,调整ROI形状为梯形,以及改进直线拟合策略以提高检测稳定性。
摘要由CSDN通过智能技术生成

目录

1 导入工具库,查看图片

2 图片灰度处理

3 Canny边缘检测

4 划定ROI

5 霍夫变换,直线检测

6 直线拟合,根据端点画出左右 lane

7 Pipeline搭建 & Video车道检测

8 方法改进

8.1 分别提取yellow pixels(HSV) & white pixels

8.2 高斯模糊(减小噪声)

8.3 ROI 由三角形,改进为上窄下宽的梯形

 8.4 直线拟合:采用平均斜率和平均点来确定近似直线

8.5 Pipeline and results


 利用OpenCV工具库,采用一些图像处理方法,实现车道线的简单检测。

 

用到的cv库函数:

cv2.fillPoly() for regions selection
cv2.line() to draw lines on an image given endpoints
cv2.addWeighted() to coadd / overlay two images
cv2.cvtColor() to grayscale or change color
cv2.bitwise_and() to apply a mask to an image

思路:

  1. Grayscale将图片灰度化(方便后续的边缘检测)
  2. Canny Edge Detection边缘检测(Canny 边缘检测,检测出边缘像素点)
  3. Hough Transform 霍夫变换(检测边缘像素点的可能直线)
  4. Group Left and Right Lines 根据直线斜率将霍夫变换检测出的直线分组:left or right
  5. Fit and Draw 将左右两组的线分别拟合为一条线,并设定 y_bottom 和y_top,根据拟合方程分别求出left和right的 x_bottom和x_top,完成检测,左线:(left_x_bottom ,y_bottom,left_x_top,y_top),右线:(right_x_bottom ,y_bottom,right_x_top,y_top)

1 导入工具库,查看图片

import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
# reading in an image
image = mpimg.imread('whiteCarLaneSwitch.jpg')
# printing out some stats and plotting the image
print('This image is:', type(image), 'with dimensions:', image.shape)
plt.imshow(image)
plt.show()

2 图片灰度处理

读入的图像是RGB格式,channel=3,后续进行边缘检测时只关注color的强度变化,对于color是什么并不会影响检测结果。所以先将图像灰度化,作为后续边缘检测的预处理。

灰度化的结果是只有一个通道的图像,但是如果要查看灰度图片,需要 plt.imshow(gray_img,cmap='gray')。

def grayscale(img):
        """
        将图像灰度化,作为后续边缘检测的预处理
        """
        return cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
gray_img=grayscale(image)
plt.imshow(gray_img)

 

3 Canny边缘检测

边缘检测的目的,是检测出最类似边缘的像素点,其结果是一些pixels。这些pixels的特点是,像素值变化大,也就是梯度较大。Canny边缘检测基于x y方向的像素梯度来实现检测。

cv2.Canny(img,low_threshold,high_threshold):

大于 high_threshold:  edge;
小于 low_threshold:  not edge;
中间值(low_threshold, high_threshold):若与edge相连,则认为是edge,不相连则 not edge

def canny(img,low_threshold=100,high_threshold=200):
        """
        input是经过灰度处理的灰度图像,不关注颜色,只关注颜色强度
        边缘检测,原理:计算颜色值的梯度和方向,找到梯度变化较大的像素
        >high_threshold: edge
        <low_threshold:not edge
        中间值:若与edge相连,则认为是edge,不相连则not edge
        """
        return cv2.Canny(img,low_threshold,high_threshold)
canny_img=canny(gray_img)
plt.imshow(canny_img)

4 划定ROI

根据行车记录仪图像特点,我们将目标区域缩小为一个三角形(底边在bottom上,顶点大约在图像中心位置),划定该区域为ROI(Region of Interests),将其他区域里的目标进行遮挡(mask 掩膜操作)。

def region_of_interest(img):
        """
        分割出ROI,并填充,再对图像掩膜处理,将其他object遮挡
        """
        #draw the polygon with three vertices
        height=img.shape[0]
        width=img.shape[1]
        region_of_interest_vertices = [
        (0, height),
        (width / 2, height / 2),
        (width, height)]
        # Define a blank matrix that matches the image height/width.
        mask = np.zeros_like(img)
        # Retrieve the number of color channels of the image.
        #channel_count = img.shape[2]
        # Create a match color with the same color channel counts.
        #match_mask_color = (255,) * channel_count #彩色图像时的color
        match_mask_color = 255
        # Fill inside the polygon
        #cv2.fillPoly(mask, np.array([region_of_interest_vertices],np.int32),match_mask_color)#多边形填充
        cv2.fillPoly(mask, np.array([region_of_interest_vertices],np.int32), match_mask_color)
        #按位与操作,对图片进行mask淹膜操作,ROI区域正常显示,其他区域置零
        masked_image = cv2.bitwise_and(img, mask) 
        return masked_image
ROI_img=region_of_interest(canny_img)
plt.imshow(ROI_img)

5 霍夫变换,直线检测

Canny 边缘检测结果,只是一些类似边缘的pixels,利用霍夫变换求出其中可能存在的直线。霍夫变换的原理:将该点映射到霍夫空间(r θ坐标系),该空间的每条线都代表过图像空间中一点的所有直线集合,求空间里线与线的交点,即为图像空间的过某几个点的直线。霍夫变换的结果是多条直线的坐标[ [x1,y1,x2,y2], [x x y y]...]

可以看到,霍夫变换的结果中线可能是不连续的,是由多条线组成的。

def hough_lines(img,rho=6,theta=np.pi/180,threshold=160,
                    min_line_len=40,max_line_gap=25):
        """
        将canny边缘检测后的像素点连接成线,并调用划线函数,返回画线的图片
        hough transform原理:转换到 hough space,r,θ极坐标,正弦曲线,
        每条线代表个image space中过一点的所有线,
        lines的交点代表共线,找到交点再返回到image space空间
        lines:[[x1,y1,x2,y2],[x x y y]...]
        """
        lines=cv2.HoughLinesP(img,rho,theta,threshold, np.array([]), 
                              minLineLength=min_line_len, maxLineGap=max_line_gap)
        return lines
    
def draw_lines(img,lines,color=[255,0,0],thickness=3):
        """
        生成一个zeros图划线,并与原图混合
        """
        if lines is None:
            return
        img=np.copy(img)
        #生成待划线的图,zeros,addweighted混合的时候,0值不会显示
        img_channels=img.shape[2]
        line_img=np.zeros((img.shape[0],img.shape[1],img_channels),dtype=np.uint8)
        for line in lines:
            for x1,y1,x2,y2 in line:
                cv2.line(line_img,(x1,y1),(x2,y2),color,thickness)
        #将划线图与原图合并
        #cv2.addWeighted(initial_img, α, img, β , γ) 
        #output: initial_img * α + img * β + γ
        img=cv2.addWeighted(img, 0.8, line_img, 1.0, 0.0) #叠加的两幅图片尺寸和channel需要一致
        return img

lines=hough_lines(ROI_img)
line_img=draw_lines(image,lines)
plt.imshow(line_img)

以下是一个简单的基于OpenCV的C++实现车道线检测的代码示例: ``` #include <iostream> #include <opencv2/opencv.hpp> using namespace std; using namespace cv; int main() { // 读入图像 Mat img = imread("lane.jpg"); // 转换为灰度图像 Mat gray; cvtColor(img, gray, COLOR_BGR2GRAY); // 使用高斯滤波去除噪声 Mat blur; GaussianBlur(gray, blur, Size(5, 5), 0); // 使用Canny算子进行边缘检测 Mat edges; Canny(blur, edges, 50, 150); // 定义ROI(感兴趣区域) Mat roi; Point points[4] = {Point(0, img.rows), Point(img.cols / 2, img.rows / 2), Point(img.cols / 2, img.rows / 2), Point(img.cols, img.rows)}; Mat mask = Mat::zeros(img.size(), CV_8UC1); fillConvexPoly(mask, points, 4, Scalar(255)); bitwise_and(edges, mask, roi); // 使用霍夫变换进行直线检测 vector<Vec4i> lines; HoughLinesP(roi, lines, 1, CV_PI / 180, 50, 50, 10); // 绘制检测到的直线 for (size_t i = 0; i < lines.size(); i++) { line(img, Point(lines[i][0], lines[i][1]), Point(lines[i][2], lines[i][3]), Scalar(0, 0, 255), 2); } // 显示结果 imshow("Lane Detection", img); waitKey(0); return 0; } ``` 这个代码实现了以下步骤: 1. 读入图像,并将其转换为灰度图像。 2. 使用高斯滤波器去除噪声。 3. 使用Canny算子检测边缘。 4. 定义ROI(感兴趣区域),并应用到边缘图像上。 5. 使用霍夫变换进行直线检测。 6. 绘制检测到的直线。 7. 显示结果。 请注意,这只是一个基本示例,实际上车道线检测是一个相当复杂的任务,需要对多个因素进行考虑,包括照明条件、道路表面状况、车速等。此外,还可以使用更高级的技术,如深度学习等,来改进车道线检测的准确性和鲁棒性。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值