Finding Lane Lines Project

Import libraries


In [1]:
import numpy as np
import cv2
import os
from moviepy.editor import VideoFileClip
from IPython.display import HTML

Define findLaneLines function


In [2]:
def findLaneLines(image):
    #Define Parameters
    #------------------------------------
    #Region mask Parameters
    lowery=1
    upppery=0.55
    dx=0.07
    gap=0.04
    #Color mask parameters
    white_threshold=np.array([175],dtype="uint8")
    yellow_threshold=np.array([50, 0, 150],dtype="uint8")
    upperb_white=np.array([255],dtype="uint8")
    upperb_yellow=np.array([255,150,255],dtype="uint8")
    #Gaussian smoothing kernel
    kernel_size = 5
    #Canny edge detection thresholds
    low_threshold = 50
    high_threshold = 180
    #Hough lines parameters
    rho = 1 # distance resolution in pixels of the Hough grid
    theta = np.pi/180 # angular resolution in radians of the Hough grid
    threshold = 5     # minimum number of votes (intersections in Hough grid cell)
    min_line_length = 15 #minimum number of pixels making up a line
    max_line_gap = 15    # maximum gap in pixels between connectable line segments
    #threshold to determine if line is yellow
    minYellow=300
    #-------------------------------------
    
    #Convert BGR image to lab color space and gray scale
    lab = cv2.cvtColor(image,cv2.COLOR_BGR2LAB)
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    #Calculate yellow and white color masks
    white_mask=cv2.inRange(gray,white_threshold,upperb_white)
    yellow_mask=cv2.inRange(lab,yellow_threshold,upperb_yellow)
    #Smoothe gray scale image
    blur_gray = cv2.GaussianBlur(gray,(kernel_size, kernel_size),0)
    #normalize B channel of lab image
    normalizedImg=cv2.normalize(lab[:,:,2],np.zeros_like(lab[:,:,2]), 0, 255, cv2.NORM_MINMAX)
    #Extract edges from gray scale LAB color space images and merge them
    edges = cv2.Canny(blur_gray, low_threshold, high_threshold)
    edges=cv2.bitwise_or(cv2.Canny(normalizedImg, 30, 180),edges)
    #Filter edges with color masks
    white_edges=cv2.bitwise_and(edges,edges,mask=white_mask)
    yellow_edges=cv2.bitwise_and(edges,edges,mask=yellow_mask)
    #Create regional masks, for areas whare lane lines are expected
    left_mask = np.zeros_like(edges)
    right_mask = np.zeros_like(edges)
    ignore_mask_color = 255   
    #define corners
    ysize = image.shape[0]
    xsize = image.shape[1]
    
    left_left_top=[xsize*(0.5-dx),ysize*upppery]
    left_right_top=[xsize*(0.50-gap),ysize*upppery]
    left_left_bottom=[xsize*dx,ysize*lowery]
    left_right_bottom=[xsize*(0.5-2*gap),ysize*lowery]
    
    right_left_top=[xsize*(0.5+gap),ysize*upppery]
    right_right_top=[xsize*(0.5+dx),ysize*upppery]
    right_left_bottom=[xsize*(0.5+2*gap),ysize*lowery]
    right_right_bottom=[xsize*(1-dx),ysize*lowery]
    #Create polygons from corners
    left_vertices = np.array([[left_left_top,left_right_top, left_right_bottom, left_left_bottom]], dtype=np.int32)
    right_vertices = np.array([[right_left_top,right_right_top, right_right_bottom, right_left_bottom]], dtype=np.int32)
    #Set marks as areas within the polygons
    cv2.fillPoly(left_mask, left_vertices, ignore_mask_color)
    cv2.fillPoly(right_mask, right_vertices, ignore_mask_color)
    #check if lane lines are white or yellow
    countYellowLeft=cv2.countNonZero(cv2.bitwise_and(yellow_mask, left_mask))
    countYellowRight=cv2.countNonZero(cv2.bitwise_and(yellow_mask, right_mask))
    left_yellow=(countYellowLeft>minYellow)
    #print("Left: Yellow Count: ", countYellowLeft)
    right_yellow=(countYellowRight>minYellow)
    #print("Right Yellow Count: ", countYellowRight)
    if(left_yellow):
        left_masked_edges = cv2.bitwise_and(yellow_edges, left_mask)
    else:
        left_masked_edges = cv2.bitwise_and(white_edges, left_mask)
    if(right_yellow):
        right_masked_edges = cv2.bitwise_and(yellow_edges, right_mask)
    else:
        right_masked_edges = cv2.bitwise_and(white_edges, right_mask)
    
    line_image = np.copy(image)*0 # creating a blank to draw lines on

    # Run Hough on edge detected image
    # Output "lines" is an array containing endpoints of detected line segments
    left_lines = cv2.HoughLinesP(left_masked_edges, rho, theta, threshold, np.array([]),
                                    min_line_length, max_line_gap)
    right_lines = cv2.HoughLinesP(right_masked_edges, rho, theta, threshold, np.array([]),
                                    min_line_length, max_line_gap)
    # Iterate over the output "lines" and draw lines on a blank image
    x=[]
    y=[]
    if(left_lines is None):
        print("No left_lines detected! Yellow: "+str(left_yellow))
    else:
        #Extract X and Y values from hough lines
        for line in left_lines:
            for x1,y1,x2,y2 in line:
                x.append(x1)
                y.append(y1)
                x.append(x2)
                y.append(y2)
        #try fitting a 2nd degree polynomial
        poly=np.polyfit(y,x,2)
        #if rank is low fit a 1st gegree polynomial
        if(np.ndim(poly)<2):
            poly=np.polyfit(y,x,1)
            p = np.poly1d(poly)
        #calculate points along the poly in 10px steps
        y = np.arange(ysize*upppery, ysize*(lowery), 10)
        y = np.arange(ysize*upppery, ysize*(lowery), 10)
        x=p(y)
        i=0
        #draw lines
        for xi in x:
            cv2.line(line_image,(int(round(xi)),int(round(y[i]))),(int(round(x[i+1])),int(round(y[i+1]))),(255,0,0),10)
            i=i+1
            if i+1==len(x):
                break
    #Do the same for the right side
    x=[]
    y=[]
    if(right_lines is None):
        print("No right_lines detected! Yellow: "+str(right_yellow))
    else:
        
        for line in right_lines:
            for x1,y1,x2,y2 in line:
                #if((abs(x1-x2))<(100*abs(y1-y2))):
                x.append(x1)
                y.append(y1)
                x.append(x2)
                y.append(y2)
        poly=np.polyfit(y,x,2)
        if(np.ndim(poly)<2):
            poly=np.polyfit(y,x,1)
            p = np.poly1d(poly)
        y = np.arange(ysize*upppery, ysize*(lowery), 10)
        y = np.arange(ysize*upppery, ysize*(lowery), 10)
        x=p(y)
        i=0
        for xi in x:
            cv2.line(line_image,(int(round(xi)),int(round(y[i]))),(int(round(x[i+1])),int(round(y[i+1]))),(0,0,255),10)
            i=i+1
            if i+1==len(x):
                break

    # Draw the lines on the original image

    lines_edges = cv2.addWeighted(image, 0.8, line_image, 1, 0) 
    return lines_edges;

