Esempio n. 1
0
def find_lines(cut_off_img, Line, mode):
    #This function detects and tracks pixels that are part of a line in an image by using a sliding window approach. Both regular and convolution sliding windows are implemented
    #The detected pixels are then passed to a Line object which processes these pixels and an annotated image with detected pixels is returned

    #obtaining a binary version of the thresholded image
    binary_warped = np.zeros_like(cut_off_img)
    binary_warped[cut_off_img != 0] = 1

    #defining masking region of the input image to ignore pixels at edges
    masking_x_region = 200

    #Taking a histogram of the bottom third of the image
    histogram = np.sum(cut_off_img[2 * cut_off_img.shape[0] // 3:, :], axis=0)

    #creating image for visualization
    out_img = np.dstack((cut_off_img, cut_off_img, cut_off_img)) * 255

    #Set the width and margin of the windows +/- margin
    margin = 50
    window_width = 50
    #Setting the number of sliding windows
    nwindows = 10
    #Setting height of windows
    window_height = np.int(cut_off_img.shape[0] // nwindows)
    # Set minimum number of pixels found to recenter window
    minpix = 50

    #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])

    if (mode == 'regular'):

        #Fidning the starting point for the left and right lines
        midpoint = np.int(histogram.shape[0] // 2)
        if (Line.detected == False):
            #If no previous line is detected, the starting points of left and right lines are the peaks of the histogram previously calculated that fall withing
            #the defined region
            leftx_base = np.argmax(histogram[masking_x_region:(
                midpoint - masking_x_region)]) + masking_x_region
            rightx_base = np.argmax(histogram[(midpoint + masking_x_region):(
                histogram.shape[0] -
                masking_x_region)]) + midpoint + masking_x_region
        else:
            #If previpus lines were detected, starting points are obtained based on the previous fitted polynomials
            y_eval = binary_warped.shape[0]
            leftx_base = int(Line.avg_left_poly[0] * y_eval**2 +
                             Line.avg_left_poly[1] * y_eval +
                             Line.avg_left_poly[2])
            rightx_base = int(Line.avg_right_poly[0] * y_eval**2 +
                              Line.avg_right_poly[1] * y_eval +
                              Line.avg_right_poly[2])

        # Current positions to be updated for each window
        leftx_current = leftx_base
        rightx_current = rightx_base

        # Create empty lists to receive left and right lane pixel indices
        left_lane_inds = []
        right_lane_inds = []

        #Defining momentum values that induce windows to keep moving in the same direction
        right_momentum = 0
        left_momentum = 0

        #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]

            #Appending these indices to the lists
            left_lane_inds.append(good_left_inds)
            right_lane_inds.append(good_right_inds)

            #If found > minpix pixels, update momentum values
            if len(good_left_inds) > minpix:
                left_change = np.int(np.mean(
                    nonzerox[good_left_inds])) - leftx_current
                if (left_momentum == 0):
                    left_momentum = left_change
                else:
                    left_momentum = left_momentum + 0.5 * left_change
            if len(good_right_inds) > minpix:
                right_change = np.int(np.mean(
                    nonzerox[good_right_inds])) - rightx_current
                if (right_momentum == 0):
                    right_momentum = right_change
                else:
                    right_momentum = right_momentum + 0.5 * right_change

#updating windows center values
            if (myLine.detected == False):
                #in case no previous line was detected, update window position by adding newly calculated momentum values
                leftx_current = leftx_current + int(left_momentum)
                rightx_current = rightx_current + int(right_momentum)
            else:
                leftx_current = int(0.5 * (leftx_current + left_momentum) +
                                    0.5 *
                                    (Line.avg_left_poly[0] * win_y_low**2 +
                                     Line.avg_left_poly[1] * win_y_low +
                                     Line.avg_left_poly[2]))
                rightx_current = int(0.5 * (rightx_current + right_momentum) +
                                     0.5 *
                                     (Line.avg_right_poly[0] * win_y_low**2 +
                                      Line.avg_right_poly[1] * win_y_low +
                                      Line.avg_right_poly[2]))

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

        #Extracting 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]

        #plotting detected pixels
        pts_r = np.vstack((rightx, righty)).astype(np.int32).T
        cv2.polylines(out_img, [pts_r], False, (0, 0, 255), 5)
        pts_l = np.vstack((leftx, lefty)).astype(np.int32).T
        cv2.polylines(out_img, [pts_l], False, (0, 0, 255), 5)

        #Appending to line object
        Line.add_points(lefty, leftx, righty, rightx)

    elif (mode == 'convolution'):

        window_centroids = [
        ]  #Store the (left,right) window centroid positions per level
        window = np.ones(
            window_width
        )  #Create our window template that we will use for convolutions

        if (Line.detected == False):
            #First find the two starting positions for the left and right lane by using np.sum to get the vertical image slice
            #and then np.convolve the vertical image slice with the window template
            l_sum = np.sum(cut_off_img[int(3 * cut_off_img.shape[0] /
                                           4):, :int(cut_off_img.shape[1] /
                                                     2)],
                           axis=0)
            l_center = np.argmax(np.convolve(window, l_sum)) - window_width / 2
            r_sum = np.sum(cut_off_img[int(3 * cut_off_img.shape[0] / 4):,
                                       int(cut_off_img.shape[1] / 2):],
                           axis=0)
            r_center = np.argmax(np.convolve(window,
                                             r_sum)) - window_width / 2 + int(
                                                 binary_warped.shape[1] / 2)
        else:
            #If previpus lines were detected, starting points are obtained based on the previous fitted polynomials
            y_eval = binary_warped.shape[0]
            l_center = int(Line.avg_left_poly[0] * y_eval**2 +
                           Line.avg_left_poly[1] * y_eval +
                           Line.avg_left_poly[2])
            r_center = int(Line.avg_right_poly[0] * y_eval**2 +
                           Line.avg_right_poly[1] * y_eval +
                           Line.avg_right_poly[2])

        window_centroids.append((l_center, r_center))

        leftx = []
        lefty = []
        rightx = []
        righty = []

        # Create empty lists to receive left and right lane pixel indices
        left_lane_inds = []
        right_lane_inds = []

        #Defining momentum values that induce windows to keep moving in the same direction
        right_momentum = 0
        left_momentum = 0

        # Go through each layer looking for max pixel locations
        for level in range(1, (int)(binary_warped.shape[0] / window_height)):

            # convolve the window into the vertical slice of the image
            win_y_high = int(cut_off_img.shape[0] - level * window_height)
            win_y_low = int(cut_off_img.shape[0] - (level + 1) * window_height)
            image_layer = np.sum(cut_off_img[win_y_low:win_y_high, :], axis=0)
            conv_signal = np.convolve(window, image_layer)

            # Find the best left centroid by using past left center as a reference
            # Use window_width/2 as offset because convolution signal reference is at right side of window, not center of window
            offset = window_width / 2
            l_min_index = int(max(l_center + offset - margin, 0))
            l_max_index = int(
                min(l_center + offset + margin, cut_off_img.shape[1]))
            #l_center = np.argmax(conv_signal[l_min_index:l_max_index])+l_min_index-offset

            # Find the best right centroid by using past right center as a reference
            r_min_index = int(max(r_center + offset - margin, 0))
            r_max_index = int(
                min(r_center + offset + margin, binary_warped.shape[1]))
            #r_center = np.argmax(conv_signal[r_min_index:r_max_index])+r_min_index-offset

            #plotting windows
            cv2.rectangle(out_img, (l_min_index, win_y_low),
                          (l_max_index, win_y_high), (0, 255, 0), 2)
            cv2.rectangle(out_img, (r_min_index, win_y_low),
                          (r_max_index, 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 >= l_min_index) &
                              (nonzerox < l_max_index)).nonzero()[0]
            good_right_inds = ((nonzeroy >= win_y_low) &
                               (nonzeroy < win_y_high) &
                               (nonzerox >= r_min_index) &
                               (nonzerox < r_max_index)).nonzero()[0]

            #Append these indices to the lists
            left_lane_inds.append(good_left_inds)
            right_lane_inds.append(good_right_inds)

            #If found > minpix pixels, update momentum values
            if len(good_left_inds) > minpix:
                left_change = np.argmax(conv_signal[l_min_index:l_max_index]
                                        ) + l_min_index - offset - l_center
                if (left_momentum == 0):
                    left_momentum = left_change
                else:
                    left_momentum = left_momentum + 0.5 * left_change
            if len(good_right_inds) > minpix:
                right_change = np.argmax(conv_signal[r_min_index:r_max_index]
                                         ) + r_min_index - offset - r_center
                if (right_momentum == 0):
                    right_momentum = right_change
                else:
                    right_momentum = right_momentum + 0.5 * right_change

            #updating windows center values
            if (myLine.detected == False):
                #in case no previous line was detected, update window position by adding newly calculated momentum values
                l_center = l_center + int(left_momentum)
                r_center = r_center + int(right_momentum)
            else:
                l_center = int(0.5 * (l_center + left_momentum) + 0.5 *
                               (Line.avg_left_poly[0] * win_y_low**2 +
                                Line.avg_left_poly[1] * win_y_low +
                                Line.avg_left_poly[2]))
                r_center = int(0.5 * (r_center + right_momentum) + 0.5 *
                               (Line.avg_right_poly[0] * win_y_low**2 +
                                Line.avg_right_poly[1] * win_y_low +
                                Line.avg_right_poly[2]))

        # 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]

        #plotting detected pixels
        pts_r = np.vstack((rightx, righty)).astype(np.int32).T
        cv2.polylines(out_img, [pts_r], False, (0, 0, 255), 5)
        pts_l = np.vstack((leftx, lefty)).astype(np.int32).T
        cv2.polylines(out_img, [pts_l], False, (0, 0, 255), 5)

        #Appending to line object
        Line.add_points(lefty, leftx, righty, rightx)

    return out_img.astype(np.uint8)