輔助駕駛 | 簡單車道線識別

2021-02-21 碼出名企路

原文連結

https://zhuanlan.zhihu.com/p/53172090

本文將介紹如何利用Opencv,對簡單場景下的車道線進行離線識別。梳理整個識別過程的邏輯,並對過程中使用的相關知識點進行介紹。正文中使用C++實現,在文末也會附上利用python實現的代碼,讀者完全可以依照本文復現該項目。

整體思路

簡單的車道線識別可由以下幾步完成:

讀取視頻-灰度變換-高斯濾波-邊緣檢測-感興趣區域檢測-霍夫變換-車道線擬合-圖片混合

在下面的內容中,將按照以上步驟一步步實現,最終實現對車道線的檢測。大家都知道,視頻是由一幀幀的圖像組成,因此對視頻的車道線檢測本質上是對圖像的車道線進行檢測。

實現單張圖片車道線檢測

導入包含的庫文件

#include <iostream>
#include <opencv2/opencv.hpp>
#include<vector>
#include<numeric>
#include<string>
using namespace std;
using namespace cv;

讀取圖片

   //*************reading image******************
    Mat image;
    image = imread("/home/project1/test1.jpg");
    if(image.empty()){
        cout <<"reading error"<<endl;
        return -1;
    } 

在Opencv中,圖像的數據格式是Mat,相當於一個矩陣.這個步驟雖然簡單,但有兩點需要注意:一是imread後面的文件地址,在linux和windows下斜線的方向可能不一樣,需要注意,最好是使用全局路徑,不容易出錯; 二是在讀入圖像後,最好加一段image.empty()來判斷是否正確導入了圖片.

灰度變換

 //***************gray image*******************
    Mat image_gray;
    cvtColor(image,image_gray, CV_BGR2GRAY);

使用Opencv中的cvtColor函數可以直接將RGB的圖像轉換成灰度圖.這個函數有三個輸入參數,分別是:輸入圖像,輸出圖像,格式轉化類別.

高斯濾波

 Mat image_gau;
 GaussianBlur(image_gray, image_gau, Size(5,5),0,0); 

使用高斯濾波,也叫高斯模糊,能夠剔除原圖像中的一些噪點.比如,如果不使用高斯濾波,直接處理原圖,圖中一些無關緊要的特徵就無法避開,影響後面的處理.相反,通過高斯模糊之後,一些不那麼清晰的噪點就被刪除掉了.

函數GaussianBlur的四個參數分別為:輸入圖像,輸出圖像,高斯內核,高斯內核在X方向的標準偏差,高斯內核在Y方向上的標準偏差.

其中,高斯內核是由width和height兩個維度構成,這兩個維度可以使用不同的值,但是必須是正奇數或者為0; 高斯內核在XY兩個方向上的標準偏差,通常設置為0(具體如何調參數暫未研究).

邊緣檢測

//******************canny*********************
Mat image_canny;
Canny(image_gau, image_canny,100, 200, 3);

Canny邊緣檢測函數共有5個輸入參數,分別為:輸入圖像、輸出圖像、閾值1、閾值2、sobel算子的孔徑參數.

閾值:低於閾值1的像素點會被認為不是邊緣,高於閾值2的像素點會被認為是邊緣,在閾值1和閾值2之間的像素點,如果與高於閾值2的像素點相鄰,則認為是邊緣,否則認為不是邊緣.soble算子孔徑參數,一般默認為3,即表示為一個3*3的矩陣.sobel算子與高斯拉普拉斯算子都是常用的邊緣算子.

ROI感興趣區域

    Mat dstImg;
    Mat mask = Mat::zeros(image_canny.size(), CV_8UC1);
    Point PointArray[4];
    PointArray[0] = Point(0, mask.rows);
    PointArray[1] = Point(400,330);
    PointArray[2] = Point(570,330);
    PointArray[3] = Point(mask.cols, mask.rows);
    fillConvexPoly(mask,PointArray,4,Scalar(255));
    bitwise_and(mask,image_canny,dstImg);

