Esempio n. 1
0
 def is_line_plausible(self, left, right):
     """
     determine if pixels describing two line are plausible lane lines based on curvature and distance.
     :param left: Tuple of arrays containing the coordinates of detected pixels
     :param right: Tuple of arrays containing the coordinates of detected pixels
     :return:
     """
     if len(left[0]) < 3 or len(right[0]) < 3:
         return False
     else:
         new_left = Line(y=left[0], x=left[1])
         new_right = Line(y=right[0], x=right[1])
         return are_lanes_plausible(new_left, new_right)
    def postprocess_lines(self):
        lines = []
        for points in self.lines:
            for i in range(len(points) - 1):
                x1 = points[i][0]
                y1 = points[i][1]
                x2 = points[i + 1][0]
                y2 = points[i + 1][1]
                lines += [Line(x1, y1, x2, y2)]

        results = []
        for y in range(64):
            coords = []
            for line in lines:
                x = line.get_x(y)
                if line.contains(x, y):
                    coords += [x]
            results += [coords]
        return results
Esempio n. 3
0
from timeit import timeit
from utils.line import Line
from utils.sorter import radixSort

# Little test to check if algorithm is working
#intList = getRandomRepeatingListWithRange(15, 100)
#print(f"Initial: {intList}")
#radixSort(intList)
#print(f"Final: {intList}")

# Change this value to switch from and to test mode
testMode = False
testDivisor = 100

counts = [10000, 20000, 40000, 70000, 100000, 500000]

if testMode:
    counts = [int(n / testDivisor) for n in counts]

numberOfTests = 1

randomLists = [getRandomList(count) for count in counts]

elapsedTimes = [
    timeit(lambda: radixSort(list), number=numberOfTests)
    for list in randomLists
]

lines = [Line((counts, elapsedTimes), "Caso aleatório", 'b')]
plot(lines, figname="products/radix_sort_graph.png")
Esempio n. 4
0
from utils.plotter import plot
from utils.generator import getRandomList, getDecrescentList
from timeit import timeit
from utils.line import Line
from utils.sorter import insertionSort

counts = [1000, 2000, 3000, 4000, 5000, 8000, 11000, 15000]

randomLists = [getRandomList(count) for count in counts]
worstLists = [getDecrescentList(count) for count in counts]

elapsedTimes = [timeit(lambda: insertionSort(list), number = 1) for list in randomLists]
worstElapsedTimes = [timeit(lambda: insertionSort(list), number = 1) for list in worstLists]

lines = [Line((counts, elapsedTimes), "Caso aleatório", 'b'), Line((counts, worstElapsedTimes), "Pior caso", 'k')]
plot(lines, figname = "products/insertion_sort_graph.png")
Esempio n. 5
0
counts = [10000, 20000, 40000, 70000, 100000, 500000]

if testMode:
    counts = [int(n / testDivisor) for n in counts]

numberOfTests = 1

randomLists = [getRandomList(count) for count in counts]

elapsedTimes = [
    timeit(lambda: bucketSort(list), number=numberOfTests)
    for list in randomLists
]

lines = [Line((counts, elapsedTimes), "Caso aleatório", 'b')]
plot(lines, "products/bucket_sort_graph.png")

bucketNumbers = [1, 10, 100, 1000, 10000, 100000]
bucketNumberTimes = [
    timeit(lambda: bucketSort(getRandomList(100000), bucketNumber),
           number=numberOfTests) for bucketNumber in bucketNumbers
]

lines = [
    Line((bucketNumbers, bucketNumberTimes), "Lista com 100000 elementos", 'b')
]
plot(lines, 'products/bucket_number_graph.png', 'Número de buckets')
print(
    "De acordo com as informações obtidas ao analisar o gráfico, sugiro uma quantidade de buckets igual ao tamanho da entrada, ou uma quantidade de buckets igual a 1% do tamanho da entrada."
)
Esempio n. 6
0
    def process_frame(self, frame):
        """
        apply lane detection on a single image
        :param frame: input frame
        :return: processed frame
        """
        orig_frame = np.copy(frame)

        # undistort frame
        frame = self.camera_calibrator.undistort(frame)

        # apply sobel and color transforms to create a thresholded binary image.
        frame = generate_lane_mask(frame, 400)

        # apply perspective transform to get birds-eye view
        frame = self.perspective_transformer.transform(frame)

        left_detected = right_detected = False
        left_x = left_y = right_x = right_y = []

        # if lanes were detected in the past, algorithm will first try to find new lanes along the old one. 
        # this will improve performance
        if self.left_line is not None and self.right_line is not None:
            left_x, left_y = detect_lane_along_poly(frame, self.left_line.best_fit_poly, self.line_segments)
            right_x, right_y = detect_lane_along_poly(frame, self.right_line.best_fit_poly, self.line_segments)
  
            left_detected, right_detected = self.validate_lines(left_x, left_y, right_x, right_y)

        # if no lanes were found a histogram search is performed
        if not left_detected:
            left_x, left_y = histogram_lane_detection(
                frame, self.line_segments, (self.image_offset, frame.shape[1] // 2), h_window=7)
            left_x, left_y = outlier_removal(left_x, left_y)
            
        if not right_detected:
            right_x, right_y = histogram_lane_detection(
                frame, self.line_segments, (frame.shape[1] // 2, frame.shape[1] - self.image_offset), h_window=7)
            right_x, right_y = outlier_removal(right_x, right_y)

        if not left_detected or not right_detected:
            left_detected, right_detected = self.validate_lines(left_x, left_y, right_x, right_y)

        # updated left lane information
        if left_detected:
            # switch x and y since lines are almost vertical
            if self.left_line is not None:
                self.left_line.update(y=left_x, x=left_y)
            else:
                self.left_line = Line(self.n_frames, left_y, left_x)
 
        # updated right lane information.
        if right_detected:
            # switch x and y since lines are almost vertical
            if self.right_line is not None:
                self.right_line.update(y=right_x, x=right_y)
            else:
                self.right_line = Line(self.n_frames, right_y, right_x)

        # add calculated information onto the frame
        if self.left_line is not None and self.right_line is not None:
            self.dists.append(self.left_line.get_best_fit_distance(self.right_line))
            self.center_poly = (self.left_line.best_fit_poly + self.right_line.best_fit_poly) / 2
            self.curvature = calc_curvature(self.center_poly)
            self.car_offset = (frame.shape[1] / 2 - self.center_poly(719)) * 3.7 / 700
    
            self.render_predicted_lane_area(orig_frame)
            self.display_dashboard(orig_frame)
            
        
        return self.add_logo(orig_frame)
Esempio n. 7
0
class LaneFinder:
    
    def __init__(self):
        """
        find lanes on images (or video frames) using Sobel operations, lane color extraction and sliding histogram.
        """
        self.camera_calibrator = CameraCalibrator()
        self.perspective_transformer = PerspectiveTransformer()
        
        self.n_frames = 7
        
        self.line_segments = 10
        self.image_offset = 250
        
        self.left_line = None
        self.right_line = None
        self.center_poly = None
        self.curvature = 0.0
        self.car_offset = 0.0
        
        self.dists = []
        
        
    def display_dashboard(self, img):
        """
        display dashboard with information like lane curvature and car's center offset. 
        """
        font = cv2.FONT_HERSHEY_SIMPLEX
        
        text = "Radius of curvature is {:.2f}m".format(self.curvature)
        cv2.putText(img, text, (50, 50), font, 1, (255, 255, 255), 2)
        
        left_or_right = 'left' if self.car_offset < 0 else 'right'
        text = "Car is {:.2f}m {} of center".format(np.abs(self.car_offset), left_or_right)
        cv2.putText(img, text, (50, 100), font, 1, (255, 255, 255), 2)

    def render_predicted_lane_area(self, img):
        """
        render the predicted lane area onto the image
        """
        overlay = np.zeros([img.shape[0], img.shape[1], img.shape[2]])
        mask = np.zeros([img.shape[0], img.shape[1]])

        # lane area
        lane_area = calculate_lane_area((self.left_line, self.right_line), img.shape[0], 20)
        mask = cv2.fillPoly(mask, np.int32([lane_area]), 1)
        mask = self.perspective_transformer.inverse_transform(mask)

        overlay[mask == 1] = (128, 255, 0)
        selection = (overlay != 0)
        img[selection] = img[selection] * 0.5 + overlay[selection] * 0.5

        # side lines 
        mask[:] = 0
        mask = draw_poly(mask, self.left_line.best_fit_poly, 5, 255)
        mask = draw_poly(mask, self.right_line.best_fit_poly, 5, 255)
        mask = self.perspective_transformer.inverse_transform(mask)
        img[mask == 255] = (255, 200, 2)
    
    def add_logo(self, orig_frame):
        background = Image.fromarray(orig_frame)
        foreground = Image.open("../test_images/logo.png")
        background.paste(foreground, (30, orig_frame.shape[0] - 80), mask=foreground.split()[3])
        orig_frame = np.array(background.convert())
        return orig_frame
        

    def process_frame(self, frame):
        """
        apply lane detection on a single image
        :param frame: input frame
        :return: processed frame
        """
        orig_frame = np.copy(frame)

        # undistort frame
        frame = self.camera_calibrator.undistort(frame)

        # apply sobel and color transforms to create a thresholded binary image.
        frame = generate_lane_mask(frame, 400)

        # apply perspective transform to get birds-eye view
        frame = self.perspective_transformer.transform(frame)

        left_detected = right_detected = False
        left_x = left_y = right_x = right_y = []

        # if lanes were detected in the past, algorithm will first try to find new lanes along the old one. 
        # this will improve performance
        if self.left_line is not None and self.right_line is not None:
            left_x, left_y = detect_lane_along_poly(frame, self.left_line.best_fit_poly, self.line_segments)
            right_x, right_y = detect_lane_along_poly(frame, self.right_line.best_fit_poly, self.line_segments)
  
            left_detected, right_detected = self.validate_lines(left_x, left_y, right_x, right_y)

        # if no lanes were found a histogram search is performed
        if not left_detected:
            left_x, left_y = histogram_lane_detection(
                frame, self.line_segments, (self.image_offset, frame.shape[1] // 2), h_window=7)
            left_x, left_y = outlier_removal(left_x, left_y)
            
        if not right_detected:
            right_x, right_y = histogram_lane_detection(
                frame, self.line_segments, (frame.shape[1] // 2, frame.shape[1] - self.image_offset), h_window=7)
            right_x, right_y = outlier_removal(right_x, right_y)

        if not left_detected or not right_detected:
            left_detected, right_detected = self.validate_lines(left_x, left_y, right_x, right_y)

        # updated left lane information
        if left_detected:
            # switch x and y since lines are almost vertical
            if self.left_line is not None:
                self.left_line.update(y=left_x, x=left_y)
            else:
                self.left_line = Line(self.n_frames, left_y, left_x)
 
        # updated right lane information.
        if right_detected:
            # switch x and y since lines are almost vertical
            if self.right_line is not None:
                self.right_line.update(y=right_x, x=right_y)
            else:
                self.right_line = Line(self.n_frames, right_y, right_x)

        # add calculated information onto the frame
        if self.left_line is not None and self.right_line is not None:
            self.dists.append(self.left_line.get_best_fit_distance(self.right_line))
            self.center_poly = (self.left_line.best_fit_poly + self.right_line.best_fit_poly) / 2
            self.curvature = calc_curvature(self.center_poly)
            self.car_offset = (frame.shape[1] / 2 - self.center_poly(719)) * 3.7 / 700
    
            self.render_predicted_lane_area(orig_frame)
            self.display_dashboard(orig_frame)
            
        
        return self.add_logo(orig_frame)
    
    def validate_lines(self, left_x, left_y, right_x, right_y):
        """
        compare two line to each other and to their last prediction.
        :param left_x:
        :param left_y:
        :param right_x:
        :param right_y:
        :return: boolean tuple (left_detected, right_detected)
        """
        left_detected = False
        right_detected = False

        if self.is_line_plausible((left_x, left_y), (right_x, right_y)):
            left_detected = True
            right_detected = True
        elif self.left_line is not None and self.right_line is not None:
            if self.is_line_plausible((left_x, left_y), (self.left_line.ally, self.left_line.allx)):
                left_detected = True
            if self.is_line_plausible((right_x, right_y), (self.right_line.ally, self.right_line.allx)):
                right_detected = True

        return left_detected, right_detected

    def is_line_plausible(self, left, right):
        """
        determine if pixels describing two line are plausible lane lines based on curvature and distance.
        :param left: Tuple of arrays containing the coordinates of detected pixels
        :param right: Tuple of arrays containing the coordinates of detected pixels
        :return:
        """
        if len(left[0]) < 3 or len(right[0]) < 3:
            return False
        else:
            new_left = Line(y=left[0], x=left[1])
            new_right = Line(y=right[0], x=right[1])
            return are_lanes_plausible(new_left, new_right)
Esempio n. 8
0
    parser.add_argument("-epochs", "--epochs", type=int, default=1)
    parser.add_argument("-lr", "--learning_rate", type=float,
                        default=0.025)  # As starting value in paper
    parser.add_argument("-negpow", "--negativepower", type=float, default=0.75)
    args = parser.parse_args()

    # Create dict of distribution when opening file
    edgedistdict, nodedistdict, weights, nodedegrees, maxindex = makeDist(
        args.graph_path, args.negativepower)

    edgesaliassampler = VoseAlias(edgedistdict)
    nodesaliassampler = VoseAlias(nodedistdict)

    batchrange = int(len(edgedistdict) / args.batchsize)
    print(maxindex)
    line = Line(maxindex + 1, embed_dim=args.dimension, order=args.order)

    opt = optim.SGD(line.parameters(),
                    lr=args.learning_rate,
                    momentum=0.9,
                    nesterov=True)

    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

    lossdata = {"it": [], "loss": []}
    it = 0

    print("\nTraining on {}...\n".format(device))
    for epoch in range(args.epochs):
        print("Epoch {}".format(epoch))
        for b in trange(batchrange):
Esempio n. 9
0
def correct_sharp_turns(path, img_shape):
    theta = (3 / 4) * pi
    min_dist_betw_tps = 5 * road_width
    margin_fit = 3 * road_width
    min_len_fit = 2 * road_width
    max_len_fit = 6 * road_width
    max_l = len(path) - 1
    max_x, max_y = img_shape[1] - 1, img_shape[0] - 1

    # get potential turning points using RDP with a low epsilon
    turning_points = rdp(path, epsilon=1)
    turning_points = turning_points[1:-1]

    tp_indices = []
    for tp in turning_points:
        tuple_tp = tuple(tp)
        tp_indices.append(path.index(tuple_tp))

    # remove turning points to close to the start or the end of the path
    tp_indices_new = []
    for i_tp in tp_indices:
        if 10 <= i_tp < len(path) - 10:
            tp_indices_new.append(i_tp)
    tp_indices = tp_indices_new

    turning_points_new = []
    angles = []
    segment_data_tuples = []
    tp_indices_new = []

    # fit lines at turning points and store all relevant info
    for i in tp_indices:
        segment1, len_s1, s1_i_min, s1_i_max = get_segment(path,
                                                           i,
                                                           max_len_fit,
                                                           margin_fit,
                                                           after=False)
        segment2, len_s2, s2_i_min, s2_i_max = get_segment(path,
                                                           i,
                                                           max_len_fit,
                                                           margin_fit,
                                                           after=True)

        if len_s1 < min_len_fit:
            line1 = Line(path[0], path[i])
            s1_i_min = 0
        else:
            line1 = fit_line(segment1)

        if len_s2 < min_len_fit:
            line2 = Line(path[i], path[max_l])
            s2_i_max = max_l
        else:
            line2 = fit_line(segment2)

        segment1_data = segment1, len_s1, s1_i_min, s1_i_max
        segment2_data = segment2, len_s2, s2_i_min, s2_i_max

        if line1 and line2:
            angle = line1.angle(line2)
            if angle <= theta:
                ip = line1.intersection(line2)
                if ip:
                    ip = int(round(ip[0])), int(round(ip[1]))
                    cp = closest_point(ip, path[s1_i_max:s2_i_min])
                    line = Line(cp, ip)
                    tp = line.point_on_max_dist_from_p1(road_width)
                    tp = min(tp[0], max_x), min(tp[1], max_y)
                    turning_points_new.append(tp)
                    angles.append(angle)
                    segment_data_tuples.append((segment1_data, segment2_data))
                    tp_indices_new.append(i)

    turning_points = turning_points_new
    tp_indices = tp_indices_new

    # sort turning points by angle and keep only the turning points with the smallest angle in their neighborhood
    tp_indices_sorted_by_angle = sorted(range(len(angles)),
                                        key=lambda k: angles[k])
    to_keep = [True] * len(turning_points)
    to_remove = set()

    for i in tp_indices_sorted_by_angle:
        if i in to_remove:
            to_keep[i] = False
        else:
            tp_i = turning_points[i]
            for j, tp_j in enumerate(turning_points):
                if i != j and euclidean_distance(tp_i,
                                                 tp_j) < min_dist_betw_tps:
                    to_remove.add(j)

    turning_points_new = []
    angles_new = []
    segment_data_tuples_new = []
    tp_indices_new = []

    for i, keep in enumerate(to_keep):
        if keep:
            turning_points_new.append(turning_points[i])
            angles_new.append(angles[i])
            segment_data_tuples_new.append(segment_data_tuples[i])
            tp_indices_new.append(tp_indices[i])

    turning_points = turning_points_new
    angles = angles_new
    segment_data_tuples = segment_data_tuples_new
    tp_indices = tp_indices_new

    # compute the distances between remaining adjacent turning points
    distances = []
    for i in range(len(turning_points) - 1):
        dist = euclidean_distance(turning_points[i], turning_points[i + 1])
        distances.append(dist)

    # recompute turning points with lower margins for adjacent turns that are still close to each other
    previous_close = False

    for i in range(len(turning_points)):
        if i < len(turning_points) - 1:
            dist = distances[i]
            if dist < 9 * road_width:
                next_close = True
            else:
                next_close = False
        else:
            next_close = False

        if previous_close or next_close:
            j = tp_indices[i]  # index tp in path

            if previous_close:
                dist_prev = distances[i - 1]
                s1, len_s1, s1_i_min, s1_i_max = get_segment(path,
                                                             j,
                                                             dist_prev / 2,
                                                             dist_prev / 4,
                                                             after=False)
                segment_data_tuples[i] = (s1, len_s1, s1_i_min,
                                          s1_i_max), segment_data_tuples[i][1]
            else:
                s1, len_s1, _, s1_i_max = segment_data_tuples[i][0]

            if next_close:
                dist_next = distances[i]
                s2, len_s2, s2_i_min, s2_i_max = get_segment(path,
                                                             j,
                                                             dist_next / 2,
                                                             dist_next / 4,
                                                             after=True)
                segment_data_tuples[i] = segment_data_tuples[i][0], (s2,
                                                                     len_s2,
                                                                     s2_i_min,
                                                                     s2_i_max)
                previous_close = True
            else:
                s2, len_s2, s2_i_min, _ = segment_data_tuples[i][1]
                previous_close = False

            line1 = fit_line(s1)
            line2 = fit_line(s2)

            view = False

            if view:
                plt.figure()

                px = [x for (x, y) in path]
                py = [y for (x, y) in path]
                plt.plot(px, py, c='g', linewidth=1)

                s1x = [x for (x, y) in s1]
                s1y = [y for (x, y) in s1]
                plt.plot(s1x, s1y, c='blue', linewidth=4)

                s2x = [x for (x, y) in s2]
                s2y = [y for (x, y) in s2]
                plt.plot(s2x, s2y, c='red', linewidth=4)

                pixels_line1 = line1.pixels()
                l1x = [x for (x, y) in pixels_line1]
                l1y = [y for (x, y) in pixels_line1]
                plt.plot(l1x, l1y, c='cyan', linewidth=2)

                pixels_line2 = line2.pixels()
                l2x = [x for (x, y) in pixels_line2]
                l2y = [y for (x, y) in pixels_line2]
                plt.plot(l2x, l2y, c='orange', linewidth=2)

                plt.scatter([path[j][0]], [path[j][1]], s=50, c='green')
                plt.scatter([turning_points[i][0]], [turning_points[i][1]],
                            s=50,
                            c='red')

            if line1 and line2:
                ip = line1.intersection(line2)
                if ip:
                    ip = int(round(ip[0])), int(round(ip[1]))
                    cp = closest_point(ip, path[s1_i_max:s2_i_min])
                    line = Line(cp, ip)
                    tp = line.point_on_max_dist_from_p1(1.42 * road_width)
                    tp = min(tp[0], max_x), min(tp[1], max_y)
                    turning_points[i] = tp

                    if view:
                        plt.scatter([tp[0]], [tp[1]], s=50, c='blue')
                        plt.show()

    # insert sharp turns in the path, connect all adjacent turning points that are still close to each other
    path_new = []
    tp_indices = []
    previous_close = False
    n = 0

    for i in range(len(turning_points)):
        tp = turning_points[i]
        _, _, _, s1_i_max = segment_data_tuples[i][0]
        _, _, s2_i_min, _ = segment_data_tuples[i][1]

        if i < len(turning_points) - 1:
            dist = distances[i]
            if dist < 9 * road_width:
                next_close = True
            else:
                next_close = False
        else:
            next_close = False

        if previous_close:
            if next_close:
                turn = fill([], turning_points[i - 1], tp)[1:]
                previous_close = True
            else:
                turn = fill([tp], turning_points[i - 1], path[s2_i_min])[1:]
                previous_close = False
        else:
            path_new.extend(path[n:s1_i_max])
            if next_close:
                turn = fill([], path[s1_i_max], tp)
                previous_close = True
            else:
                turn = fill([tp], path[s1_i_max], path[s2_i_min])
                previous_close = False

        path_new.extend(turn)
        tp_indices.append(path_new.index(tp))
        n = s2_i_min + 1

    path_new.extend(path[n:])

    return path_new, tp_indices