def filter_lifelines(lifelines, vp1): """ Filters given trajectories by those which have direction ti the first vanishing point. :param lifelines: given trajectories :param vp1: detected vanishing point :return: filtered trajectories """ filtered = [] for lifeline in lifelines: line_to_vp = Line(lifeline[0], vp1.point) try: lifeline_line = Line(lifeline[0], lifeline[-1]) except SamePointError: continue if constants.TRACKER_TRAJECTORY_MIN_ANGLE < lifeline_line.angle(line_to_vp) < constants.TRACKER_TRAJECTORY_MAX_ANGLE: continue elif lifeline[0][1] < lifeline[-1][1]: continue else: filtered.append(lifeline) return filtered
def stopline(self, value): """ Sets the stopline with specified offset, assuming that first vanishing point is in the top part of frame """ self._stop_line = value left_edge_point = self.stopline.edge_points(info=self._info)[0] right_edge_point = self.stopline.edge_points(info=self._info)[1] self._stop_line = Line( point1=(left_edge_point[0], left_edge_point[1] - constants.CORRIDORS_STOP_LINE_OFFSET), point2=(right_edge_point[0], right_edge_point[1] - constants.CORRIDORS_STOP_LINE_OFFSET)) left_edge_point = self.stopline.edge_points(info=self._info)[0] right_edge_point = self.stopline.edge_points(info=self._info)[1] top_line = Line(point1=(left_edge_point[0], 3 * left_edge_point[1] / 5), point2=(right_edge_point[0], 3 * right_edge_point[1] / 5)) self._info.update_area.change_area(top_line=top_line)
def test_angle(self): l1 = Line((0, 0), (0, 1)) l2 = Line((0, 0), (1, 0)) l3 = Line((0, 0), (1, 1)) self.assertEqual(l1.angle(l2), 90) self.assertAlmostEqual(l1.angle(l3), 45, 4) l2.general_equation()
def middle_point(self): """ :return: middle point of area """ l1 = Line(point1=self._top_left, point2=self._bot_right) l2 = Line(point1=self._bot_left, point2=self._top_right) return l1.intersection(l2)
def add_line(self): """ Adds new line to storage """ try: new_line = Line(self.point1, self.point2) if new_line.angle(Line.horizontal_line()) != 0: self.selected.append(Line(self.point1, self.point2)) except SamePointError: pass
def test_point_distance(self): l1 = Line((0, 0), (0, 1)) point1 = (0, 0) point2 = (1, 0) self.assertEqual(l1.point_distance(point1), 0) self.assertEqual(l1.point_distance(point2), 1)
def draw_trajectories(self, image, method="second"): """ Helper method for drawing car trajectories (trajectories of center point) :param image: selected image :param method: method of trajectory obtaining to be printed :return: updated image """ if method == "second": for index, point in enumerate(self._history): cv2.circle(img=image, center=point.tuple(), color=constants.COLOR_BLUE, radius=5, thickness=constants.FILL) try: cv2.line(img=image, pt1=point.tuple(), pt2=self._history[index + 1].tuple(), color=constants.COLOR_BLUE, thickness=2) except IndexError: pass if method == "first": try: Line(self._history[0].tuple(), self._history[-1].tuple()).draw(image, constants.COLOR_RED, 1) except SamePointError: return cv2.circle(img=image, center=self._history[0].tuple(), color=constants.COLOR_BLUE, radius=5, thickness=constants.FILL) cv2.circle(img=image, center=self._history[-1].tuple(), color=constants.COLOR_BLUE, radius=5, thickness=constants.FILL) cv2.line(img=image, pt1=self._history[0].tuple(), pt2=self._history[-1].tuple(), color=constants.COLOR_BLUE, thickness=2) position_history = [ coordinates.tuple() for coordinates in self._history ] line, value = ransac(position_history, position_history, 1) if line is not None and value > 5: line.draw(image, constants.COLOR_RED, 2)
def draw_line(self, image, point, color, thickness): """ Helper function to dra line from point to this vanishing point. Works in both cases - when vanishing point is defined by a point or when defined by an angle :param image: selected image to draw on :param point: selected point as origin :param color: color of line :param thickness: thickness of line """ if self.infinity: line = Line(point1=point, direction=self.direction) else: line = Line(point1=point, point2=self.point) line.draw(image=image, color=color, thickness=thickness)
def find_stop_line(self): """ Finds stop line from stored stop-points. For stop line is used second vanishing point which is used as anchor for all detected stop line points. Stop line is detected using RANSAC algorithm. """ best_line_ratio = 0 best_line = None vp2 = self._info.vanishing_points[1] test_image = np.zeros(shape=(self._info.height, self._info.width)) for point in self._stop_places: cv2.circle(test_image, point.tuple(), radius=5, color=255, thickness=5) cv2.imwrite("stopky.png", test_image) for point2 in self._stop_places: try: line = Line(vp2.point, point2.tuple()) except SamePointError: continue except VanishingPointError: line = Line(point1=point2.tuple(), direction=vp2.direction) num = 0 ransac_threshold = constants.CORRIDORS_RANSAC_THRESHOLD for point in self._stop_places: distance = line.point_distance(point.tuple()) if distance < ransac_threshold: num += 1 if num > best_line_ratio: best_line_ratio = num best_line = line self.stopline = best_line self._stopline_found = True
def add_line(self): """ Adds stop line """ try: self.line = Line(self.point1, self.point2) except SamePointError: pass
def __init__(self, info, top_left, bottom_right, top_right, bottom_left): """ :param info: instance of InputInfo :param top_left: top left anchor of area :param bottom_right: bottom right anchor of area :param top_right: top right anchor of area :param bottom_left: bottom left anchor of area """ self._top_left = top_left.tuple() self._bot_right = bottom_right.tuple() self._top_right = top_right.tuple() self._bot_left = bottom_left.tuple() self.top_line = Line(point1=self._top_left, point2=self._top_right) self.left_line = Line(point1=self._top_left, point2=self._bot_left) self.bottom_line = Line(point1=self._bot_left, point2=self._bot_right) self.right_line = Line(point1=self._top_right, point2=self._bot_right) self._info = info
def _calculate_third_vp(self): """ Because principal point is said to be in midle, the third vanishing point can be obtained by simple mathematics. After vanishing point is being found it propagates this information to InputInfo where it adds VanishingPoint to corresponding list """ vp1 = self._info.vanishing_points[0].point try: vp2 = self._info.vanishing_points[1].point vp1_to_vp2 = Line(point1=vp1, point2=vp2) except VanishingPointError: vp1_to_vp2 = Line( point1=vp1, direction=self._info.vanishing_points[1].direction) self._info.vanishing_points.append( VanishingPoint(direction=vp1_to_vp2.normal_direction()))
def _find_corridors(self, lifelines): """ After both vanishing points are found corridors can be constructed with the information of car trajectories. :param lifelines: trajectories of cars """ filtered_lifelines = TrackedObject.filter_lifelines( lifelines, self._info.vp1) mask = np.zeros(shape=(self._info.height, self._info.width, 3), dtype=np.uint8) # for history in filtered_lifelines: # line, value = ransac(history, history, 1) # # if line is not None and value > 5: # bottom_point = Coordinates(*line.find_coordinate(y=self._info.height)).tuple() # # cv2.line(img=mask, # pt1=bottom_point, # pt2=self._info.vp1.point, # color=params.COLOR_LIFELINE, # thickness=100) for history in filtered_lifelines: helper_mask = np.zeros_like(mask) first_point = history[0] line = Line(first_point, self._info.vp1.point) line.draw(image=helper_mask, color=constants.COLOR_LIFELINE, thickness=100) mask = cv2.add(mask, helper_mask) cv2.imwrite("lifeline.jpg", mask) self._info.corridors_repository.find_corridors( lifelines_mask=mask, vp1=self._info.vanishing_points[0])
def test_vertical(self): self.assertFalse(Line((0, 1), (2, 1)).vertical) self.assertTrue(Line((0, 1), (0, 2)).vertical)
def _detect_second_vanishing_point(self, new_frame, boxes_mask, boxes_mask_no_border, light_status) -> None: """ Calculates second vanishing point using information about car positions and detection of edges supporting second vanishing point. It is being detected only if green light status is present on current frame. Detected lines from edges are accumulated into parallel coordinate space - RANSAC algorithm is used for intersection detection - Vanishing Point. After vanishing point is being found it propagates this information to InputInfo where it adds VanishingPoint to corresponding list :param new_frame: examined frame :param boxes_mask: mask used for selecting parts of image where cars exists :param boxes_mask_no_border: mask used for selecting parts of image where cars exists :param light_status: current light status """ if light_status in [Color.RED, Color.RED_ORANGE]: return selected_areas = cv2.bitwise_and( new_frame, cv2.cvtColor(boxes_mask, cv2.COLOR_GRAY2RGB)) blured = cv2.GaussianBlur(selected_areas, (7, 7), 0) canny = cv2.Canny(blured, 50, 150, apertureSize=3) no_border_canny = cv2.bitwise_and(canny, boxes_mask_no_border) no_border_canny = cv2.bitwise_and(no_border_canny, no_border_canny, mask=self._info.update_area.mask()) lines = cv2.HoughLinesP( image=no_border_canny, rho=1, theta=np.pi / 350, threshold=constants.CALIBRATOR_HLP_THRESHOLD, minLineLength=constants.CALIBRATOR_MIN_LINE_LENGTH, maxLineGap=constants.CALIBRATOR_MAX_LINE_GAP) vp1 = self._info.vanishing_points[0] canny = cv2.cvtColor(no_border_canny, cv2.COLOR_GRAY2RGB) if lines is not None: for (x1, y1, x2, y2), in lines: point1 = x1, y1 point2 = x2, y2 try: if vp1.coordinates.distance(Coordinates( x1, y1)) > vp1.coordinates.distance( Coordinates(x2, y2)): line_to_vp = Line(point1, vp1.point) else: line_to_vp = Line(point2, vp1.point) if Line(point1, point2).angle(line_to_vp) < 30 or Line( point1, point2).angle(line_to_vp) > 150: cv2.line(canny, point1, point2, constants.COLOR_RED, 2) continue self._pc_lines.add_to_pc_space(point1, point2) cv2.line(canny, point1, point2, constants.COLOR_BLUE, 2) except SamePointError: continue cv2.imwrite("test.jpg", canny) if self._pc_lines.count > constants.CALIBRATOR_VP2_TRACK_MINIMUM: new_vanishing_point = self._pc_lines.find_most_lines_cross() x, y = new_vanishing_point if y is not None: self._info.vanishing_points.append( VanishingPoint(point=new_vanishing_point)) else: dx = np.cos(np.deg2rad(x)) dy = np.sin(np.deg2rad(x)) direction = dx, dy self._info.vanishing_points.append( VanishingPoint(direction=direction)) self._pc_lines.clear()
import numpy as np from primitives.point import Point from primitives.line import Line # testing point creation pointa = Point(1, 2) pointb = Point(3, 4) print(pointa.coords) # test line object creation with coordinates linea = Line([pointa.coords, pointb.coords]) # test setter with point objects lineb = Line([pointb, pointa]) print(lineb.coords) # test exception handling for line # linec = Line(["asdkjalskdfj", pointa]) # test coordinate setting from point coordinates points = [pointa.coords, pointb.coords] lineb.setcoords(points) # test coordinate setting from point objects lineb.setcoords([pointb, pointa]) # test adding points from coordinates pointc = Point(0, 0) lineb.addPoint(pointc.coords)
def test_angle_90(self): l1 = Line((0, 1), (0, 0)) l2 = Line((0, 0), (1, 0)) self.assertEqual(l1.angle(l2), 90.)
def test_same_points(self): with self.assertRaises(SamePointError): Line((3, 3), (3, 3))
def test_angle_019(self): l1 = Line((1, 2), (3, 5)) l2 = Line((3, 4), (2, 5)) self.assertAlmostEqual(l1.angle(l2), 78.7, 1)
def setUpClass(cls): p1 = Point(0, 0) p2 = Point(1, 1) l = Line([p1, p2])
def test_point(self): l1 = Line((1, 1), (2, 2)) self.assertTrue(l1.on_line((3, 3))) self.assertFalse(l1.on_line((-3, 3)))
def test_intersection(self): l1 = Line((0, 0), (1, 0)) l2 = Line((0, 0), (0, 1)) self.assertEqual(l1.intersection(l2), (0, 0))
def test_same(self): l1 = Line((-3, 2), (-3, 3)) l2 = Line((-2, 2), (-2, 3)) with self.assertRaises(NoIntersectionError): l1.intersection(l2)
def test_horizontal(self): self.assertTrue(Line((0, 1), (2, 1)).horizontal) self.assertFalse(Line((0, 1), (2, 1)).vertical)
def find_corridors(self, lifelines_mask, vp1): """ Finds corridors on frame using first positions of cars and detected first vanishing point to construct mask on which thresholding is used to detect separate corridors. By computation is used only 1px wide age around left, bottom and right edge of frame. :param lifelines_mask: mask of lifelines :param vp1: detected first vanishing point """ # extract left-bot-right 1px border around lifeline image and make "1D array" left_edge = lifelines_mask[:, :1] bottom_edge = lifelines_mask[-1:, :].transpose(1, 0, 2) right_edge = np.flip(lifelines_mask[:, -1:]) frame_edge = np.concatenate((left_edge, bottom_edge, right_edge)) # greyscale image and reduce noise by multiple blur and threshold edge_grey = cv2.cvtColor(frame_edge, cv2.COLOR_RGB2GRAY) edge_grey_blured = cv2.medianBlur(edge_grey, 11) _, threshold = cv2.threshold(edge_grey_blured, 50, 255, cv2.THRESH_BINARY) threshold = cv2.dilate(threshold, (5, 5), iterations=5) height, width = edge_grey_blured.shape edge_grey_canny = cv2.Canny(threshold, 50, 150) coordinates = [] # border image with 0 edge_grey_canny[0][0] = 0 edge_grey_canny[-1][0] = 0 for i in range(height): if edge_grey_canny[i][0] == 255: coordinates.append(i) points = np.array(coordinates).reshape(-1, 2) for index, point in enumerate(points): try: half_diff = int((points[index + 1][0] - point[1]) / 2) except IndexError: break point[1] += half_diff points[index + 1][0] -= half_diff for point in points: points = [] for coordinate in list(point): if coordinate < self._info.height: points.append((0, coordinate)) elif coordinate < self._info.height + self._info.width: points.append((coordinate - self._info.height, self._info.height - 1)) else: points.append((self._info.width - 1, self._info.width + 2 * self._info.height - coordinate)) left_bottom = tuple(points[0]) right_bottom = tuple(points[1]) left_top = right_top = vp1.point self.create_new_corridor(left_line=Line(left_bottom, left_top), right_line=Line(right_bottom, right_top)) # cv2.imwrite("mask.jpg", self.get_mask()) self._corridor_mask = cv2.bitwise_and( self._corridor_mask, self._corridor_mask, mask=self._info.update_area.mask()) self._corridors_found = True