1. 程式人生 > >優達學城無人駕駛工程師——P1尋找車道線

優達學城無人駕駛工程師——P1尋找車道線

這次介紹的是優達學城的無人駕駛工程師的P1專案,利用車的前攝像頭來識別當前車道的左右兩邊兩條的車道線。測試圖片和視訊在文章最後的連結裡。

一開始先倒包

#importing some useful packages
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
import cv2
%matplotlib inline

開始讀取圖片

#reading in an image
image = mpimg.imread('test_images/solidWhiteRight.jpg')

#printing out some stats and plotting
print('This image is:', type(image), 'with dimensions:', image.shape)
plt.imshow(image)  # if you wanted to show a single color channel image called 'gray', for example, call as plt.imshow(gray, cmap='gray')


下面是一些輔助函式(選用,可以根據自己想法新增刪除其他方法)

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"""
    #這個是用於邊緣檢測的  需要處理的原影象,該影象必須為單通道的灰度圖
    #其中較大的閾值2用於檢測影象中明顯的邊緣,但一般情況下檢測的效果不會那麼完美,
    #邊緣檢測出來是斷斷續續的。
    #所以這時候用較小的第一個閾值用於將這些間斷的邊緣連線起來。
    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.
    `vertices` should be a numpy array of integer points.
    """
    #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=2):
    """
    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)
            
    #下面是高階的draw_lines()的寫法,供參考,我是無法理解,太複雜了
#     imshape = img.shape 
    
#     slope_left=0
#     slope_right=0
#     leftx=0
#     lefty=0
#     rightx=0
#     righty=0
#     i=0
#     j=0
    
    
#     for line in lines:
#         for x1,y1,x2,y2 in line:
#             slope = (y2-y1)/(x2-x1)
#             if slope >0.1: #Left lane and not a straight line
#                 # Add all values of slope and average position of a line
#                 slope_left += slope 
#                 leftx += (x1+x2)/2
#                 lefty += (y1+y2)/2
#                 i+= 1
#             elif slope < -0.2: # Right lane and not a straight line
#                 # Add all values of slope and average position of a line
#                 slope_right += slope
#                 rightx += (x1+x2)/2
#                 righty += (y1+y2)/2
#                 j+= 1
#     # Left lane - Average across all slope and intercepts
#     if i>0: # If left lane is detected
#         avg_slope_left = slope_left/i
#         avg_leftx = leftx/i
#         avg_lefty = lefty/i
#         # Calculate bottom x and top x assuming fixed positions for corresponding y
#         xb_l = int(((int(0.97*imshape[0])-avg_lefty)/avg_slope_left) + avg_leftx)
#         xt_l = int(((int(0.61*imshape[0])-avg_lefty)/avg_slope_left)+ avg_leftx)

#     else: # If Left lane is not detected - best guess positions of bottom x and top x
#         xb_l = int(0.21*imshape[1])
#         xt_l = int(0.43*imshape[1])
    
#     # Draw a line
#     cv2.line(img, (xt_l, int(0.61*imshape[0])), (xb_l, int(0.97*imshape[0])), color, thickness)
    
#     #Right lane - Average across all slope and intercepts
#     if j>0: # If right lane is detected
#         avg_slope_right = slope_right/j
#         avg_rightx = rightx/j
#         avg_righty = righty/j
#         # Calculate bottom x and top x assuming fixed positions for corresponding y
#         xb_r = int(((int(0.97*imshape[0])-avg_righty)/avg_slope_right) + avg_rightx)
#         xt_r = int(((int(0.61*imshape[0])-avg_righty)/avg_slope_right)+ avg_rightx)
    
#     else: # If right lane is not detected - best guess positions of bottom x and top x
#         xb_r = int(0.89*imshape[1])
#         xt_r = int(0.53*imshape[1])
    
#     # Draw a line    
#     cv2.line(img, (xt_r, int(0.61*imshape[0])), (xb_r, int(0.97*imshape[0])), 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)
    
    
    #霍夫變換線 用來測試直線的
    #函式cv2.HoughLinesP()是一種概率直線檢測
    #我們知道,原理上講hough變換是一個耗時耗力的演算法,尤其是每一個點計算,
    #即使經過了canny轉換了有的時候點的個數依然是龐大的,這個時候我們採取一種概率挑選機制,
    #不是所有的點都計算,而是隨機的選取一些個點來計算,相當於降取樣了
    #這樣的話我們的閾值設定上也要降低一些。在引數輸入輸出上,輸入不過多了兩個引數:
    #minLineLengh(線的最短長度,比這個短的都被忽略)和MaxLineCap
    #(兩條直線之間的最大間隔,小於此值,認為是一條直線)。
    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, β, γ)
    #劃線顯示權重,α越大 背景圖越清楚,β越大,線在影象上顯示越深

開始測試圖片

import os
os.listdir("test_images/")

下面就是主要實現函式,和一些引數調整

def line_detect(image):

    gary = grayscale(image)

    kernel_size = 9
    blur_gray = gaussian_blur(gary,kernel_size)
    
    low_threshold = 10
    high_threshold = 150
    edges = canny(blur_gray,low_threshold,high_threshold)


    imshape = image.shape
    vertices = np.array([[(0,imshape[0]),(int(0.45*imshape[1]),int(0.6*imshape[0])),
                          (int(0.6*imshape[1]),int(0.6*imshape[0])), (imshape[1],imshape[0])]], dtype=np.int32)
    masked_edges = 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_length = 150 #minimum number of pixels making up a line
    max_line_gap = 100  # maximum gap in pixels between connectable line segments

    #threshod: 累加平面的閾值引數,int型別,超過設定閾值才被檢測出線段,值越大,
    #基本上意味著檢出的線段越長,檢出的線段個數越少。根據情況推薦先用100試試
    #minLineLength:線段以畫素為單位的最小長度,根據應用場景設定 
    #maxLineGap:同一方向上兩條線段判定為一條線段的最大允許間隔(斷裂),
    #超過了設定值,則把兩條線段當成一條線段
    #,值越大,允許線段上的斷裂越大,越有可能檢出潛在的直線段
    
    line_image = hough_lines(masked_edges,rho,theta,threshold,min_line_length,max_line_gap)
    
    result = weighted_img(line_image,image, α=0.8, β=1.)
    
    return edges,masked_edges,result

下面是把圖片都顯示出來,分為4幅圖片,原圖,Canny變化後的圖,masked後的圖,最終結果圖

import glob
new_path = os.path.join("test_images/","*.jpg")
for infile in glob.glob(new_path):
        image = mpimg.imread(infile)
        edges,masked_edges,result = line_detect(image)
        
        plt.figure(figsize=(20,10))
        fig = plt.figure()
        plt.subplot(221)
        plt.title("original image")
        plt.imshow(image)
        
        plt.subplot(222)
        plt.title("Canny")
        plt.imshow(edges,cmap = "gray")
        
        plt.subplot(223)
        plt.title("masked image")
        plt.imshow(masked_edges,cmap = "gray")
        
        plt.subplot(224)
        plt.title("result")
        plt.imshow(result)


在視訊上顯示車道線

# Import everything needed to edit/save/watch video clips
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)
    
    edges,masked_edges,result = line_detect(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)
HTML("""
<video width="960" height="540" controls>
  <source src="{0}">
