Exemple #1
0
    def hough_transform(self, image):
        rho = 1  # distance resolution in pixels of the Hough grid
        theta = np.pi / 180  # angular resolution in radians of the Hough grid
        threshold = 50  # minimum number of votes (intersections in Hough grid cell)
        min_line_len = 15  #minimum number of pixels making up a line
        max_line_gap = 30  # maximum gap in pixels between connectable line segments
        hough_lines = cv2.HoughLinesP(image,
                                      rho,
                                      theta,
                                      threshold,
                                      np.array([]),
                                      minLineLength=min_line_len,
                                      maxLineGap=max_line_gap)

        # save debug image
        color_image = np.dstack((image, image, image)) * 255
        line_image = np.zeros_like(color_image)

        for line in hough_lines:
            for x1, y1, x2, y2 in line:
                cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 10)

        line_image = cv2.addWeighted(color_image, 0.7, line_image, 0.7, 0)
        Logger.save(line_image, 'hough-lines')

        return hough_lines
Exemple #2
0
def main(mode=None, source=None, out=None, log=False):

    # log properties
    Logger.logging = log
    Logger.mode = mode
    pipeline = Pipeline()

    if mode == 'test_images':
        images = glob.glob('test_images/*.jpg')
        for idx, fname in enumerate(images):
            Logger.source = fname
            pipeline.reset()
            image = pipeline.process(imread(fname))
    elif mode == 'video':
        Logger.source = source
        source_video = VideoFileClip(source)
        output_video = source_video.fl_image(pipeline.process)
        output_video.write_videofile(out, audio=False)
    elif mode == 'calibrate':
        images = glob.glob('camera_cal/calibration*.jpg')
        calibration.calibrate(images)
        for idx, fname in enumerate(images):
            Logger.source = fname
            image = imread(fname)
            image = calibration.undistort(image)
            Logger.save(image, 'undistored')
def plot(left, right, shape):

    # save curvature plot
    fig = plt.figure(figsize=(8, 6))
    plt.xlim(0, shape[1])
    plt.ylim(0, shape[0])

    left.plot(color='red')
    right.plot(color='blue')

    plt.gca().invert_yaxis()
    Logger.save(fig, 'curvature')
    plt.close()
Exemple #4
0
def combined_thresh(image):
    """ Returns thresholded binary image
    Sobel directional, magnitude, and direction combined
    """

    # Sobel X Threshold
    sobelx = abs_sobel_thresh(image,
                              orient='x',
                              sobel_kernel=3,
                              thresh=thresholds.get('sobelx'))
    Logger.save(sobelx, 'sobelx-binary')

    # Saturation Threshold
    saturation_binary = hls_select(image,
                                   thresh=thresholds.get('saturation'),
                                   channel=2)
    Logger.save(saturation_binary, 'saturation-binary')

    # Lightness Threshold
    lightness_binary = hls_select(image,
                                  thresh=thresholds.get('lightness'),
                                  channel=1)
    Logger.save(lightness_binary, 'lightness-binary')

    # Combined Threshold
    binary_output = np.zeros(image.shape[:2], dtype='uint8')
    binary_output[((sobelx == 1) | (saturation_binary == 1))
                  & lightness_binary == 1] = 1

    Logger.save(binary_output, 'combined-binary')

    return binary_output