Input video and process it


In [ ]:
video = "challenge.mp4"
#video="solidYellowLeft.mp4"
#video="solidWhiteRight.mp4"
fps=24
fourcc = cv2.VideoWriter_fourcc('a', 'v', 'c', '1') 
init=bool(1)
print("opening video: "+video)
vidcap = cv2.VideoCapture(video)
success,image = vidcap.read()
count = 0
success = True
while success:
    success,image = vidcap.read()
    print("processing Frame ", count)
    count=count+1
    if (init):
        shape=image.shape
        writer = cv2.VideoWriter(video.replace(".mp4","_processed.mp4"),fourcc, fps, (image.shape[1],image.shape[0]))
        init=bool(0)
    if (success):
        writer.write(findLaneLines(image))
    else:
        writer.release()


opening video: challenge.mp4
processing Frame  0
processing Frame  1
processing Frame  2
processing Frame  3
processing Frame  4
processing Frame  5
processing Frame  6
processing Frame  7
processing Frame  8
processing Frame  9
processing Frame  10
processing Frame  11
processing Frame  12
processing Frame  13
processing Frame  14
processing Frame  15
processing Frame  16
processing Frame  17
processing Frame  18
processing Frame  19
processing Frame  20
processing Frame  21
processing Frame  22
processing Frame  23
processing Frame  24
processing Frame  25
processing Frame  26
processing Frame  27
processing Frame  28
processing Frame  29
processing Frame  30
processing Frame  31
processing Frame  32
processing Frame  33
processing Frame  34
processing Frame  35
processing Frame  36
processing Frame  37
processing Frame  38
processing Frame  39
processing Frame  40
processing Frame  41
processing Frame  42
processing Frame  43
processing Frame  44
processing Frame  45
processing Frame  46
processing Frame  47
processing Frame  48
processing Frame  49
processing Frame  50
processing Frame  51
processing Frame  52
processing Frame  53
processing Frame  54
processing Frame  55
processing Frame  56
processing Frame  57
processing Frame  58
processing Frame  59
processing Frame  60
processing Frame  61
processing Frame  62
processing Frame  63
processing Frame  64
processing Frame  65
processing Frame  66
processing Frame  67
processing Frame  68
processing Frame  69
processing Frame  70
processing Frame  71
processing Frame  72
processing Frame  73
processing Frame  74
processing Frame  75
processing Frame  76
processing Frame  77
processing Frame  78
processing Frame  79
processing Frame  80
processing Frame  81
processing Frame  82
processing Frame  83
processing Frame  84
processing Frame  85
processing Frame  86
processing Frame  87
processing Frame  88
processing Frame  89
processing Frame  90
processing Frame  91
processing Frame  92
processing Frame  93
processing Frame  94
processing Frame  95
processing Frame  96
processing Frame  97
processing Frame  98
processing Frame  99
processing Frame  100
processing Frame  101
processing Frame  102
processing Frame  103
processing Frame  104
processing Frame  105
processing Frame  106
processing Frame  107
processing Frame  108
processing Frame  109
processing Frame  110
processing Frame  111
processing Frame  112
processing Frame  113
processing Frame  114
processing Frame  115
processing Frame  116
processing Frame  117
processing Frame  118
processing Frame  119
processing Frame  120
processing Frame  121
processing Frame  122
processing Frame  123
processing Frame  124
processing Frame  125
processing Frame  126
processing Frame  127
processing Frame  128
processing Frame  129
processing Frame  130
processing Frame  131
processing Frame  132
processing Frame  133
processing Frame  134
processing Frame  135
processing Frame  136
processing Frame  137
processing Frame  138
processing Frame  139
processing Frame  140
processing Frame  141
processing Frame  142
processing Frame  143
processing Frame  144
processing Frame  145
processing Frame  146
processing Frame  147
processing Frame  148
processing Frame  149
processing Frame  150
processing Frame  151
processing Frame  152
processing Frame  153
processing Frame  154
processing Frame  155
processing Frame  156
processing Frame  157
processing Frame  158
processing Frame  159
processing Frame  160
processing Frame  161
processing Frame  162
processing Frame  163
processing Frame  164
processing Frame  165
processing Frame  166
processing Frame  167
processing Frame  168
processing Frame  169
processing Frame  170
processing Frame  171
processing Frame  172
processing Frame  173
processing Frame  174
processing Frame  175
processing Frame  176
processing Frame  177
processing Frame  178
processing Frame  179
processing Frame  180
processing Frame  181
processing Frame  182
processing Frame  183
processing Frame  184
processing Frame  185
processing Frame  186
processing Frame  187
processing Frame  188
processing Frame  189
processing Frame  190
processing Frame  191
processing Frame  192
processing Frame  193
processing Frame  194
processing Frame  195
processing Frame  196
processing Frame  197
processing Frame  198
processing Frame  199
processing Frame  200
processing Frame  201
processing Frame  202
processing Frame  203
processing Frame  204
processing Frame  205
processing Frame  206
processing Frame  207
processing Frame  208
processing Frame  209
processing Frame  210
processing Frame  211
processing Frame  212
processing Frame  213
processing Frame  214
processing Frame  215
processing Frame  216
processing Frame  217
processing Frame  218
processing Frame  219
processing Frame  220
processing Frame  221
processing Frame  222
processing Frame  223
processing Frame  224
processing Frame  225
processing Frame  226
processing Frame  227
processing Frame  228
processing Frame  229
processing Frame  230
processing Frame  231
processing Frame  232
processing Frame  233
processing Frame  234
processing Frame  235
processing Frame  236
processing Frame  237
processing Frame  238
processing Frame  239
processing Frame  240
processing Frame  241
processing Frame  242
processing Frame  243

In [79]:
width=str(shape[1])
height=str(shape[0])
HTML("""
<video width="""+width+""" height="""+height+""" controls>
  <source src="{0}" type="video/mp4">
</video>
""".format(video.replace(".mp4","_processed.mp4")))


Out[79]:

In [45]:



Out[45]:
'540'

In [46]:



Out[46]:
'960'

In [ ]: