Beispiel #1
0
class RobotDetector(Detector):
    DETECTION_RECT_SCALE_FACTOR = Vector2(1, 1.2)
    RECOGNITION_PATTERN_COLOR_RANGE = ColorRange(Color.from_hsv(280, 120, 180), Color.from_hsv(335, 255, 255))

    def __init__(self, robot_factory):
        self._robot_factory = robot_factory
        self._pattern_circle_filter = ContourFilter(
            min_size_scale=0.5, max_size_scale=1.5, min_aspect_ratio=0.7, max_aspect_ratio=1.3
        )
        self._pattern_filter = ContourFilter(min_aspect_ratio=0.75, max_aspect_ratio=1.25)

    def detect(self, image, playfield):
        self._pattern_circle_filter.target_size = Coordinate.translate_physical_to_game(
            Robot.RECOGNITION_CIRCLE_PHYSICAL_SIZE_CM, playfield
        )
        self._recognition_circle_distance = Coordinate.translate_physical_to_game(
            Robot.RECOGNITION_CIRCLE_DISTANCE_CM, playfield
        )
        return self._perform_detection(image.clone(), playfield)

    def _perform_detection(self, image, playfield):
        detection_rect = self._create_detection_area(image, playfield)
        mask = self._create_mask(
            image, self.RECOGNITION_PATTERN_COLOR_RANGE, opening_kernel_size=5, closure_kernel_size=5
        )
        contours = self._find_contours(mask, image)
        return self._detect_robot_from_contours(contours, detection_rect, playfield)

    def _create_detection_area(self, image, playfield):
        detection_rect = playfield.rect.clone().scale_centered(self.DETECTION_RECT_SCALE_FACTOR)
        image.crop(detection_rect)
        self._log_detection_step("Robot Detection Area", image)
        return detection_rect

    def _detect_robot_from_contours(self, contours, detection_rect, playfield):
        recognition_circles = self._get_robot_recognition_circles(contours, detection_rect)
        return self._get_robot_from_recognition_circles(recognition_circles)

    def _get_robot_recognition_circles(self, contours, detection_rect):
        recognition_circles = []
        filtered_contours = self._pattern_circle_filter.filter_contours(contours)
        for contour in filtered_contours:
            recognition_circles.append(OpenCV.get_contour_center(contour).offset(detection_rect.location))
        return recognition_circles

    def _get_robot_from_recognition_circles(self, recognition_circles):
        self._validate_recognition_circles(recognition_circles)
        robot = self._robot_factory.create_from_recognition_circles(
            recognition_circles, CoordinateSystem.CAMERA, RobotCreationSource.DETECTION
        )
        self._validate_robot(robot)
        return robot

    def _validate_recognition_circles(self, recognition_circles):
        if len(recognition_circles) != 3:
            raise DetectionError(
                "The required amount of recognition circles were not detected. Detected: {0}.".format(
                    len(recognition_circles)
                )
            )
        for pair in ListUtils.pairs(recognition_circles):
            pair_distance = Segment(pair[0], pair[1]).length
            if not MathUtils.in_range(
                pair_distance, self._recognition_circle_distance.x, self._recognition_circle_distance.y
            ):
                raise DetectionError(
                    "Distance between detected recognition circles was not of the correct length. Detected: {0}.".format(
                        pair_distance
                    )
                )

    def _validate_robot(self, robot):
        rotated_rect = robot.get_rotated_rect()
        if not self._pattern_filter.filter_rotated_rect(rotated_rect):
            raise DetectionError(
                "Detected recognition circles do not meet the required criterias. Aspect ratio: {0}".format(
                    rotated_rect.aspect_ratio
                )
            )