從上圖可以看出,通過邊緣檢測得到的圖片包含了很多環境信息,這些是我們不感興趣的,需要提取我們需要都得信息.觀察原圖可知,車道先一般位於圖片下方的一個梯形區域,手動設定4個點,組成梯形區域的四個頂點.利用fillConvexPoly函數可以畫出多邊形,這個函數共有4個參數:空圖(大小與原圖一致)、頂點信息、多邊形的邊數、線條顏色.

將梯形掩模區域與原圖進行bitwise_and操作,可以只得到感興趣區域內的邊緣檢測圖,從途中可以看出只有車道線信息.bitwise_and函數是將兩張圖片做「與」操作,共有3個輸入參數,分別是:掩模圖、原圖、輸出圖.需要注意的是,三張圖的大小和顏色通道數量.

霍夫變換

通過上面的操作,得到的是組成車道線的一些像素點,但這些點都是一個個獨立的像素點,沒有連成線。霍夫變換可以通過像素點找到圖中的直線。霍夫變換有3種,標準霍夫變換,多尺度霍夫變換和累計概率霍夫變換,前兩種使用HoughLines函數,最後一種使用HoughLines函數實現。累計霍夫變換的執行效率更高,所以一般更多的傾向使用累計概率霍夫變換.

霍夫變換將在迪卡爾坐標系下的線條轉換到極坐標系下,迪卡爾坐標下通過一個點的所有直線的集合在極坐標系下是一條正弦曲線.正弦曲線的交點,表示這些曲線代表的點在同一條直線上.霍夫變換就通過找這些交點,確定哪些像素點是在同一條直線上.

vector<Vec4i> lines; //包含4個int類型的結構體
int rho = 1;
double theta = CV_PI/180;
int threshold = 30;
int min_line_len = 30;
int max_line_gap = 20;
HoughLinesP(dstImg,lines,rho,theta,threshold,min_line_len,max_line_gap);

Opencv中HoughLinesP函數共有7個參數:輸入原圖像(單通道二進位圖像,canny的結果),輸出線的兩個端點(x1, y1, x2, y2),rho直線搜索時的步長(單位為像素),theta直線搜索時的角度步長單位為弧度,threshold多少個點交在一起才認為是一條直線(int),min_linelen最低線段長度默認為0,max_line_gap兩條直線並列多遠的時候認為是兩條(默認為0).

車道線擬合

//簡單的車道線擬合 
 Mat image_draw = Mat::zeros(image_canny.size(),CV_8UC3);

    for(size_t i= 0;i<lines.size();i++){
        Vec4i L = lines[i];
        line(image_draw, Point(L[0],L[1]),Point(L[2],L[3]),Scalar(0,0,255),3,LINE_AA);
    }

最簡單的車道線擬合,直接將霍夫變換找到的直線畫出來,對於連續的線段,沒有影響,但是如果車道線有虛線,就會出現不連續的情況.

如下圖

為了解決虛線之間不連續的問題,需要對霍夫變換得到的線段進行處理。一張圖片通過霍夫變換得到的線段有很多,在這裡可以根據斜率分為兩類,左車道線和右車道線。在分類的過程中需要注意的是圖像的坐標系:左上角為原點,x正方向朝右側,y的正向朝下。

霍夫變換得到的lines中是兩個點,通過兩個點,可以計算得到斜率和截距。對一張圖片中,同一側的斜率和截距進行平均,然後直接利用平均後的參數可以直接畫出一條完整的直線