</video>
""".format(white_output))

第二個視訊

yellow_output = 'test_videos_output/solidYellowLeft.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
##clip2 = VideoFileClip('test_videos/solidYellowLeft.mp4').subclip(0,5)
clip2 = VideoFileClip('test_videos/solidYellowLeft.mp4')
yellow_clip = clip2.fl_image(process_image)
%time yellow_clip.write_videofile(yellow_output, audio=False)
HTML("""
<video width="960" height="540" controls>
  <source src="{0}">
</video>
""".format(yellow_output))

到這裡就算是完結了,這裡的主要難點還是draw_lines()這個函式,怎麼去優化劃線。

連結:https://pan.baidu.com/s/1BQZU2UvqkTCguodha3NwZw 密碼:60kg


相關推薦

無人駕駛工程師——P1尋找車道

這次介紹的是優達學城的無人駕駛工程師的P1專案,利用車的前攝像頭來識別當前車道的左右兩邊兩條的車道線。測試圖片和視訊在文章最後的連結裡。一開始先倒包#importing some useful packages import matplotlib.pyplot as plt

無人駕駛工程師——P4車道檢測功能

這次講的是優達學城的無人駕駛工程師的P4專案,利用車前方的攝像頭檢測車道線,下面開始我們的程式碼部分。import numpy as np import cv2 import glob import matplotlib.pyplot as plt import pickle

【備忘】最新udacity無人駕駛工程師視訊教程

為什麼學習無人駕駛開發?無人駕駛車是現代歷史中最具開創性的進步之一。它們帶來的影響不僅僅在技術、交通或城市規劃領域,而是深入到我們生活中的每一個方面,超乎你的想象。加入這個納米學位專案,你將掌握那些能讓你塑造未來的技術。你將參與一系列互動型實戰專案,包括但不限於計算機視覺、

無人駕駛入門》學習筆記——把python翻譯成C++

如果你學習的第一門語言是python,可能和我當初一樣,並沒有什麼特別的感受。但是,後面又學習了C++的話就會發現,python使用起來太方便了!C++的各種條條框框太多了! 作為動態語言,python不需要預先設定資料的型別,非常靈活,而代價就是執行速度慢。

零基礎如何學習的《無人駕駛入門》?

因為感興趣,而且看好無人駕駛行業,我學習了優達學城的《無人駕駛入門》課程。最近整理了無人駕駛領域的資料,寫成文章分享給大家。作為系列文章的第一篇,我想介紹一下《無人駕駛入門》這門課,課程所需要的先修知識,以及我是如何準備的。 學習這門課的收穫《無人駕駛入門》其實給我帶來了不

-神經網路之預測共享單車使用情況 程式碼分析

優達學城-神經網路之預測共享單車使用情況 程式碼分析 標籤(): 機器學習 程式碼來自於優達學城深度學習納米學位課程的第一個專案 https://cn.udacity.com/course/deep-learning-nanodegree-foundation–nd101

-深度學習筆記(一)

優達學城-深度學習筆記(一) 標籤: 機器學習 優達學城-深度學習筆記一 一 神經網路簡介 最大似然概率 交叉熵Cross entropy

(Udacity)深度學習筆記-1.Python&os學習

歡迎使用Markdown編輯器寫部落格 Python對於檔案操作非常方便,很大一部分是因為os這個庫,在做優達城深度學習作業的時候裡面有一堆os,各種列表推導式混合os.path,一下就繞暈了。這裡做點筆記,方便自己學習&複習。 如上圖,

無人駕駛工程師第二期——P1擴充套件卡爾曼濾波器

這次記錄的是優達學城的無人駕駛工程師第二期的第一個專案,Extended Kalman Filters,這個專案和之前第一期的P3專案比較像,也是需要程式碼和一個程式之間連結,所以一開始的安裝步驟就會比較麻煩,文中也有說在linux上執行會比較容易,所以這篇文章就是介紹我是如

無人駕駛工程師第二期——P5MPC

P5要重新配置一些環境 主要就是安裝Ipopt和CppAD 我的是Ubuntu14 先按照Udacity給的教程配置 sudo apt-get install gfortran sudo apt-get install unzip wget https://www

如何成為一名無人駕駛工程師

作者 | 劉少山 無人駕駛作為一項新興技術,落地為產品需要大量演算法、工程、產品貫通的AI全棧人才。筆者在最近一年招聘中發現,許多技術方向的同學對人工智慧既愛又畏懼,一方面覺得這是未來,另一方面又覺得很難而不敢觸碰。懂工程的同學做演算法時有很大的畏懼感,而專注演算法的同學又常常容易陷入某個演算法而缺

Udacity無人駕駛工程師學習筆記(一)

        無人駕駛是當前一個火熱的話題,多個學科的人才開始湧入這個行業,udacity出了這門網課,在學習之餘,我想記錄下相關的知識點,以便於整理歸類,同時藉助這個平臺也能夠與大家一起討論。本人非專業人士,不足之處請多指教!         在第一學期的第一次課程中,

自動駕駛技術之——無人駕駛中的CAN總

得到 選中 bsp 取出 普通 sign 整數 基本上 使用 CAN總線在整個無人駕駛系統中有著十分重要的作用。除了在VCU信號需要通過CAN總線進行傳輸外,無人車上的某些傳感器(如雷達、Mobileye)的信號傳遞也是通過CAN實現的。 前言 本文主要內容是——無人駕

【美團點評】無人駕駛演算法工程師 2017-09-03電話面試

前言 以後關於校招的面經,全部以問題的形式寫在部落格裡面。校招季很忙,沒有那麼多時間去寫部落格,希望大家諒解。 面經 1、自我介紹 2、問簡歷上的專案,一個是模型壓縮方面的,一個是目標檢測方面的;

無人駕駛:Term-1 p1 lane-detection

簡介   Udacity是矽谷的一個線上教育網站,主要以介紹AI技術為主,除了基本的課程錄影還會有專業老師進行程式碼review,通過課程會頒發nano degree。其中最為火爆的一門課程就是自動駕駛課程CarNd,這門課程由簡入繁分了三個term,第一個t

誰掌控無人駕駛?領域鼻祖"谷歌"專利居然排第10位

text 競賽 -i 判斷 通過 ins 企業 2017年 nom 無人駕駛大勢所趨,無論是科技公司還是傳統車企,都在搶占無人駕駛技術高地。說起誰將引領無人駕駛潮流,人們一般最先想到是科技公司如谷歌、特斯拉,但最近一份以專利數量來衡量無人駕駛技術實力的排行中,谷歌僅排在第十

沈默已久的華為突然宣告殺入無人駕駛領域,司機將全部失業!

5g 汽車 無人汽車 無人駕駛 5G要來了!5G到來後的世界,是一個萬物互聯的天下,手機將失去今天的獨霸天下的地位。而汽車,作為萬物互聯中的重要一個維度,將像今天的智能手機一樣,成為未來爭奪的重要陣地。這個陣地的最前沿入口,是智能駕駛!誰捷足先登,掌握了智能駕駛的技術和數據,誰就將掌握5G時代

現實中的大城市道路 真需要無人駕駛汽車嗎?

無人駕駛汽車相信許多80後都看過一部美國譯制片《霹靂遊俠》,筆者早已忘卻了主人公的名字,但對於那輛有生命的汽車,我卻一直記憶猶新,它的名字叫基恩,外殼堅硬,如銅墻鐵壁,抗得住子彈,甚至能把子彈反彈回去;程序設定基恩會分析路況環境,恰到好處、善解人意地同主人聊天,比之Siri懂事1000倍,自然,基恩肯定能自我

Web前端開發好學嗎?談談一位姐的前端工程師之路

努力 不同 最終 log jpg 問題 mage image 前端工程 我的第一篇博客。。。。。。。 我是一名工科女,因高考失利與理想的院校擦肩而過,從而選擇了機電專業。畢業後找工作時才發現機電專業的工作並不太適合我。我的父母也支持我轉專業求職,但這個過程有時會讓我迷茫。在

我該如何進入無人駕駛領域?

思考 服務 內心 .cn lan 收益 谷歌 目前 新的 KITTCAMP無人駕駛社區股權眾籌工作正在火熱進行當中,一經開始,很多業內外人士對此事產生了高度的關註。 無人駕駛汽車?不就是不需要人開的車嗎!如果只是那樣,事情該多麽簡單。真正的無人駕駛是將