# -*- coding: utf-8 -*-
"""lane-detection.ipynb

Automatically generated by Colaboratory.

Original file is located at
    https://colab.research.google.com/drive/1sq3rmi1lnGTkzWccZ_DAzjxGEXK22EZ6
"""

#importing libraries
import numpy as np
import matplotlib.pyplot as plt
import cv2

from google.colab.patches import cv2_imshow

from google.colab import drive
drive.mount('/content/gdrive')

image_path = r"/content/gdrive/MyDrive/Lane-Detection-master/Lane-Detection-master/Images/test_image.jpg"
image = cv2.imread(image_path) #converts the image into multidimensional numpy array
cv2_imshow(image)
cv2.waitKey(0)
plt.imshow(image)

#Grayscale
lane_image = np.copy(image)
gray = cv2.cvtColor(lane_image, cv2.COLOR_RGB2GRAY)
cv2_imshow(gray)
cv2.waitKey(0)

#Gaussian blur
blur = cv2.GaussianBlur(gray, (5,5), 0)
cv2_imshow( blur)
cv2.waitKey(0)

#applying canny edge function
c = cv2.Canny(blur, 50,150)
cv2_imshow( c)
cv2.waitKey(0)

lane_image = np.copy(image)

#canny function will contain all the changes
def canny(image):
    gray = cv2.cvtColor(lane_image, cv2.COLOR_RGB2GRAY) #original image
    blur = cv2.GaussianBlur(gray, (5,5), 0)
    canny = cv2.Canny(blur, 50,150)
    return canny

plt.imshow(canny(lane_image))

"""Thus we got the image that is grayscaled, gaussiun blurred and applied on with canny algorithm. 

"""

#array of image applied with canny edge function 
c1 = canny(lane_image)

#region of interest
def region_of_int(image):
    height = image.shape[0] 
    #Coordinates of the triangular region
    polygons = np.array([
        [(200,height), (1100, height), (550, 250)]
    ])
    #Create a black image with the same dimensions as original image
    mask = np.zeros_like(image)
    cv2.fillPoly(mask, polygons, 255)#filling the traced polygon with white
    return mask
    
cv2_imshow( region_of_int(c1))
cv2.waitKey(0)

#Bitwise on the canny edge image
def region_of_int(image):
    height = image.shape[0]
    #Coordinates of the triangular region
    polygons = np.array([
        [(200,height), (1100, height), (550, 250)]
    ])
    #create a black image with the same dimensions as original image  
    mask = np.zeros_like(image)
    cv2.fillPoly(mask, polygons, 255)
    masked_image = cv2.bitwise_and(image, mask)
    return masked_image

cropped_image = region_of_int(c1)
cv2_imshow(cropped_image)
cv2.waitKey(0)

#Hough transform  
lines = cv2.HoughLinesP(cropped_image, 2, np.pi/180, 100, np.array([]), minLineLength = 40, maxLineGap = 5)

def display_lines(image, lines):
    line_image = np.zeros_like(image)
    
    #to make sure array is not empty
    if lines is not None: 
       for line in lines:
            x1, y1, x2, y2= line.reshape(4)
            
            #Black lines on image
            cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 10)
    return line_image

line_image = display_lines(lane_image, lines)
cv2_imshow(line_image)
cv2.waitKey(0)

#sum of color image(lane_image) with weights, i.e merging the black and original image
combo_image = cv2.addWeighted(lane_image, 0.8, line_image, 1, 1)
cv2_imshow(combo_image)
cv2.waitKey(0)

#optimization 

#the coordinates for the averaged out single line
def make_coord(image, line_parameters):
    slope, intercept = line_parameters
    y1 = image.shape[0]
    y2 = int(y1*(3/5))
    x1 = int((y1 - intercept)/slope)
    x2 = int((y2 - intercept)/slope)
    return np.array([x1, y1, x2, y2])
  


#average the slope of multiple lines and make one line
def average_slope(image, lines):
    left_fit= []
    right_fit = []
    for line in lines:
        x1, y1, x2, y2= line.reshape(4)
        
        #fit line to points, return slope and y-int
        parameters = np.polyfit((x1, x2), (y1, y2), 1) 
        slope = parameters[0]
        intercept = parameters[1]
        #lines on the right have positive slope, and lines on the left have negative slope
        if slope < 0:
            left_fit.append((slope, intercept))
        else: 
            right_fit.append((slope, intercept))
    
    #average of all the columns (column0: slope, cloumns: y_int)
    left_fit_avg = np.average(left_fit, axis = 0)
    right_fit_avg = np.average(right_fit, axis = 0)
    
    #Create line based on avg value
    left_line = make_coord(image, left_fit_avg)
    right_line = make_coord(image, right_fit_avg)
    return np.array([left_line, right_line])

averaged_lines = average_slope(lane_image, lines)
line_image = display_lines(lane_image, averaged_lines)
cv2_imshow(line_image)
cv2.waitKey(0)

combo_image = cv2.addWeighted(lane_image, 0.8, line_image, 1, 1)
cv2_imshow(combo_image)
cv2.waitKey(0)

"""## Detecting lane lines in video"""

capture = cv2.VideoCapture(r"/content/gdrive/MyDrive/Lane-Detection-master/Lane-Detection-master/Videos/test2.mp4")
while(capture.isOpened()):
    ret, frame = capture.read()
    if ret == True:
        c1 = canny(frame)
        cropped_image = region_of_int(c1)
        lines = cv2.HoughLinesP(cropped_image, 2, np.pi/180, 100, np.array([]), minLineLength=40,maxLineGap=5)
        averaged_lines = average_slope(frame, lines)
        line_image = display_lines(frame, averaged_lines)
        combo_image = cv2.addWeighted(frame, 0.8, line_image, 1, 1)
        cv2_imshow(combo_image)
        if cv2.waitKey(10) & 0xFF == ord('q'):
            break
    else:
        break
capture.release()
cv2.destroyAllWindows()