/***************draw line update********************************
    Mat image_draw = Mat::zeros(image_canny.size(),CV_8UC3);
    vector<int> right_x, right_y, left_x, left_y;
    double slope_right_sum;
    double b_right_sum ;
    double slope_left_sum ;
    double b_left_sum ;
    double slope_right_mean;
    double slope_left_mean;
    double b_right_mean;
    double b_left_mean;
    vector<double> slope_right, slope_left,b_right, b_left;
    for(size_t i= 0;i<lines.size();i++){
        Vec4i L;
        double slope,b;
        L = lines[i];
        slope = (L[3]-L[1])*1.0/(L[2]-L[0]);
        b = L[1]-L[0]*slope;

        if (slope >=0.2){
            slope_right.push_back(slope);
            b_right.push_back(b);
            //right_x.push_back((L[0],L[2]));
            //right_y.push_back((L[1],L[3]));

          }
        else{
            slope_left.push_back(slope);
            b_left.push_back(b);
            // left_x.push_back((L[0],L[2]));
            // right_y.push_back((L(1),L[3]));

            }
        }
//accumulate 實現vector內值的累加,輸出格式與最後一個參數的數據格式一致。
    slope_right_sum = accumulate(slope_right.begin(), slope_right.end(),0.0);
    b_right_sum = accumulate(b_right.begin(), b_right.end(),0.0);
    slope_left_sum = accumulate(slope_left.begin(),slope_left.end(),0.0);
    b_left_sum = accumulate(b_left.begin(),b_left.end(),0.0);
    slope_right_mean = slope_right_sum/slope_right.size();
    slope_left_mean = slope_left_sum/slope_left.size();
    b_right_mean = b_right_sum/b_right.size();
    b_left_mean = b_left_sum/b_left.size();
    cout <<"slope_right: "<<slope_right_sum<<endl;
    double x1r = 550;
    double x2r = 850;
    double x1l = 120;
    double x2l = 425;
    int y1r = slope_right_mean * x1r + b_right_mean;
    int y2r = slope_right_mean * x2r + b_right_mean;
    int y1l = slope_left_mean * x1l + b_left_mean;
    int y2l = slope_left_mean * x2l + b_left_mean;
    line(image_draw, Point(x1r,y1r),Point(x2r,y2r),Scalar(0,0,255),5,LINE_AA);
    line(image_draw, Point(x1l,y1l),Point(x2l,y2l),Scalar(0,0,255),5,LINE_AA);

圖像混合

將畫出來的直線疊加到原圖像上,可以使用addWeighted函數,實現圖像加權疊加.addWeighted函數共有6個參數,分別為:原圖1、圖1的透明度、原圖2、圖2的透明度、加權值(一般設置為0)、輸出圖.

//*************mix two image*************************
    Mat image_mix = Mat::zeros(image_canny.size(),CV_8UC3);
    addWeighted(image_draw,1,image,1,0.0,image_mix);

通過以上9個步驟,我們完成了對與單張圖片的車道線檢測。

對視頻的車道線檢測

將2中9個步驟重構成一個類image_process

重構的image_process具有兩個成員變量:原圖和結果圖,一個成員函數:對圖像的車道線識別。另外還有一個構造函數和一個析構函數。具體代碼如下:

//image_process.h
#ifndef PROJECT1_IMAGE_PROCESS_H
#define PROJECT1_IMAGE_PROCESS_H
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

class image_process {
public:
    Mat image_src;
    Mat image_dst;
    image_process(Mat image);

    Mat process();
    ~image_process();

};

//process_image.cpp
#include "image_process.h"
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

//構造函數
image_process::image_process(Mat image):image_src(image){}
//成員函數
Mat image_process::process(){
    //*************reading image******************
    Mat image;
    image = image_src ;
    if(image.empty()){
        cout <<"reading error"<<endl;
    }

    //***************gray image*******************
    Mat image_gray;
    cvtColor(image,image_gray, CV_BGR2GRAY);

    //************gaussian smoothing**************
    Mat image_gau;
    GaussianBlur(image_gray, image_gau, Size(5,5),0,0); 

    //******************canny*********************
    Mat image_canny;
    Canny(image_gau, image_canny,100, 200, 3);

    //**************interesting aera*************
    Mat dstImg;
    Mat mask = Mat::zeros(image_canny.size(), CV_8UC1);
    Point PointArray[4];
    PointArray[0] = Point(0, mask.rows);
    PointArray[1] = Point(400,330);
    PointArray[2] = Point(570,330);
    PointArray[3] = Point(mask.cols, mask.rows);
    fillConvexPoly(mask,PointArray,4,Scalar(255));
    bitwise_and(mask,image_canny,dstImg);

//************************houghline*******************
    vector<Vec4i> lines;
    int rho = 1;
    double theta = CV_PI/180;
    int threshold = 30;
    int min_line_len = 100;
    int max_line_gap = 100;
    HoughLinesP(dstImg,lines,rho,theta,threshold,min_line_len,max_line_gap);
    //cout<<lines[1]<<endl;
//***************draw line update********************************
    Mat image_draw = Mat::zeros(image_canny.size(),CV_8UC3);
    vector<int> right_x, right_y, left_x, left_y;
    double slope_right_sum;
    double b_right_sum ;
    double slope_left_sum ;
    double b_left_sum ;
    double slope_right_mean;
    double slope_left_mean;
    double b_right_mean;
    double b_left_mean;
    vector<double> slope_right, slope_left,b_right, b_left;
    for(size_t i= 0;i<lines.size();i++){
        Vec4i L;
        double slope,b;
        L = lines[i];
        slope = (L[3]-L[1])*1.0/(L[2]-L[0]);
        b = L[1]-L[0]*slope;

        if (slope >=0.2){
            slope_right.push_back(slope);
            b_right.push_back(b);
            //right_x.push_back((L[0],L[2]));
            //right_y.push_back((L[1],L[3]));

          }
        else{
            slope_left.push_back(slope);
            b_left.push_back(b);
            // left_x.push_back((L[0],L[2]));
            // right_y.push_back((L(1),L[3]));

            }


        }
    slope_right_sum = accumulate(slope_right.begin(), slope_right.end(),0.0);
    b_right_sum = accumulate(b_right.begin(), b_right.end(),0.0);
    slope_left_sum = accumulate(slope_left.begin(),slope_left.end(),0.0);
    b_left_sum = accumulate(b_left.begin(),b_left.end(),0.0);
    slope_right_mean = slope_right_sum/slope_right.size();
    slope_left_mean = slope_left_sum/slope_left.size();
    b_right_mean = b_right_sum/b_right.size();
    b_left_mean = b_left_sum/b_left.size();
    cout <<"slope_right: "<<slope_right_sum<<endl;
       double x1r = 550;
       double x2r = 850;
       double x1l = 120;
       double x2l = 425;
       int y1r = slope_right_mean * x1r + b_right_mean;
       int y2r = slope_right_mean * x2r + b_right_mean;
       int y1l = slope_left_mean * x1l + b_left_mean;
       int y2l = slope_left_mean * x2l + b_left_mean;
      line(image_draw, Point(x1r,y1r),Point(x2r,y2r),Scalar(0,0,255),5,LINE_AA);
      line(image_draw, Point(x1l,y1l),Point(x2l,y2l),Scalar(0,0,255),5,LINE_AA);
//*************mix two image*************************
    Mat image_mix = Mat::zeros(image_canny.size(),CV_8UC3);
    addWeighted(image_draw,1,image,1,0.0,image_mix);
//**************out put****************************
    return image_mix;
}
//析構函數
image_process::~image_process() {}

主函數

可以直接使用capture函數讀取視頻,然後將視頻中的每一幀圖像傳遞給frame。通過構造函數將frame傳遞給處理單張圖片的類,然後調用成員函數進行處理,最後顯示。

waitKey()中.如果沒有參數,代表窗口會一直等待直到我們對窗口進行操作.有參數時,等待固定的時間後自動關閉.例如waitKey(30)窗口等待30ms後關閉,接著顯示下一幀的圖像.

#include <iostream>
#include <opencv2/opencv.hpp>
#include<vector>
#include <opencv2/highgui/highgui.hpp>
#include"image_process.h"
#include<string>
using namespace std;
using namespace cv;
int main(){
    Mat image;
    Mat image_result;
    VideoCapture capture("/home/solidYellowLeft.mp4");
    Mat frame;
    if(!capture.isOpened()) {
        cout << "can not open video" << endl;
        return -1;
    }
    while(capture.isOpened()){
        capture>>frame;
        image_process image2(frame);
        Mat image_result2;
        image_result2 = image2.process();
        imshow("result_video",image_result2);
        waitKey(30);
    }
}

python實現:

import math

def grayscale(img):
    """Applies the Grayscale transform
    This will return an image with only one color channel
    but NOTE: to see the returned image as grayscale
    (assuming your grayscaled image is called 'gray')
    you should call plt.imshow(gray, cmap='gray')"""
    
    return cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
    # Or use BGR2GRAY if you read an image with cv2.imread()
    # return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
def canny(img, low_threshold, high_threshold):
    """Applies the Canny transform"""
    return cv2.Canny(img, low_threshold, high_threshold)

def gaussian_blur(img, kernel_size):
    """Applies a Gaussian Noise kernel"""
    return cv2.GaussianBlur(img, (kernel_size, kernel_size), 0)

def region_of_interest(img, vertices):
    """
    Applies an image mask.
    
    Only keeps the region of the image defined by the polygon
    formed from `vertices`. The rest of the image is set to black.
    """
    #defining a blank mask to start with
    mask = np.zeros_like(img)   
    
    #defining a 3 channel or 1 channel color to fill the mask with depending on the input image
    if len(img.shape) > 2:
        channel_count = img.shape[2]  # i.e. 3 or 4 depending on your image
        ignore_mask_color = (255,) * channel_count
    else:
        ignore_mask_color = 255
        
    #filling pixels inside the polygon defined by "vertices" with the fill color    
    cv2.fillPoly(mask, vertices, ignore_mask_color)
    
    #returning the image only where mask pixels are nonzero
    masked_image = cv2.bitwise_and(img, mask)
    return masked_image


def draw_lines(img, lines, color=[255, 0, 0], thickness=8):
    """
    NOTE: this is the function you might want to use as a starting point once you want to 
    average/extrapolate the line segments you detect to map out the full
    extent of the lane (going from the result shown in raw-lines-example.mp4
    to that shown in P1_example.mp4).  
    
    Think about things like separating line segments by their 
    slope ((y2-y1)/(x2-x1)) to decide which segments are part of the left
    line vs. the right line.  Then, you can average the position of each of 
    the lines and extrapolate to the top and bottom of the lane.
    
    This function draws `lines` with `color` and `thickness`.    
    Lines are drawn on the image inplace (mutates the image).
    If you want to make the lines semi-transparent, think about combining
    this function with the weighted_img() function below
    """
#     for line in lines:
#         for x1,y1,x2,y2 in line:
#             cv2.line(img, (x1, y1), (x2, y2), color, thickness)
    right_x =[]
    right_y =[] 
    left_x =[]
    left_y =[]
    left_slope =[]
    right_slope =[]
    for line in lines:
       for x1, y1, x2, y2 in line:
            slope = ((y2-y1)/(x2-x1))
            if slope >=0.2:
                #right_slope.extend(int(slope))
                right_x.extend((x1, x2))
                right_y.extend((y1, y2))
             
            elif slope <= -0.2:
                #left_slope.extend(int(slope))
                left_x.extend((x1, x2))
                left_y.extend((y1, y2))    
    right_fit= np.polyfit(right_x, right_y, 1)
    right_line = np.poly1d(right_fit)
    x1R = 550
    y1R = int(right_line(x1R))
    x2R = 850
    y2R = int(right_line(x2R))   
    cv2.line(img, (x1R, y1R), (x2R, y2R), color, thickness)  
    left_fit= np.polyfit(left_x, left_y, 1)
    left_line = np.poly1d(left_fit)
    x1L = 120
    y1L = int(left_line(x1L))
    x2L = 425
    y2L = int(left_line(x2L))
    cv2.line(img, (x1L, y1L), (x2L, y2L), color, thickness)


def hough_lines(img, rho, theta, threshold, min_line_len, max_line_gap):
    """
    `img` should be the output of a Canny transform.
        
    Returns an image with hough lines drawn.
    """
    lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]), minLineLength=min_line_len, maxLineGap=max_line_gap)
    line_img = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.uint8)
    draw_lines(line_img, lines)
    return line_img

# Python 3 has support for cool math symbols.

def weighted_img(img, initial_img, α=0.8, β=1., λ=0.):
    """
    `img` is the output of the hough_lines(), An image with lines drawn on it.
    Should be a blank image (all black) with lines drawn on it.
    
    `initial_img` should be the image before any processing.
    
    The result image is computed as follows:
    
    initial_img * α + img * β + λ
    NOTE: initial_img and img must be the same shape!
    """
    return cv2.addWeighted(initial_img, α, img, β, λ)

def pipeline(input_image):
    
    image = input_image
    

    import os
    os.listdir("test_images/")
    gray=grayscale(image)
    # Gaussian smoothing
    kernel_size = 5
    gau=gaussian_blur(gray,kernel_size)

    # Canny
    low_threshold = 100
    high_threshold =200
    edges=canny(gau, low_threshold, high_threshold)

    imshape = image.shape
    vertices = np.array([[(0,imshape[0]),(400, 330), (570, 330), (imshape[1],imshape[0])]], dtype=np.int32)
    region=region_of_interest(edges, vertices)

    rho = 1 # distance resolution in pixels of the Hough grid
    theta = np.pi/180 # angular resolution in radians of the Hough grid
    threshold = 30    # minimum number of votes (intersections in Hough grid cell)
    min_line_len = 20 #minimum number of pixels making up a line
    max_line_gap = 20
    line_img=hough_lines(region, rho, theta, threshold, min_line_len, max_line_gap)
    line_last=weighted_img(line_img, image, α=0.8, β=1., λ=0.)
    return line_last

from moviepy.editor import VideoFileClip
from IPython.display import HTML
def process_image(image):
  # NOTE: The output you return should be a color image (3 channel) for processing video below
  # TODO: put your pipeline here,
  # you should return the final output (image where lines are drawn on lanes)
  result = pipeline(image)

  return result
white_output = 'test_videos_output/solidWhiteRight.mp4'
## To speed up the testing process you may want to try your pipeline on a shorter subclip of the video
## To do so add .subclip(start_second,end_second) to the end of the line below
## Where start_second and end_second are integer values representing the start and end of the subclip
## You may also uncomment the following line for a subclip of the first 5 seconds
#clip1 = VideoFileClip("test_videos/solidWhiteRight.mp4").subclip(0,5)
clip1 = VideoFileClip("test_videos/solidWhiteRight.mp4")
white_clip = clip1.fl_image(process_image) #NOTE: this function expects color images!!
%time white_clip.write_videofile(white_output, audio=False)

相關焦點

  • 無人駕駛的圖像識別之車道線檢測(二)
    前言在《圖像識別之初級車道線檢測(1)》,我對計算機視覺技術的一些基本理論和OpenCV庫的使用進行了分享。這些技術包括圖像的灰度處理、邊緣提取算法、霍夫變換直線檢測算法以及數據的後處理方法。應用這些技術後,可以將圖像中近似直線的車道線檢測出來。檢測的效果如下圖紅線所示。
  • 說的是BMW自動駕駛輔助系統Pro!
    寶馬自動駕駛技術獲專業蓋章好評啦——日前,在Euro NCAP(歐洲新車安全評鑑協會)駕駛輔助測評中,全新BMW 3系搭載的自動駕駛輔助系統Pro榮獲 「VERY GOOD」評級。專業測評機構的肯定再次證明了該項技術的成熟以及卓越的客戶體驗。
  • 聊聊LKA車道保持系統
    每周還是聊一些好玩的東西,在跑在前面以前,我們需要從車輛在行駛過程中橫向和縱向,以及橫向和總線結合來組合成完善的高階輔助駕駛系統。
  • 使用霍夫變換檢測車道線
    車道線檢測是自動駕駛汽車的重要組成部分之一,有很多方法可以做到這一點。本文,我們將使用最簡單的霍夫變換方法。我們可能會想,為什麼我們不把這些線添加到真實圖像上,而是黑色圖像上。因為原始圖像有點太亮了,所以如果我們把它調暗一點,讓車道線看得更清楚一點就好了(是的,我們知道,這不是大不了的,但找到改進算法的方法總是很好的)。
  • 怎樣的自動駕駛輔助系統,才能獲得你的信任?
    例如近幾年來被大肆宣傳的自動駕駛輔助技術,目前絕大多數廠商都對外宣告它們的技術等級已達到L2+,即允許駕駛員雙腳離開控制踏板、雙手脫離方向盤,車輛在一定程度上實現自動駕駛。但是,它們的名字都在原來「自動駕駛」的基礎上悄悄地加上了「輔助」兩個字,目的相當明顯,就是把責任與駕駛員捆綁在一起,發生任何事件與智能化技術無關。事故發生時自動駕駛系統處於開啟狀態,不要問,問就是駕駛員的責任。
  • 道路駕駛中如何預判左右車道路況,兩種場景下的不同應對策略技巧,新手上路需要掌握
    ▲識別二維碼訂閱觀看本文章【視頻】版新手開車在道路駕駛中,不但要觀察好自己行駛車道的路況,還要對左右車道近距離的車輛行駛動態要有一個觀察,主要是預判他們的行駛動向對你的正常行駛是否會產生影響,就此你應該採取那些措施來應對
  • 車道線檢測:SCNN(一)
    這裡(a)是訓練的網絡,(b)是用網絡進行預測的流程,需要注意的是,(b)中右側輸出了四個數值,這四個數分別對應四條車道線的概率,0.99就是有車道線,0.02就是沒有車道線,所以圖中就顯示了三條車道線,至於為啥是四條,這就屬於作者設置的一個先驗信息了
  • 高德詳解:如何將車道級導航植入手機?
    通常低等級智能駕駛搭載的傳統汽車電氣架構無法提供更多的算力資源,而高等級智能駕駛使用的集中計算單元可以提供的算力資源更豐富。除此之外還有許多與實際應用相關的需求,比如輸出定位結果的時間穩定性,定位能夠覆蓋的場景範圍等。總結一下,車道級導航需要的核心能力是識別當前車道,這一般要求定位精度小於1米,同時作為導航應用,需要在傳統導航的基礎上提高道路匹配的準確率。
  • 基於閾值的車道標記
    因此,最好對未變形的閾值圖像執行透視變換,以鳥瞰車道線,以便以後可以準確地完成通過它們的曲線擬合。下一步是沿車道線擬合曲線。線查找方法:直方圖中的峰在對道路圖像應用校準,閾值和透視變換後,大家應該擁有一個二進位圖像,其中車道線清晰可見。但是仍然需要明確確定哪些像素是線條的一部分,哪些像素屬於左線條,哪些像素屬於右線條。對此圖像繪製二進位激活在何處發生的直方圖是一種可能的解決方案。
  • 這些車都能實現半自動駕駛了,無人駕駛還會遠嗎?!
    通用也對L1-5進行了解析,大家可以看一下:L1是輔助駕駛,解放雙腳,帶有自適應巡航、緊急制動功能車型均可為代表車型。L2是部分自動駕駛,解放雙手。奔馳的自動駕駛系統包括主動車道變換輔助功能、主動車道保持輔助功能、主動限速輔助功能、交通標誌協助功能、主動距離輔助巡航功能、主動緊急停車輔助功能、主動制動輔助功能、迴避轉向輔助功能、主動盲點輔助功能、主動泊車輔助功能和遠程停車輔助功能等一系列的功能。可以看出奔馳的這個自動駕駛技術算是比較成熟。
  • 【聚焦ADAS】自動駕駛汽車最大的賣點是「安全」?
    現代Ioniq配備了ADAS功能,如自適應巡航控制、自動緊急剎車和車道偏離警告;豐田普銳斯配備了ADAS行人檢測系統、自適應前燈、避碰系統、自適應巡航控制、智能停車輔助和車道偏離警告。剛剛上市的廣汽新能源Aion LX為全球首款量產交付L3級自動駕駛能力的車型,包含HWA高速變道輔助駕駛系統、APA融合泊車等功能,硬體層面配備了全球最頂級的"高精雷達+Mobileye Q4攝像頭"雙探測硬體組合,可以探測半徑200米的探測距離。
  • 自動駕駛感知技術的實踐與探索
    顯而易見,第一個是車道線,我們知道車道線才能知道怎麼開;然後我們還需要知道紅綠燈,以及非常重要一點,就是動態障礙物(如前面有什麼車輛),這是非常重要的;還有就是行人(對於城區的自動駕駛是非常關鍵的)。對於智加的重卡自動駕駛中,最重要的還是車道線和動態障礙物,所以這兩方面會重點進行介紹。1.
  • 車道線檢測技術分析
    《Unifying Lane-Sensitive Architecture Search and Adaptive Point Blending》:採用CNN的方式,通過多尺度融合和輸出的方式提高定位精度,最後採用一種類似於NMS方法,將低層輸出中位置精度回歸較高的點逐步向高層輸出替換,得到最後融合優化的車道線點輸出。3.
  • 劃時代的VR設備終於問世 ,我的駕駛體驗何時也能擁有遊戲一樣的快感?
    頭顯外部設置有4個攝像頭,可以通過攝像頭看到現實世界,此外,手柄上還設置有紅外LED,Quest可以通過攝像頭來識別手柄上的紅外LED,從而識別玩家的手部運動。  有了這些高科技硬體的加持,歐拉好貓的智能巡航系統和交通擁堵輔助系統就能更好地發揮作用。經過多重測試、高度靈敏的ACC自適應巡航系統、ICA智能巡航輔助、LCK車道居中保持和併線輔助燈功能就能更好地幫助你應對各種路況。
  • 基於 EPS 的車道保持輔助系統設計
    基於電動助力轉向的車道保持系統[J]. 汽車工程, 2013, 35(6): 526-531[3] 於立嬌. 基於 EPS的車道保持輔助控制算法設計與實驗驗證[D]. 長春: 吉林大學, 2016[4] Kim W, Son Y S, Chung C C.
  • 斯巴魯EyeSight駕駛輔助系統
    時隔27年,斯巴魯EyeSight駕駛輔助系統終於公布於世,讓汽車真正擁有人類的視角。作為斯巴魯全方位安全中一項十分先進的預防安全系統,它可以像人眼一樣監測到行車中的危險。       通過風擋玻璃後方的兩個攝像頭,EyeSight駕駛輔助系統可以識別出車輛、行人、自行車、障礙物,並對其進行預判。
  • 再也不怕睡到床邊上了 福特跨領域技術「車道保持床」了解下
    現在的汽車可以說是更加的智能化,所配備的各項駕駛輔助技術與駕駛者密不可分,目的是為了汽車有更好的穩定性及保證駕乘人員的安全,像ACC
  • 知薦 | 基於 EPS 的車道保持輔助系統設計
    基於電動助力轉向的車道保持系統[J]. 汽車工程, 2013, 35(6): 526-531[3] 於立嬌. 基於 EPS的車道保持輔助控制算法設計與實驗驗證[D]. 長春: 吉林大學, 2016[4] Kim W, Son Y S, Chung C C.
  • 基於駕駛腦的智能駕駛車輛硬體平臺架構
    自20世紀90年代開始,日本交通部門的高級駕駛輔助公路系統研究協會(Advanced Cruise-Assist Highway System Research Asso-ciation,AHSRA)發起了高級安全車輛(advanced safety vehicle,ASV)項目,以每5年為一個階段開展無人駕駛技術研究。
  • 卡羅拉自動駕駛——「0-180全速域」解放感
    而消費者對於這項全新技術同樣趨之若鶩,但通常而言,當前市面上普遍的L2級自動駕駛技術都出現在30萬元以上的豪華車型中,對於廣大家用車消費者來說,距離依然有些遙遠。2021款卡羅拉全系標配了L2級自動駕駛核心功能,讓很多消費者第一次感受到自動駕駛這一技術紅利。不到12萬元的起售價格,絕大多數工薪家庭都可輕鬆入手,真正做到了技術的普及。