<reponame>sameerpawar/CarND-Advanced-lane-lines
'''
Choices made
1. histogram computation height: Think of robustness in a sense sometimes the lanes will not be in lower few pixel part.
1. [also addressed in lecture 35 with convolution) leftx_base, rightx_base are taken at "midpoint" using "max". Both chocies can be thought again, 
e.g., instead of max per column take aggregation of few columns to account for line thickness or Sliding window in histogram 
of certain width (another hyper parameter) to determine a position where we accumaulate maximum pixels.
1. Window size: vertical (nWindows) and horizontal (margin), 
1. minpix to be found in a window to re-center the x positions.
1. When you reuse the polynomioal lane estimate from previous frame the margin can be different than the window margin in first frame. Also, you can have a minpix_2 threshold to determine 
if we need to re-do the sliding window again since the older estimate is less trust worthy.

# Propagation of belief [not very clear how to proceed]
1. Initial prior on the first layer of first frame is uniform.
1. Histogram is an observation. Convolution on histogram is just ML boosting of SNR by assuming averaging imporves signal but not noise.
1. Find the center of lane.
1. Take a window around the center as first box of lane line.
1. Take 3 windows (1.5 on each side of lane center) worth observations normalize to generate distribution of possible lane positions.

In new frame prior can be last frame posterier with some confidence.
Confidence can be based on how many pixels are in the estimated zone. If it is clear that we have detected a strong lane line we can have a more concentrated posterior.

1. Current code uses mean to find center within a selected box for next layer. We can try some other statistics such as median or other ways of eliminating outliers before averaging 


'''
import numpy as np
import cv2
import matplotlib.pyplot as plt