def get_lane_pixels(image):

    histogram = get_histogram(image)

    # save picture of histogram
    fig = plt.figure(figsize=(8, 6))
    plt.plot(histogram)
    Logger.save(fig, 'histogram')
    plt.close()

    height = image.shape[0]
    width = image.shape[1]
    midpoint = int(width / 2)
    slices = 30
    search_window = 70

    # determine starting points for seeking
    left_pos = np.argmax(histogram[:midpoint])
    right_pos = np.argmax(histogram[midpoint:]) + midpoint

    # blank image to store lane line pixels
    left_blank = np.zeros_like(image)
    right_blank = np.zeros_like(image)
    # for debugging seek process
    rectangles = np.dstack((image, image, image))

    for bottom in range(height, 0, -slices):
        top = bottom - slices
        image_slice = image[top:bottom, :]

        # draw window for debugging
        cv2.rectangle(rectangles, (left_pos - search_window, bottom),
                      (left_pos + search_window, top), (0, 255, 0), 2)
        cv2.rectangle(rectangles, (right_pos - search_window, bottom),
                      (right_pos + search_window, top), (0, 255, 0), 2)

        left_blank, left_pos = seek(left_blank, image_slice, left_pos, top,
                                    bottom, search_window)
        right_blank, right_pos = seek(right_blank, image_slice, right_pos, top,
                                      bottom, search_window)

    # debugging image
    both = cv2.addWeighted(left_blank, 1, right_blank, 1, 0)
    both = np.dstack((both, both, both)) * 255
    both = cv2.addWeighted(both, 1, rectangles, 1, 0)
    Logger.save(both, 'lane-seek')

    return left_blank, right_blank
def mask_image(image):
    """
    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.
    """

    height = image.shape[0]
    width = image.shape[1]

    bl = mask_region.get('bottom_left')
    tl = mask_region.get('top_left')
    tr = mask_region.get('top_right')
    br = mask_region.get('bottom_right')

    vertices = np.array([[(bl[0] * width, bl[1] * image.shape[0]),
                          (tl[0] * width, tl[1] * height),
                          (tr[0] * width, tr[1] * height),
                          (br[0] * width, br[1] * image.shape[0])]],
                        dtype=np.int32)

    #defining a blank mask to start with
    mask = np.zeros_like(image)

    #defining a 3 channel or 1 channel color to fill the mask with depending on the input image
    if len(image.shape) > 2:
        channel_count = image.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(image, mask)
    Logger.save(masked_image, 'masked-image')

    return masked_image
    def process(self, image):

        Logger.save(image, 'original')

        # Apply the distortion correction to the raw image.
        image = calibration.undistort(image)
        undistorted_image = copy.copy(image)
        Logger.save(undistorted_image, 'undistorted')

        # Use color transforms, gradients, etc., to create a thresholded binary image.
        thresholded_image = threshold.combined_thresh(image)
        masked_image = mask.mask_image(thresholded_image)

        # Apply a perspective transform to rectify binary image ("birds-eye view").
        src, dest = self.perspective.get_transform_points(masked_image)
        M, Minv = self.perspective.get_matrix(
            src, dest), self.perspective.get_matrix(dest, src)
        image_src = self.perspective.draw_perspective_lines(
            undistorted_image, src)
        Logger.save(image_src, 'perspective-transform-src')
        image_dest = self.perspective.transform(undistorted_image, M)
        image_dest = self.perspective.draw_perspective_lines(image_dest, dest)
        Logger.save(image_dest, 'perspective-transform-dest')
        transformed_image = self.perspective.transform(thresholded_image, M)
        Logger.save(transformed_image, 'perspective-transform-binary')

        # Detect lane pixels and fit to find lane boundary.
        left_pixels, right_pixels = lane_finder.get_lane_pixels(
            transformed_image)

        self.left.fit(left_pixels)
        self.right.fit(right_pixels)

        lane_finder.plot(self.left, self.right, transformed_image.shape)
        lane_boundaries = self.overlay.draw(transformed_image, self.left,
                                            self.right)

        # Warp the detected lane boundaries back onto the original image.
        # Combine the result with the original image
        lane_boundaries = self.perspective.transform(lane_boundaries, Minv)
        image = cv2.addWeighted(undistorted_image, 1, lane_boundaries, 0.3, 0)

        # Determine curvature of the lane and vehicle position with respect to center.
        # Output visual display of the lane boundaries and numerical estimation of lane curvature and vehicle position.
        image = self.overlay.stats(image, self.left, self.right)
        Logger.save(image, 'final')
        Logger.increment()
        return image