# Assuming you have created a warped binary image called "binary_warped"
# Take a histogram of the bottom half of the image
histogram = np.sum(binary_warped[binary_warped.shape[0]//2:,:], axis=0)
# Create an output image to draw on and  visualize the result
out_img = np.dstack((binary_warped, binary_warped, binary_warped))*255
# Find the peak of the left and right halves of the histogram
# These will be the starting point for the left and right lines
midpoint = np.int(histogram.shape[0]//2)
leftx_base = np.argmax(histogram[:midpoint])
rightx_base = np.argmax(histogram[midpoint:]) + midpoint

# Choose the number of sliding windows
nwindows = 9
# Set height of windows
window_height = np.int(binary_warped.shape[0]//nwindows)
# Identify the x and y positions of all nonzero pixels in the image
nonzero = binary_warped.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
# Current positions to be updated for each window
leftx_current = leftx_base
rightx_current = rightx_base
# Set the width of the windows +/- margin
margin = 100
# Set minimum number of pixels found to recenter window
minpix = 50
# Create empty lists to receive left and right lane pixel indices
left_lane_inds = []
right_lane_inds = []

# Step through the windows one by one
for window in range(nwindows):
    # Identify window boundaries in x and y (and right and left)
    win_y_low = binary_warped.shape[0] - (window+1)*window_height
    win_y_high = binary_warped.shape[0] - window*window_height
    win_xleft_low = leftx_current - margin
    win_xleft_high = leftx_current + margin
    win_xright_low = rightx_current - margin
    win_xright_high = rightx_current + margin
    # Draw the windows on the visualization image
    cv2.rectangle(out_img,(win_xleft_low,win_y_low),(win_xleft_high,win_y_high),
    (0,255,0), 2) 
    cv2.rectangle(out_img,(win_xright_low,win_y_low),(win_xright_high,win_y_high),
    (0,255,0), 2) 
    # Identify the nonzero pixels in x and y within the window
    good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
    (nonzerox >= win_xleft_low) &  (nonzerox < win_xleft_high)).nonzero()[0]
    good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
    (nonzerox >= win_xright_low) &  (nonzerox < win_xright_high)).nonzero()[0]
    # Append these indices to the lists
    left_lane_inds.append(good_left_inds)
    right_lane_inds.append(good_right_inds)
    # If you found > minpix pixels, recenter next window on their mean position
    if len(good_left_inds) > minpix:
        leftx_current = np.int(np.mean(nonzerox[good_left_inds]))
    if len(good_right_inds) > minpix:        
        rightx_current = np.int(np.mean(nonzerox[good_right_inds]))

# Concatenate the arrays of indices
left_lane_inds = np.concatenate(left_lane_inds)
right_lane_inds = np.concatenate(right_lane_inds)

# Extract left and right line pixel positions
leftx = nonzerox[left_lane_inds]
lefty = nonzeroy[left_lane_inds] 
rightx = nonzerox[right_lane_inds]
righty = nonzeroy[right_lane_inds] 

# Fit a second order polynomial to each
left_fit = np.polyfit(lefty, leftx, 2)
right_fit = np.polyfit(righty, rightx, 2)
'''
Choices made
1. histogram computation height: Think of robustness in a sense sometimes the lanes will not be in lower few pixel part.
1. [also addressed in lecture 35 with convolution) leftx_base, rightx_base are taken at "midpoint" using "max". Both chocies can be thought again, 
e.g., instead of max per column take aggregation of few columns to account for line thickness or Sliding window in histogram 
of certain width (another hyper parameter) to determine a position where we accumaulate maximum pixels.
1. Window size: vertical (nWindows) and horizontal (margin), 
1. minpix to be found in a window to re-center the x positions.
1. When you reuse the polynomioal lane estimate from previous frame the margin can be different than the window margin in first frame. Also, you can have a minpix_2 threshold to determine 
if we need to re-do the sliding window again since the older estimate is less trust worthy.

# Propagation of belief [not very clear how to proceed]
1. Initial prior on the first layer of first frame is uniform.
1. Histogram is an observation. Convolution on histogram is just ML boosting of SNR by assuming averaging imporves signal but not noise.
1. Find the center of lane.
1. Take a window around the center as first box of lane line.
1. Take 3 windows (1.5 on each side of lane center) worth observations normalize to generate distribution of possible lane positions.

In new frame prior can be last frame posterier with some confidence.
Confidence can be based on how many pixels are in the estimated zone. If it is clear that we have detected a strong lane line we can have a more concentrated posterior.

1. Current code uses mean to find center within a selected box for next layer. We can try some other statistics such as median or other ways of eliminating outliers before averaging 


'''
import numpy as np
import cv2
import matplotlib.pyplot as plt

# Assuming you have created a warped binary image called "binary_warped"
# Take a histogram of the bottom half of the image
histogram = np.sum(binary_warped[binary_warped.shape[0]//2:,:], axis=0)
# Create an output image to draw on and  visualize the result
out_img = np.dstack((binary_warped, binary_warped, binary_warped))*255
# Find the peak of the left and right halves of the histogram
# These will be the starting point for the left and right lines
midpoint = np.int(histogram.shape[0]//2)
leftx_base = np.argmax(histogram[:midpoint])
rightx_base = np.argmax(histogram[midpoint:]) + midpoint

# Choose the number of sliding windows
nwindows = 9
# Set height of windows
window_height = np.int(binary_warped.shape[0]//nwindows)
# Identify the x and y positions of all nonzero pixels in the image
nonzero = binary_warped.nonzero()
nonzeroy = np.array(nonzero[0])
nonzerox = np.array(nonzero[1])
# Current positions to be updated for each window
leftx_current = leftx_base
rightx_current = rightx_base
# Set the width of the windows +/- margin
margin = 100
# Set minimum number of pixels found to recenter window
minpix = 50
# Create empty lists to receive left and right lane pixel indices
left_lane_inds = []
right_lane_inds = []

# Step through the windows one by one
for window in range(nwindows):
    # Identify window boundaries in x and y (and right and left)
    win_y_low = binary_warped.shape[0] - (window+1)*window_height
    win_y_high = binary_warped.shape[0] - window*window_height
    win_xleft_low = leftx_current - margin
    win_xleft_high = leftx_current + margin
    win_xright_low = rightx_current - margin
    win_xright_high = rightx_current + margin
    # Draw the windows on the visualization image
    cv2.rectangle(out_img,(win_xleft_low,win_y_low),(win_xleft_high,win_y_high),
    (0,255,0), 2) 
    cv2.rectangle(out_img,(win_xright_low,win_y_low),(win_xright_high,win_y_high),
    (0,255,0), 2) 
    # Identify the nonzero pixels in x and y within the window
    good_left_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
    (nonzerox >= win_xleft_low) &  (nonzerox < win_xleft_high)).nonzero()[0]
    good_right_inds = ((nonzeroy >= win_y_low) & (nonzeroy < win_y_high) & 
    (nonzerox >= win_xright_low) &  (nonzerox < win_xright_high)).nonzero()[0]
    # Append these indices to the lists
    left_lane_inds.append(good_left_inds)
    right_lane_inds.append(good_right_inds)
    # If you found > minpix pixels, recenter next window on their mean position
    if len(good_left_inds) > minpix:
        leftx_current = np.int(np.mean(nonzerox[good_left_inds]))
    if len(good_right_inds) > minpix:        
        rightx_current = np.int(np.mean(nonzerox[good_right_inds]))

# Concatenate the arrays of indices
left_lane_inds = np.concatenate(left_lane_inds)
right_lane_inds = np.concatenate(right_lane_inds)

# Extract left and right line pixel positions
leftx = nonzerox[left_lane_inds]
lefty = nonzeroy[left_lane_inds] 
rightx = nonzerox[right_lane_inds]
righty = nonzeroy[right_lane_inds] 

# Fit a second order polynomial to each
left_fit = np.polyfit(lefty, leftx, 2)
right_fit = np.polyfit(righty, rightx, 2)
Choices made 1. histogram computation height: Think of robustness in a sense sometimes the lanes will not be in lower few pixel part. 1. [also addressed in lecture 35 with convolution) leftx_base, rightx_base are taken at "midpoint" using "max". Both chocies can be thought again,  e.g., instead of max per column take aggregation of few columns to account for line thickness or Sliding window in histogram  of certain width (another hyper parameter) to determine a position where we accumaulate maximum pixels. 1. Window size: vertical (nWindows) and horizontal (margin),  1. minpix to be found in a window to re-center the x positions. 1. When you reuse the polynomioal lane estimate from previous frame the margin can be different than the window margin in first frame. Also, you can have a minpix_2 threshold to determine  if we need to re-do the sliding window again since the older estimate is less trust worthy.  # Propagation of belief [not very clear how to proceed] 1. Initial prior on the first layer of first frame is uniform. 1. Histogram is an observation. Convolution on histogram is just ML boosting of SNR by assuming averaging imporves signal but not noise. 1. Find the center of lane. 1. Take a window around the center as first box of lane line. 1. Take 3 windows (1.5 on each side of lane center) worth observations normalize to generate distribution of possible lane positions.  In new frame prior can be last frame posterier with some confidence. Confidence can be based on how many pixels are in the estimated zone. If it is clear that we have detected a strong lane line we can have a more concentrated posterior.  1. Current code uses mean to find center within a selected box for next layer. We can try some other statistics such as median or other ways of eliminating outliers before averaging # Assuming you have created a warped binary image called "binary_warped" # Take a histogram of the bottom half of the image # Create an output image to draw on and  visualize the result # Find the peak of the left and right halves of the histogram # These will be the starting point for the left and right lines # Choose the number of sliding windows # Set height of windows # Identify the x and y positions of all nonzero pixels in the image # Current positions to be updated for each window # Set the width of the windows +/- margin # Set minimum number of pixels found to recenter window # Create empty lists to receive left and right lane pixel indices # Step through the windows one by one # Identify window boundaries in x and y (and right and left) # Draw the windows on the visualization image # Identify the nonzero pixels in x and y within the window # Append these indices to the lists # If you found > minpix pixels, recenter next window on their mean position # Concatenate the arrays of indices # Extract left and right line pixel positions # Fit a second order polynomial to each